[kernel] r10376 - in dists/trunk/linux-2.6/debian/patches: bugfix/all series

Maximilian Attems maks at alioth.debian.org
Sat Feb 2 12:56:07 UTC 2008


Author: maks
Date: Sat Feb  2 12:37:43 2008
New Revision: 10376

Log:
update to patch-2.6.24-git12

just 2 m68k patches fallout
nuke a keyspan patch from git12

usb, pci, suspend, nfs merges


Added:
   dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git12
      - copied, changed from r10370, /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git10
Removed:
   dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git10
Modified:
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra

Copied: dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git12 (from r10370, /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git10)
==============================================================================
--- /dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git10	(original)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/patch-2.6.24-git12	Sat Feb  2 12:37:43 2008
@@ -44,6 +44,47 @@
  N: Jon Tombs
  E: jon at gte.esi.us.es
  W: http://www.esi.us.es/~jon
+diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
+index 9734577..11a3c16 100644
+--- a/Documentation/ABI/testing/sysfs-bus-usb
++++ b/Documentation/ABI/testing/sysfs-bus-usb
+@@ -52,3 +52,36 @@ Description:
+ 		facility is inherently dangerous, it is disabled by default
+ 		for all devices except hubs.  For more information, see
+ 		Documentation/usb/persist.txt.
++
++What:		/sys/bus/usb/device/.../power/connected_duration
++Date:		January 2008
++KernelVersion:	2.6.25
++Contact:	Sarah Sharp <sarah.a.sharp at intel.com>
++Description:
++		If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
++		is present.  When read, it returns the total time (in msec)
++		that the USB device has been connected to the machine.  This
++		file is read-only.
++Users:
++		PowerTOP <power at bughost.org>
++		http://www.lesswatts.org/projects/powertop/
++
++What:		/sys/bus/usb/device/.../power/active_duration
++Date:		January 2008
++KernelVersion:	2.6.25
++Contact:	Sarah Sharp <sarah.a.sharp at intel.com>
++Description:
++		If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
++		is present.  When read, it returns the total time (in msec)
++		that the USB device has been active, i.e. not in a suspended
++		state.  This file is read-only.
++
++		Tools can use this file and the connected_duration file to
++		compute the percentage of time that a device has been active.
++		For example,
++		echo $((100 * `cat active_duration` / `cat connected_duration`))
++		will give an integer percentage.  Note that this does not
++		account for counter wrap.
++Users:
++		PowerTOP <power at bughost.org>
++		http://www.lesswatts.org/projects/powertop/
 diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
 index 4953bc2..6a0ad47 100644
 --- a/Documentation/DocBook/Makefile
@@ -76,6 +117,23 @@
    </chapter>
  
    <chapter id="chrdev">
+diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rapidio.tmpl
+index 1becf27..a8b88c4 100644
+--- a/Documentation/DocBook/rapidio.tmpl
++++ b/Documentation/DocBook/rapidio.tmpl
+@@ -133,9 +133,9 @@
+ !Idrivers/rapidio/rio-sysfs.c
+      </sect1>
+      <sect1><title>PPC32 support</title>
+-!Iarch/ppc/kernel/rio.c
+-!Earch/ppc/syslib/ppc85xx_rio.c
+-!Iarch/ppc/syslib/ppc85xx_rio.c
++!Iarch/powerpc/kernel/rio.c
++!Earch/powerpc/sysdev/fsl_rio.c
++!Iarch/powerpc/sysdev/fsl_rio.c
+      </sect1>
+   </chapter>
+ 
 diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
 index 254e769..3d2f31b 100644
 --- a/Documentation/DocBook/s390-drivers.tmpl
@@ -1214,10 +1272,33 @@
  	 Jamie Honan,
  	 Michael Hunold,
 diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
-index 20c4c8b..181bff0 100644
+index 20c4c8b..a7d9d17 100644
 --- a/Documentation/feature-removal-schedule.txt
 +++ b/Documentation/feature-removal-schedule.txt
-@@ -191,15 +191,6 @@ Who:	Kay Sievers <kay.sievers at suse.de>
+@@ -156,22 +156,6 @@ Who:	Arjan van de Ven <arjan at linux.intel.com>
+ 
+ ---------------------------
+ 
+-What:	USB driver API moves to EXPORT_SYMBOL_GPL
+-When:	February 2008
+-Files:	include/linux/usb.h, drivers/usb/core/driver.c
+-Why:	The USB subsystem has changed a lot over time, and it has been
+-	possible to create userspace USB drivers using usbfs/libusb/gadgetfs
+-	that operate as fast as the USB bus allows.  Because of this, the USB
+-	subsystem will not be allowing closed source kernel drivers to
+-	register with it, after this grace period is over.  If anyone needs
+-	any help in converting their closed source drivers over to use the
+-	userspace filesystems, please contact the
+-	linux-usb-devel at lists.sourceforge.net mailing list, and the developers
+-	there will be glad to help you out.
+-Who:	Greg Kroah-Hartman <gregkh at suse.de>
+-
+----------------------------
+-
+ What:	vm_ops.nopage
+ When:	Soon, provided in-kernel callers have been converted
+ Why:	This interface is replaced by vm_ops.fault, but it has been around
+@@ -191,15 +175,6 @@ Who:	Kay Sievers <kay.sievers at suse.de>
  
  ---------------------------
  
@@ -1233,7 +1314,7 @@
  What:	ACPI procfs interface
  When:	July 2008
  Why:	ACPI sysfs conversion should be finished by January 2008.
-@@ -225,14 +216,6 @@ Who:	Len Brown <len.brown at intel.com>
+@@ -225,14 +200,6 @@ Who:	Len Brown <len.brown at intel.com>
  
  ---------------------------
  
@@ -1248,7 +1329,7 @@
  What:	'time' kernel boot parameter
  When:	January 2008
  Why:	replaced by 'printk.time=<value>' so that printk timestamps can be
-@@ -266,22 +249,6 @@ Who:  Tejun Heo <htejun at gmail.com>
+@@ -266,22 +233,6 @@ Who:  Tejun Heo <htejun at gmail.com>
  
  ---------------------------
  
@@ -1271,7 +1352,7 @@
  What: The arch/ppc and include/asm-ppc directories
  When: Jun 2008
  Why:  The arch/powerpc tree is the merged architecture for ppc32 and ppc64
-@@ -295,16 +262,6 @@ Who:  linuxppc-dev at ozlabs.org
+@@ -295,16 +246,6 @@ Who:  linuxppc-dev at ozlabs.org
  
  ---------------------------
  
@@ -1288,7 +1369,7 @@
  What:   sk98lin network driver
  When:   Feburary 2008
  Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
-@@ -323,13 +280,77 @@ Who:	Thomas Gleixner <tglx at linutronix.de>
+@@ -323,13 +264,77 @@ Who:	Thomas Gleixner <tglx at linutronix.de>
  
  ---------------------------
  
@@ -1306,8 +1387,8 @@
 +When:	May 2008
 +Why:	These drivers are superseded by i810fb, intelfb and savagefb.
 +Who:	Jean Delvare <khali at linux-fr.org>
- 
- ---------------------------
++
++---------------------------
 +
 +What:	bcm43xx wireless network driver
 +When:	2.6.26
@@ -1365,8 +1446,8 @@
 +When:	January 2009 or Linux 2.7.0, whichever comes first
 +Why:	Superseded by newer revisions or modules
 +Who:	Jan Engelhardt <jengelh at computergmbh.de>
-+
-+---------------------------
+ 
+ ---------------------------
 +
 +What:	b43 support for firmware revision < 410
 +When:	July 2008
@@ -1446,7 +1527,7 @@
 +			Localalloc is not enabled for local mounts.
 +localflocks		This disables cluster aware flock.
 diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
-index dec9945..4413a2d 100644
+index dec9945..194c8f3 100644
 --- a/Documentation/filesystems/proc.txt
 +++ b/Documentation/filesystems/proc.txt
 @@ -857,6 +857,45 @@ CPUs.
@@ -1495,6 +1576,32 @@
  
  ------------------------------------------------------------------------------
  Summary
+@@ -1095,13 +1134,6 @@ check the amount of free space (value is in seconds). Default settings are: 4,
+ resume it  if we have a value of 3 or more percent; consider information about
+ the amount of free space valid for 30 seconds
+ 
+-audit_argv_kb
+--------------
+-
+-The file contains a single value denoting the limit on the argv array size
+-for execve (in KiB). This limit is only applied when system call auditing for
+-execve is enabled, otherwise the value is ignored.
+-
+ ctrl-alt-del
+ ------------
+ 
+@@ -1880,11 +1912,6 @@ max_size
+ Maximum size  of  the routing cache. Old entries will be purged once the cache
+ reached has this size.
+ 
+-max_delay, min_delay
+---------------------
+-
+-Delays for flushing the routing cache.
+-
+ redirect_load, redirect_number
+ ------------------------------
+ 
 diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
 index fde4420..3bd9583 100644
 --- a/Documentation/i2c/busses/i2c-i801
@@ -1704,6 +1811,349 @@
  ================================================================================
  
  IDE ATAPI streaming tape driver
+diff --git a/Documentation/ide/ChangeLog.ide-cd.1994-2004 b/Documentation/ide/ChangeLog.ide-cd.1994-2004
+new file mode 100644
+index 0000000..190d17b
+--- /dev/null
++++ b/Documentation/ide/ChangeLog.ide-cd.1994-2004
+@@ -0,0 +1,268 @@
++/*
++ * 1.00  Oct 31, 1994 -- Initial version.
++ * 1.01  Nov  2, 1994 -- Fixed problem with starting request in
++ *                       cdrom_check_status.
++ * 1.03  Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
++ * (from mlord)       -- minor changes to cdrom_setup()
++ *                    -- renamed ide_dev_s to ide_drive_t, enable irq on command
++ * 2.00  Nov 27, 1994 -- Generalize packet command interface;
++ *                       add audio ioctls.
++ * 2.01  Dec  3, 1994 -- Rework packet command interface to handle devices
++ *                       which send an interrupt when ready for a command.
++ * 2.02  Dec 11, 1994 -- Cache the TOC in the driver.
++ *                       Don't use SCMD_PLAYAUDIO_TI; it's not included
++ *                       in the current version of ATAPI.
++ *                       Try to use LBA instead of track or MSF addressing
++ *                       when possible.
++ *                       Don't wait for READY_STAT.
++ * 2.03  Jan 10, 1995 -- Rewrite block read routines to handle block sizes
++ *                       other than 2k and to move multiple sectors in a
++ *                       single transaction.
++ * 2.04  Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
++ *                       Thanks to Nick Saw <cwsaw at pts7.pts.mot.com> for
++ *                       help in figuring this out.  Ditto for Acer and
++ *                       Aztech drives, which seem to have the same problem.
++ * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
++ * 2.05  Jun  8, 1995 -- Don't attempt to retry after an illegal request
++ *                        or data protect error.
++ *                       Use HWIF and DEV_HWIF macros as in ide.c.
++ *                       Always try to do a request_sense after
++ *                        a failed command.
++ *                       Include an option to give textual descriptions
++ *                        of ATAPI errors.
++ *                       Fix a bug in handling the sector cache which
++ *                        showed up if the drive returned data in 512 byte
++ *                        blocks (like Pioneer drives).  Thanks to
++ *                        Richard Hirst <srh at gpt.co.uk> for diagnosing this.
++ *                       Properly supply the page number field in the
++ *                        MODE_SELECT command.
++ *                       PLAYAUDIO12 is broken on the Aztech; work around it.
++ * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
++ *                       (my apologies to Scott, but now ide-cd.c is independent)
++ * 3.00  Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
++ *                       Implement CDROMREADAUDIO ioctl (UNTESTED).
++ *                       Use input_ide_data() and output_ide_data().
++ *                       Add door locking.
++ *                       Fix usage count leak in cdrom_open, which happened
++ *                        when a read-write mount was attempted.
++ *                       Try to load the disk on open.
++ *                       Implement CDROMEJECT_SW ioctl (off by default).
++ *                       Read total cdrom capacity during open.
++ *                       Rearrange logic in cdrom_decode_status.  Issue
++ *                        request sense commands for failed packet commands
++ *                        from here instead of from cdrom_queue_packet_command.
++ *                        Fix a race condition in retrieving error information.
++ *                       Suppress printing normal unit attention errors and
++ *                        some drive not ready errors.
++ *                       Implement CDROMVOLREAD ioctl.
++ *                       Implement CDROMREADMODE1/2 ioctls.
++ *                       Fix race condition in setting up interrupt handlers
++ *                        when the `serialize' option is used.
++ * 3.01  Sep  2, 1995 -- Fix ordering of reenabling interrupts in
++ *                        cdrom_queue_request.
++ *                       Another try at using ide_[input,output]_data.
++ * 3.02  Sep 16, 1995 -- Stick total disk capacity in partition table as well.
++ *                       Make VERBOSE_IDE_CD_ERRORS dump failed command again.
++ *                       Dump out more information for ILLEGAL REQUEST errs.
++ *                       Fix handling of errors occurring before the
++ *                        packet command is transferred.
++ *                       Fix transfers with odd bytelengths.
++ * 3.03  Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
++ *                       `DCI-2S10' drives are broken too.
++ * 3.04  Nov 20, 1995 -- So are Vertos drives.
++ * 3.05  Dec  1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
++ * 3.06  Dec 16, 1995 -- Add support needed for partitions.
++ *                       More workarounds for Vertos bugs (based on patches
++ *                        from Holger Dietze <dietze at aix520.informatik.uni-leipzig.de>).
++ *                       Try to eliminate byteorder assumptions.
++ *                       Use atapi_cdrom_subchnl struct definition.
++ *                       Add STANDARD_ATAPI compilation option.
++ * 3.07  Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
++ *                        Vertos 300.
++ *                       Add NO_DOOR_LOCKING configuration option.
++ *                       Handle drive_cmd requests w/NULL args (for hdparm -t).
++ *                       Work around sporadic Sony55e audio play problem.
++ * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
++ *                        problem with "hde=cdrom" with no drive present.  -ml
++ * 3.08  Mar  6, 1996 -- More Vertos workarounds.
++ * 3.09  Apr  5, 1996 -- Add CDROMCLOSETRAY ioctl.
++ *                       Switch to using MSF addressing for audio commands.
++ *                       Reformat to match kernel tabbing style.
++ *                       Add CDROM_GET_UPC ioctl.
++ * 3.10  Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
++ * 3.11  Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko at colossus.escape.de>
++ *                       to remove redundant verify_area calls.
++ * 3.12  May  7, 1996 -- Rudimentary changer support.  Based on patches
++ *                        from Gerhard Zuber <zuber at berlin.snafu.de>.
++ *                       Let open succeed even if there's no loaded disc.
++ * 3.13  May 19, 1996 -- Fixes for changer code.
++ * 3.14  May 29, 1996 -- Add work-around for Vertos 600.
++ *                        (From Hennus Bergman <hennus at sky.ow.nl>.)
++ * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
++ *                        from Ben Galliart <bgallia at luc.edu> with
++ *                        special help from Jeff Lightfoot
++ *                        <jeffml at pobox.com>
++ * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
++ * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
++ * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
++ *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
++ * 3.18  Oct 31, 1996 -- Added module and DMA support.
++ *
++ * 4.00  Nov 5, 1996   -- New ide-cd maintainer,
++ *                                 Erik B. Andersen <andersee at debian.org>
++ *                     -- Newer Creative drives don't always set the error
++ *                          register correctly.  Make sure we see media changes
++ *                          regardless.
++ *                     -- Integrate with generic cdrom driver.
++ *                     -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
++ *                          a patch from Ciro Cattuto <>.
++ *                     -- Call set_device_ro.
++ *                     -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
++ *                          ioctls, based on patch by Erik Andersen
++ *                     -- Add some probes of drive capability during setup.
++ *
++ * 4.01  Nov 11, 1996  -- Split into ide-cd.c and ide-cd.h
++ *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE
++ *                          ioctls in favor of a generalized approach
++ *                          using the generic cdrom driver.
++ *                     -- Fully integrated with the 2.1.X kernel.
++ *                     -- Other stuff that I forgot (lots of changes)
++ *
++ * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio at netvision.net.il>
++ *                          to fix the drive door locking problems.
++ *
++ * 4.03  Dec 04, 1996  -- Added DSC overlap support.
++ * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch
++ *                          by Ales Makarov (xmakarov at sun.felk.cvut.cz)
++ *
++ * 4.05  Nov 20, 1997  -- Modified to print more drive info on init
++ *                        Minor other changes
++ *                        Fix errors on CDROMSTOP (If you have a "Dolphin",
++ *                          you must define IHAVEADOLPHIN)
++ *                        Added identifier so new Sanyo CD-changer works
++ *                        Better detection if door locking isn't supported
++ *
++ * 4.06  Dec 17, 1997  -- fixed endless "tray open" messages  -ml
++ * 4.07  Dec 17, 1997  -- fallback to set pc->stat on "tray open"
++ * 4.08  Dec 18, 1997  -- spew less noise when tray is empty
++ *                     -- fix speed display for ACER 24X, 18X
++ * 4.09  Jan 04, 1998  -- fix handling of the last block so we return
++ *                         an end of file instead of an I/O error (Gadi)
++ * 4.10  Jan 24, 1998  -- fixed a bug so now changers can change to a new
++ *                         slot when there is no disc in the current slot.
++ *                     -- Fixed a memory leak where info->changer_info was
++ *                         malloc'ed but never free'd when closing the device.
++ *                     -- Cleaned up the global namespace a bit by making more
++ *                         functions static that should already have been.
++ * 4.11  Mar 12, 1998  -- Added support for the CDROM_SELECT_SPEED ioctl
++ *                         based on a patch for 2.0.33 by Jelle Foks
++ *                         <jelle at scintilla.utwente.nl>, a patch for 2.0.33
++ *                         by Toni Giorgino <toni at pcape2.pi.infn.it>, the SCSI
++ *                         version, and my own efforts.  -erik
++ *                     -- Fixed a stupid bug which egcs was kind enough to
++ *                         inform me of where "Illegal mode for this track"
++ *                         was never returned due to a comparison on data
++ *                         types of limited range.
++ * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is
++ *                         now set ionly for CD-R and CD-RW drives.  I had
++ *                         removed this support because it produced errors.
++ *                         It produced errors _only_ for non-writers. duh.
++ * 4.13  May 05, 1998  -- Suppress useless "in progress of becoming ready"
++ *                         messages, since this is not an error.
++ *                     -- Change error messages to be const
++ *                     -- Remove a "\t" which looks ugly in the syslogs
++ * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
++ *                         since the .pdf version doesn't seem to work...
++ *                     -- Updated the TODO list to something more current.
++ *
++ * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess,
++ *                         patch thanks to "Eddie C. Dost" <ecd at skynet.be>
++ *
++ * 4.50  Oct 19, 1998  -- New maintainers!
++ *                         Jens Axboe <axboe at image.dk>
++ *                         Chris Zwilling <chris at cloudnet.com>
++ *
++ * 4.51  Dec 23, 1998  -- Jens Axboe <axboe at image.dk>
++ *                      - ide_cdrom_reset enabled since the ide subsystem
++ *                         handles resets fine now. <axboe at image.dk>
++ *                      - Transfer size fix for Samsung CD-ROMs, thanks to
++ *                        "Ville Hallik" <ville.hallik at mail.ee>.
++ *                      - other minor stuff.
++ *
++ * 4.52  Jan 19, 1999  -- Jens Axboe <axboe at image.dk>
++ *                      - Detect DVD-ROM/RAM drives
++ *
++ * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
++ *                         drive in transfer size limit.
++ *                      - Fix the I/O error when doing eject without a medium
++ *                         loaded on some drives.
++ *                      - CDROMREADMODE2 is now implemented through
++ *                         CDROMREADRAW, since many drives don't support
++ *                         MODE2 (even though ATAPI 2.6 says they must).
++ *                      - Added ignore parameter to ide-cd (as a module), eg
++ *                         	insmod ide-cd ignore='hda hdb'
++ *                         Useful when using ide-cd in conjunction with
++ *                         ide-scsi. TODO: non-modular way of doing the
++ *                         same.
++ *
++ * 4.54  Aug 5, 1999	- Support for MMC2 class commands through the generic
++ *			  packet interface to cdrom.c.
++ *			- Unified audio ioctl support, most of it.
++ *			- cleaned up various deprecated verify_area().
++ *			- Added ide_cdrom_packet() as the interface for
++ *			  the Uniform generic_packet().
++ *			- bunch of other stuff, will fill in logs later.
++ *			- report 1 slot for non-changers, like the other
++ *			  cd-rom drivers. don't report select disc for
++ *			  non-changers as well.
++ *			- mask out audio playing, if the device can't do it.
++ *
++ * 4.55  Sep 1, 1999	- Eliminated the rest of the audio ioctls, except
++ *			  for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
++ *			  use this independently of the actual audio handling.
++ *			  They will disappear later when I get the time to
++ *			  do it cleanly.
++ *			- Minimize the TOC reading - only do it when we
++ *			  know a media change has occurred.
++ *			- Moved all the CDROMREADx ioctls to the Uniform layer.
++ *			- Heiko Eißfeldt <heiko at colossus.escape.de> supplied
++ *			  some fixes for CDI.
++ *			- CD-ROM leaving door locked fix from Andries
++ *			  Brouwer <Andries.Brouwer at cwi.nl>
++ *			- Erik Andersen <andersen at xmission.com> unified
++ *			  commands across the various drivers and how
++ *			  sense errors are handled.
++ *
++ * 4.56  Sep 12, 1999	- Removed changer support - it is now in the
++ *			  Uniform layer.
++ *			- Added partition based multisession handling.
++ *			- Mode sense and mode select moved to the
++ *			  Uniform layer.
++ *			- Fixed a problem with WPI CDS-32X drive - it
++ *			  failed the capabilities
++ *
++ * 4.57  Apr 7, 2000	- Fixed sense reporting.
++ *			- Fixed possible oops in ide_cdrom_get_last_session()
++ *			- Fix locking mania and make ide_cdrom_reset relock
++ *			- Stop spewing errors to log when magicdev polls with
++ *			  TEST_UNIT_READY on some drives.
++ *			- Various fixes from Tobias Ringstrom:
++ *			  tray if it was locked prior to the reset.
++ *			  - cdrom_read_capacity returns one frame too little.
++ *			  - Fix real capacity reporting.
++ *
++ * 4.58  May 1, 2000	- Clean up ACER50 stuff.
++ *			- Fix small problem with ide_cdrom_capacity
++ *
++ * 4.59  Aug 11, 2000	- Fix changer problem in cdrom_read_toc, we weren't
++ *			  correctly sensing a disc change.
++ *			- Rearranged some code
++ *			- Use extended sense on drives that support it for
++ *			  correctly reporting tray status -- from
++ *			  Michael D Johnson <johnsom at orst.edu>
++ * 4.60  Dec 17, 2003	- Add mt rainier support
++ *			- Bump timeout for packet commands, matches sr
++ *			- Odd stuff
++ * 4.61  Jan 22, 2004	- support hardware sector sizes other than 2kB,
++ *			  Pascal Schmidt <der.eremit at email.de>
++ */
+diff --git a/Documentation/ide/ChangeLog.ide-floppy.1996-2002 b/Documentation/ide/ChangeLog.ide-floppy.1996-2002
+new file mode 100644
+index 0000000..46c19ef
+--- /dev/null
++++ b/Documentation/ide/ChangeLog.ide-floppy.1996-2002
+@@ -0,0 +1,63 @@
++/*
++ * Many thanks to Lode Leroy <Lode.Leroy at www.ibase.be>, who tested so many
++ * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive.
++ *
++ * Ver 0.1   Oct 17 96   Initial test version, mostly based on ide-tape.c.
++ * Ver 0.2   Oct 31 96   Minor changes.
++ * Ver 0.3   Dec  2 96   Fixed error recovery bug.
++ * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
++ * Ver 0.5   Feb 21 97   Add partitions support.
++ *                       Use the minimum of the LBA and CHS capacities.
++ *                       Avoid hwgroup->rq == NULL on the last irq.
++ *                       Fix potential null dereferencing with DEBUG_LOG.
++ * Ver 0.8   Dec  7 97   Increase irq timeout from 10 to 50 seconds.
++ *                       Add media write-protect detection.
++ *                       Issue START command only if TEST UNIT READY fails.
++ *                       Add work-around for IOMEGA ZIP revision 21.D.
++ *                       Remove idefloppy_get_capabilities().
++ * Ver 0.9   Jul  4 99   Fix a bug which might have caused the number of
++ *                        bytes requested on each interrupt to be zero.
++ *                        Thanks to <shanos at es.co.nz> for pointing this out.
++ * Ver 0.9.sv Jan 6 01   Sam Varshavchik <mrsam at courier-mta.com>
++ *                       Implement low level formatting.  Reimplemented
++ *                       IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp
++ *                       bit.  My LS-120 drive barfs on
++ *                       IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me.
++ *                       Compromise by not reporting a failure to get this
++ *                       mode page.  Implemented four IOCTLs in order to
++ *                       implement formatting.  IOCTls begin with 0x4600,
++ *                       0x46 is 'F' as in Format.
++ *            Jan 9 01   Userland option to select format verify.
++ *                       Added PC_SUPPRESS_ERROR flag - some idefloppy drives
++ *                       do not implement IDEFLOPPY_CAPABILITIES_PAGE, and
++ *                       return a sense error.  Suppress error reporting in
++ *                       this particular case in order to avoid spurious
++ *                       errors in syslog.  The culprit is
++ *                       idefloppy_get_capability_page(), so move it to
++ *                       idefloppy_begin_format() so that it's not used
++ *                       unless absolutely necessary.
++ *                       If drive does not support format progress indication
++ *                       monitor the dsc bit in the status register.
++ *                       Also, O_NDELAY on open will allow the device to be
++ *                       opened without a disk available.  This can be used to
++ *                       open an unformatted disk, or get the device capacity.
++ * Ver 0.91  Dec 11 99   Added IOMEGA Clik! drive support by
++ *     		   <paul at paulbristow.net>
++ * Ver 0.92  Oct 22 00   Paul Bristow became official maintainer for this
++ *           		   driver.  Included Powerbook internal zip kludge.
++ * Ver 0.93  Oct 24 00   Fixed bugs for Clik! drive
++ *                        no disk on insert and disk change now works
++ * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
++ * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
++ * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
++ *                       including set_bit patch from Rusty Russell
++ * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
++ * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
++ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
++ *                        fix a lost interrupt problem. It appears the busy
++ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
++ *                        drive before the drive was actually ready.
++ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
++ * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code
++ *                        to support new PocketZip drives
++ */
 diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
 index 5c7fbf9..c18363b 100644
 --- a/Documentation/ioctl-number.txt
@@ -1871,7 +2321,7 @@
 +$ find . -name Kconfig\* | xargs grep -ns "depends on.*=.*||.*=" | grep -v orig
 +
 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
-index c417877..92c40d1 100644
+index c417877..cf38689 100644
 --- a/Documentation/kernel-parameters.txt
 +++ b/Documentation/kernel-parameters.txt
 @@ -34,6 +34,7 @@ parameter is applicable:
@@ -1882,7 +2332,19 @@
  	AX25	Appropriate AX.25 support is enabled.
  	BLACKFIN Blackfin architecture is enabled.
  	DRM	Direct Rendering Management support is enabled.
-@@ -369,7 +370,8 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -167,6 +168,11 @@ and is between 256 and 4096 characters. It is defined in the file
+ 	acpi_irq_isa=	[HW,ACPI] If irq_balance, mark listed IRQs used by ISA
+ 			Format: <irq>,<irq>...
+ 
++	acpi_new_pts_ordering [HW,ACPI]
++			Enforce the ACPI 2.0 ordering of the _PTS control
++			method wrt putting devices into low power states
++			default: pre ACPI 2.0 ordering of _PTS
++
+ 	acpi_no_auto_ssdt	[HW,ACPI] Disable automatic loading of SSDT
+ 
+ 	acpi_os_name=	[HW,ACPI] Tell ACPI BIOS the name of the OS
+@@ -369,7 +375,8 @@ and is between 256 and 4096 characters. It is defined in the file
  			configured.  Potentially dangerous and should only be
  			used if you are entirely sure of the consequences.
  
@@ -1892,7 +2354,7 @@
  
  	checkreqprot	[SELINUX] Set initial checkreqprot flag value.
  			Format: { "0" | "1" }
-@@ -381,6 +383,12 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -381,6 +388,12 @@ and is between 256 and 4096 characters. It is defined in the file
  			Value can be changed at runtime via
  				/selinux/checkreqprot.
  
@@ -1905,7 +2367,7 @@
  	clock=		[BUGS=X86-32, HW] gettimeofday clocksource override.
  			[Deprecated]
  			Forces specified clocksource (if available) to be used
-@@ -408,8 +416,21 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -408,8 +421,21 @@ and is between 256 and 4096 characters. It is defined in the file
  			[SPARC64] tick
  			[X86-64] hpet,tsc
  
@@ -1929,7 +2391,7 @@
  			Range: 0 - 8192
  			Default: 64
  
-@@ -562,6 +583,12 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -562,6 +588,12 @@ and is between 256 and 4096 characters. It is defined in the file
  			See drivers/char/README.epca and
  			Documentation/digiepca.txt.
  
@@ -1942,7 +2404,7 @@
  	dmasound=	[HW,OSS] Sound subsystem buffers
  
  	dscc4.setup=	[NET]
-@@ -652,6 +679,10 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -652,6 +684,10 @@ and is between 256 and 4096 characters. It is defined in the file
  
  	gamma=		[HW,DRM]
  
@@ -1953,7 +2415,7 @@
  	gdth=		[HW,SCSI]
  			See header of drivers/scsi/gdth.c.
  
-@@ -686,6 +717,7 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -686,6 +722,7 @@ and is between 256 and 4096 characters. It is defined in the file
  			See Documentation/isdn/README.HiSax.
  
  	hugepages=	[HW,X86-32,IA-64] Maximal number of HugeTLB pages.
@@ -1961,7 +2423,7 @@
  
  	i8042.direct	[HW] Put keyboard port into non-translated mode
  	i8042.dumbkbd	[HW] Pretend that controller can only read data from
-@@ -786,6 +818,16 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -786,6 +823,16 @@ and is between 256 and 4096 characters. It is defined in the file
  			for translation below 32 bit and if not available
  			then look in the higher range.
  
@@ -1978,7 +2440,7 @@
  	io7=		[HW] IO7 for Marvel based alpha systems
  			See comment before marvel_specify_io7 in
  			arch/alpha/kernel/core_marvel.c.
-@@ -1051,6 +1093,11 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1051,6 +1098,11 @@ and is between 256 and 4096 characters. It is defined in the file
  			Multi-Function General Purpose Timers on AMD Geode
  			platforms.
  
@@ -1990,7 +2452,7 @@
  	mga=		[HW,DRM]
  
  	mousedev.tap_time=
-@@ -1123,6 +1170,10 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1123,6 +1175,10 @@ and is between 256 and 4096 characters. It is defined in the file
  			of returning the full 64-bit number.
  			The default is to return 64-bit inode numbers.
  
@@ -2001,7 +2463,7 @@
  	nmi_watchdog=	[KNL,BUGS=X86-32] Debugging features for SMP kernels
  
  	no387		[BUGS=X86-32] Tells the kernel to use the 387 maths
-@@ -1147,6 +1198,8 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1147,6 +1203,8 @@ and is between 256 and 4096 characters. It is defined in the file
  
  	nodisconnect	[HW,SCSI,M68K] Disables SCSI disconnects.
  
@@ -2010,7 +2472,7 @@
  	noexec		[IA-64]
  
  	noexec		[X86-32,X86-64]
-@@ -1157,6 +1210,8 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1157,6 +1215,8 @@ and is between 256 and 4096 characters. It is defined in the file
  			register save and restore. The kernel will only save
  			legacy floating-point registers on task switch.
  
@@ -2019,7 +2481,7 @@
  	nohlt		[BUGS=ARM]
  
  	no-hlt		[BUGS=X86-32] Tells the kernel that the hlt
-@@ -1593,7 +1648,13 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1593,7 +1653,13 @@ and is between 256 and 4096 characters. It is defined in the file
  			Format: <vendor>:<model>:<flags>
  			(flags are integer value)
  
@@ -2034,7 +2496,7 @@
  
  	scsi_mod.scan=	[SCSI] sync (default) scans SCSI busses as they are
  			discovered.  async scans them in kernel threads,
-@@ -1960,6 +2021,11 @@ and is between 256 and 4096 characters. It is defined in the file
+@@ -1960,6 +2026,11 @@ and is between 256 and 4096 characters. It is defined in the file
  			vdso=1: enable VDSO (default)
  			vdso=0: disable VDSO mapping
  
@@ -4078,10 +4540,10 @@
                      These cases are counted separately (not as InErrors).
 diff --git a/Documentation/networking/xfrm_proc.txt b/Documentation/networking/xfrm_proc.txt
 new file mode 100644
-index 0000000..53c1a58
+index 0000000..d0d8baf
 --- /dev/null
 +++ b/Documentation/networking/xfrm_proc.txt
-@@ -0,0 +1,70 @@
+@@ -0,0 +1,74 @@
 +XFRM proc - /proc/net/xfrm_* files
 +==================================
 +Masahide NAKAMURA <nakam at linux-ipv6.org>
@@ -4110,8 +4572,9 @@
 +	e.g. SA key is wrong
 +XfrmInStateModeError:
 +	Transformation mode specific error
-+XfrmInSeqOutOfWindow:
-+	Sequence out of window
++XfrmInStateSeqError:
++	Sequence error
++	i.e. Sequence number is out of window
 +XfrmInStateExpired:
 +	State is expired
 +XfrmInStateMismatch:
@@ -4144,6 +4607,9 @@
 +	Transformation protocol specific error
 +XfrmOutStateModeError:
 +	Transformation mode specific error
++XfrmOutStateSeqError:
++	Sequence error
++	i.e. Sequence number overflow
 +XfrmOutStateExpired:
 +	State is expired
 +XfrmOutPolBlock:
@@ -4152,6 +4618,61 @@
 +	Policy is dead
 +XfrmOutPolError:
 +	Policy error
+diff --git a/Documentation/pci.txt b/Documentation/pci.txt
+index 7754f5a..72b20c6 100644
+--- a/Documentation/pci.txt
++++ b/Documentation/pci.txt
+@@ -274,8 +274,6 @@ the PCI device by calling pci_enable_device(). This will:
+ 	o allocate an IRQ (if BIOS did not).
+ 
+ NOTE: pci_enable_device() can fail! Check the return value.
+-NOTE2: Also see pci_enable_device_bars() below. Drivers can
+-    attempt to enable only a subset of BARs they need.
+ 
+ [ OS BUG: we don't check resource allocations before enabling those
+   resources. The sequence would make more sense if we called
+@@ -605,40 +603,7 @@ device lists. This is still possible but discouraged.
+ 
+ 
+ 
+-10. pci_enable_device_bars() and Legacy I/O Port space
+-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-
+-Large servers may not be able to provide I/O port resources to all PCI
+-devices. I/O Port space is only 64KB on Intel Architecture[1] and is
+-likely also fragmented since the I/O base register of PCI-to-PCI
+-bridge will usually be aligned to a 4KB boundary[2]. On such systems,
+-pci_enable_device() and pci_request_region() will fail when
+-attempting to enable I/O Port regions that don't have I/O Port
+-resources assigned.
+-
+-Fortunately, many PCI devices which request I/O Port resources also
+-provide access to the same registers via MMIO BARs. These devices can
+-be handled without using I/O port space and the drivers typically
+-offer a CONFIG_ option to only use MMIO regions
+-(e.g. CONFIG_TULIP_MMIO). PCI devices typically provide I/O port
+-interface for legacy OSes and will work when I/O port resources are not
+-assigned. The "PCI Local Bus Specification Revision 3.0" discusses
+-this on p.44, "IMPLEMENTATION NOTE".
+-
+-If your PCI device driver doesn't need I/O port resources assigned to
+-I/O Port BARs, you should use pci_enable_device_bars() instead of
+-pci_enable_device() in order not to enable I/O port regions for the
+-corresponding devices. In addition, you should use
+-pci_request_selected_regions() and pci_release_selected_regions()
+-instead of pci_request_regions()/pci_release_regions() in order not to
+-request/release I/O port regions for the corresponding devices.
+-
+-[1] Some systems support 64KB I/O port space per PCI segment.
+-[2] Some PCI-to-PCI bridges support optional 1KB aligned I/O base.
+-
+-
+-
+-11. MMIO Space and "Write Posting"
++10. MMIO Space and "Write Posting"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 
+ Converting a driver from using I/O Port space to using MMIO space
 diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
 index 481faf5..a327db6 100644
 --- a/Documentation/pnp.txt
@@ -4168,6 +4689,591 @@
  device's directory:
  id - displays a list of support EISA IDs
  options - displays possible resource configurations
+diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
+index 57aef2f..1555001 100644
+--- a/Documentation/power/basic-pm-debugging.txt
++++ b/Documentation/power/basic-pm-debugging.txt
+@@ -1,45 +1,111 @@
+-Debugging suspend and resume
++Debugging hibernation and suspend
+ 	(C) 2007 Rafael J. Wysocki <rjw at sisk.pl>, GPL
+ 
+-1. Testing suspend to disk (STD)
++1. Testing hibernation (aka suspend to disk or STD)
+ 
+-To verify that the STD works, you can try to suspend in the "reboot" mode:
++To check if hibernation works, you can try to hibernate in the "reboot" mode:
+ 
+ # echo reboot > /sys/power/disk
+ # echo disk > /sys/power/state
+ 
+-and the system should suspend, reboot, resume and get back to the command prompt
+-where you have started the transition.  If that happens, the STD is most likely
+-to work correctly, but you need to repeat the test at least a couple of times in
+-a row for confidence.  This is necessary, because some problems only show up on
+-a second attempt at suspending and resuming the system.  You should also test
+-the "platform" and "shutdown" modes of suspend:
++and the system should create a hibernation image, reboot, resume and get back to
++the command prompt where you have started the transition.  If that happens,
++hibernation is most likely to work correctly.  Still, you need to repeat the
++test at least a couple of times in a row for confidence.  [This is necessary,
++because some problems only show up on a second attempt at suspending and
++resuming the system.]  Moreover, hibernating in the "reboot" and "shutdown"
++modes causes the PM core to skip some platform-related callbacks which on ACPI
++systems might be necessary to make hibernation work.  Thus, if you machine fails
++to hibernate or resume in the "reboot" mode, you should try the "platform" mode:
+ 
+ # echo platform > /sys/power/disk
+ # echo disk > /sys/power/state
+ 
+-or
++which is the default and recommended mode of hibernation.
++
++Unfortunately, the "platform" mode of hibernation does not work on some systems
++with broken BIOSes.  In such cases the "shutdown" mode of hibernation might
++work:
+ 
+ # echo shutdown > /sys/power/disk
+ # echo disk > /sys/power/state
+ 
+-in which cases you will have to press the power button to make the system
+-resume.  If that does not work, you will need to identify what goes wrong.
++(it is similar to the "reboot" mode, but it requires you to press the power
++button to make the system resume).
++
++If neither "platform" nor "shutdown" hibernation mode works, you will need to
++identify what goes wrong.
++
++a) Test modes of hibernation
++
++To find out why hibernation fails on your system, you can use a special testing
++facility available if the kernel is compiled with CONFIG_PM_DEBUG set.  Then,
++there is the file /sys/power/pm_test that can be used to make the hibernation
++core run in a test mode.  There are 5 test modes available:
++
++freezer
++- test the freezing of processes
++
++devices
++- test the freezing of processes and suspending of devices
+ 
+-a) Test mode of STD
++platform
++- test the freezing of processes, suspending of devices and platform
++  global control methods(*)
+ 
+-To verify if there are any drivers that cause problems you can run the STD
+-in the test mode:
++processors
++- test the freezing of processes, suspending of devices, platform
++  global control methods(*) and the disabling of nonboot CPUs
+ 
+-# echo test > /sys/power/disk
++core
++- test the freezing of processes, suspending of devices, platform global
++  control methods(*), the disabling of nonboot CPUs and suspending of
++  platform/system devices
++
++(*) the platform global control methods are only available on ACPI systems
++    and are only tested if the hibernation mode is set to "platform"
++
++To use one of them it is necessary to write the corresponding string to
++/sys/power/pm_test (eg. "devices" to test the freezing of processes and
++suspending devices) and issue the standard hibernation commands.  For example,
++to use the "devices" test mode along with the "platform" mode of hibernation,
++you should do the following:
++
++# echo devices > /sys/power/pm_test
++# echo platform > /sys/power/disk
+ # echo disk > /sys/power/state
+ 
+-in which case the system should freeze tasks, suspend devices, disable nonboot
+-CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
+-tasks and return to your command prompt.  If that fails, most likely there is
+-a driver that fails to either suspend or resume (in the latter case the system
+-may hang or be unstable after the test, so please take that into consideration).
+-To find this driver, you can carry out a binary search according to the rules:
++Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
++resume devices and thaw processes.  If "platform" is written to
++/sys/power/pm_test , then after suspending devices the kernel will additionally
++invoke the global control methods (eg. ACPI global control methods) used to
++prepare the platform firmware for hibernation.  Next, it will wait 5 seconds and
++invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
++
++Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
++hibernation/suspend operations.  Also, when open for reading, /sys/power/pm_test
++contains a space-separated list of all available tests (including "none" that
++represents the normal functionality) in which the current test level is
++indicated by square brackets.
++
++Generally, as you can see, each test level is more "invasive" than the previous
++one and the "core" level tests the hardware and drivers as deeply as possible
++without creating a hibernation image.  Obviously, if the "devices" test fails,
++the "platform" test will fail as well and so on.  Thus, as a rule of thumb, you
++should try the test modes starting from "freezer", through "devices", "platform"
++and "processors" up to "core" (repeat the test on each level a couple of times
++to make sure that any random factors are avoided).
++
++If the "freezer" test fails, there is a task that cannot be frozen (in that case
++it usually is possible to identify the offending task by analysing the output of
++dmesg obtained after the failing test).  Failure at this level usually means
++that there is a problem with the tasks freezer subsystem that should be
++reported.
++
++If the "devices" test fails, most likely there is a driver that cannot suspend
++or resume its device (in the latter case the system may hang or become unstable
++after the test, so please take that into consideration).  To find this driver,
++you can carry out a binary search according to the rules:
+ - if the test fails, unload a half of the drivers currently loaded and repeat
+ (that would probably involve rebooting the system, so always note what drivers
+ have been loaded before the test),
+@@ -47,23 +113,46 @@ have been loaded before the test),
+ recently and repeat.
+ 
+ Once you have found the failing driver (there can be more than just one of
+-them), you have to unload it every time before the STD transition.  In that case
+-please make sure to report the problem with the driver.
+-
+-It is also possible that a cycle can still fail after you have unloaded
+-all modules. In that case, you would want to look in your kernel configuration
+-for the drivers that can be compiled as modules (testing again with them as
+-modules), and possibly also try boot time options such as "noapic" or "noacpi".
++them), you have to unload it every time before hibernation.  In that case please
++make sure to report the problem with the driver.
++
++It is also possible that the "devices" test will still fail after you have
++unloaded all modules. In that case, you may want to look in your kernel
++configuration for the drivers that can be compiled as modules (and test again
++with these drivers compiled as modules).  You may also try to use some special
++kernel command line options such as "noapic", "noacpi" or even "acpi=off".
++
++If the "platform" test fails, there is a problem with the handling of the
++platform (eg. ACPI) firmware on your system.  In that case the "platform" mode
++of hibernation is not likely to work.  You can try the "shutdown" mode, but that
++is rather a poor man's workaround.
++
++If the "processors" test fails, the disabling/enabling of nonboot CPUs does not
++work (of course, this only may be an issue on SMP systems) and the problem
++should be reported.  In that case you can also try to switch the nonboot CPUs
++off and on using the /sys/devices/system/cpu/cpu*/online sysfs attributes and
++see if that works.
++
++If the "core" test fails, which means that suspending of the system/platform
++devices has failed (these devices are suspended on one CPU with interrupts off),
++the problem is most probably hardware-related and serious, so it should be
++reported.
++
++A failure of any of the "platform", "processors" or "core" tests may cause your
++system to hang or become unstable, so please beware.  Such a failure usually
++indicates a serious problem that very well may be related to the hardware, but
++please report it anyway.
+ 
+ b) Testing minimal configuration
+ 
+-If the test mode of STD works, you can boot the system with "init=/bin/bash"
+-and attempt to suspend in the "reboot", "shutdown" and "platform" modes.  If
+-that does not work, there probably is a problem with a driver statically
+-compiled into the kernel and you can try to compile more drivers as modules,
+-so that they can be tested individually.  Otherwise, there is a problem with a
+-modular driver and you can find it by loading a half of the modules you normally
+-use and binary searching in accordance with the algorithm:
++If all of the hibernation test modes work, you can boot the system with the
++"init=/bin/bash" command line parameter and attempt to hibernate in the
++"reboot", "shutdown" and "platform" modes.  If that does not work, there
++probably is a problem with a driver statically compiled into the kernel and you
++can try to compile more drivers as modules, so that they can be tested
++individually.  Otherwise, there is a problem with a modular driver and you can
++find it by loading a half of the modules you normally use and binary searching
++in accordance with the algorithm:
+ - if there are n modules loaded and the attempt to suspend and resume fails,
+ unload n/2 of the modules and try again (that would probably involve rebooting
+ the system),
+@@ -71,19 +160,19 @@ the system),
+ load n/2 modules more and try again.
+ 
+ Again, if you find the offending module(s), it(they) must be unloaded every time
+-before the STD transition, and please report the problem with it(them).
++before hibernation, and please report the problem with it(them).
+ 
+ c) Advanced debugging
+ 
+-In case the STD does not work on your system even in the minimal configuration
+-and compiling more drivers as modules is not practical or some modules cannot
+-be unloaded, you can use one of the more advanced debugging techniques to find
+-the problem.  First, if there is a serial port in your box, you can boot the
+-kernel with the 'no_console_suspend' parameter and try to log kernel
+-messages using the serial console.  This may provide you with some information
+-about the reasons of the suspend (resume) failure.  Alternatively, it may be
+-possible to use a FireWire port for debugging with firescope
+-(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On i386 it is also possible to
++In case that hibernation does not work on your system even in the minimal
++configuration and compiling more drivers as modules is not practical or some
++modules cannot be unloaded, you can use one of the more advanced debugging
++techniques to find the problem.  First, if there is a serial port in your box,
++you can boot the kernel with the 'no_console_suspend' parameter and try to log
++kernel messages using the serial console.  This may provide you with some
++information about the reasons of the suspend (resume) failure.  Alternatively,
++it may be possible to use a FireWire port for debugging with firescope
++(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On x86 it is also possible to
+ use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
+ 
+ 2. Testing suspend to RAM (STR)
+@@ -91,16 +180,25 @@ use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
+ To verify that the STR works, it is generally more convenient to use the s2ram
+ tool available from http://suspend.sf.net and documented at
+ http://en.opensuse.org/s2ram .  However, before doing that it is recommended to
+-carry out the procedure described in section 1.
+-
+-Assume you have resolved the problems with the STD and you have found some
+-failing drivers.  These drivers are also likely to fail during the STR or
+-during the resume, so it is better to unload them every time before the STR
+-transition.  Now, you can follow the instructions at
+-http://en.opensuse.org/s2ram to test the system, but if it does not work
+-"out of the box", you may need to boot it with "init=/bin/bash" and test
+-s2ram in the minimal configuration.  In that case, you may be able to search
+-for failing drivers by following the procedure analogous to the one described in
+-1b).  If you find some failing drivers, you will have to unload them every time
+-before the STR transition (ie. before you run s2ram), and please report the
+-problems with them.
++carry out STR testing using the facility described in section 1.
++
++Namely, after writing "freezer", "devices", "platform", "processors", or "core"
++into /sys/power/pm_test (available if the kernel is compiled with
++CONFIG_PM_DEBUG set) the suspend code will work in the test mode corresponding
++to given string.  The STR test modes are defined in the same way as for
++hibernation, so please refer to Section 1 for more information about them.  In
++particular, the "core" test allows you to test everything except for the actual
++invocation of the platform firmware in order to put the system into the sleep
++state.
++
++Among other things, the testing with the help of /sys/power/pm_test may allow
++you to identify drivers that fail to suspend or resume their devices.  They
++should be unloaded every time before an STR transition.
++
++Next, you can follow the instructions at http://en.opensuse.org/s2ram to test
++the system, but if it does not work "out of the box", you may need to boot it
++with "init=/bin/bash" and test s2ram in the minimal configuration.  In that
++case, you may be able to search for failing drivers by following the procedure
++analogous to the one described in section 1.  If you find some failing drivers,
++you will have to unload them every time before an STR transition (ie. before
++you run s2ram), and please report the problems with them.
+diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
+index d0e79d5..c53d263 100644
+--- a/Documentation/power/devices.txt
++++ b/Documentation/power/devices.txt
+@@ -502,52 +502,3 @@ If the CPU can have a "cpufreq" driver, there also may be opportunities
+ to shift to lower voltage settings and reduce the power cost of executing
+ a given number of instructions.  (Without voltage adjustment, it's rare
+ for cpufreq to save much power; the cost-per-instruction must go down.)
+-
+-
+-/sys/devices/.../power/state files
+-==================================
+-For now you can also test some of this functionality using sysfs.
+-
+-	DEPRECATED:  USE "power/state" ONLY FOR DRIVER TESTING, AND
+-	AVOID USING dev->power.power_state IN DRIVERS.
+-
+-	THESE WILL BE REMOVED.  IF THE "power/state" FILE GETS REPLACED,
+-	IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
+-
+-In each device's directory, there is a 'power' directory, which contains
+-at least a 'state' file.  The value of this field is effectively boolean,
+-PM_EVENT_ON or PM_EVENT_SUSPEND.
+-
+-   *	Reading from this file displays a value corresponding to
+-	the power.power_state.event field.  All nonzero values are
+-	displayed as "2", corresponding to a low power state; zero
+-	is displayed as "0", corresponding to normal operation.
+-
+-   *	Writing to this file initiates a transition using the
+-   	specified event code number; only '0', '2', and '3' are
+-	accepted (without a newline); '2' and '3' are both
+-	mapped to PM_EVENT_SUSPEND.
+-
+-On writes, the PM core relies on that recorded event code and the device/bus
+-capabilities to determine whether it uses a partial suspend() or resume()
+-sequence to change things so that the recorded event corresponds to the
+-numeric parameter.
+-
+-   -	If the bus requires the irqs-disabled suspend_late()/resume_early()
+-	phases, writes fail because those operations are not supported here.
+-
+-   -	If the recorded value is the expected value, nothing is done.
+-
+-   -	If the recorded value is nonzero, the device is partially resumed,
+-	using the bus.resume() and/or class.resume() methods.
+-
+-   -	If the target value is nonzero, the device is partially suspended,
+-	using the class.suspend() and/or bus.suspend() methods and the
+-	PM_EVENT_SUSPEND message.
+-
+-Drivers have no way to tell whether their suspend() and resume() calls
+-have come through the sysfs power/state file or as part of entering a
+-system sleep state, except that when accessed through sysfs the normal
+-parent/child sequencing rules are ignored.  Drivers (such as bus, bridge,
+-or hub drivers) which expose child devices may need to enforce those rules
+-on their own.
+diff --git a/Documentation/power/drivers-testing.txt b/Documentation/power/drivers-testing.txt
+index e4bdcae..7f7a737 100644
+--- a/Documentation/power/drivers-testing.txt
++++ b/Documentation/power/drivers-testing.txt
+@@ -6,9 +6,9 @@ Testing suspend and resume support in device drivers
+ Unfortunately, to effectively test the support for the system-wide suspend and
+ resume transitions in a driver, it is necessary to suspend and resume a fully
+ functional system with this driver loaded.  Moreover, that should be done
+-several times, preferably several times in a row, and separately for the suspend
+-to disk (STD) and the suspend to RAM (STR) transitions, because each of these
+-cases involves different ordering of operations and different interactions with
++several times, preferably several times in a row, and separately for hibernation
++(aka suspend to disk or STD) and suspend to RAM (STR), because each of these
++cases involves slightly different operations and different interactions with
+ the machine's BIOS.
+ 
+ Of course, for this purpose the test system has to be known to suspend and
+@@ -22,20 +22,24 @@ for more information about the debugging of suspend/resume functionality.
+ Once you have resolved the suspend/resume-related problems with your test system
+ without the new driver, you are ready to test it:
+ 
+-a) Build the driver as a module, load it and try the STD in the test mode (see:
+-Documents/power/basic-pm-debugging.txt, 1a)).
++a) Build the driver as a module, load it and try the test modes of hibernation
++   (see: Documents/power/basic-pm-debugging.txt, 1).
+ 
+-b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
+-and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
++b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
++   "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+ 
+-c) Compile the driver directly into the kernel and try the STD in the test mode.
++c) Compile the driver directly into the kernel and try the test modes of
++   hibernation.
+ 
+-d) Attempt to suspend to disk with the driver compiled directly into the kernel
+-in the "reboot", "shutdown" and "platform" modes.
++d) Attempt to hibernate with the driver compiled directly into the kernel
++   in the "reboot", "shutdown" and "platform" modes.
+ 
+-e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
+-Documents/power/basic-pm-debugging.txt, 2).  As far as the STR tests are
+-concerned, it should not matter whether or not the driver is built as a module.
++e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt,
++   2).  [As far as the STR tests are concerned, it should not matter whether or
++   not the driver is built as a module.]
++
++f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
++   (see: Documents/power/basic-pm-debugging.txt, 2).
+ 
+ Each of the above tests should be repeated several times and the STD tests
+ should be mixed with the STR tests.  If any of them fails, the driver cannot be
+diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
+index 9293e4b..ae1b7ec 100644
+--- a/Documentation/power/notifiers.txt
++++ b/Documentation/power/notifiers.txt
+@@ -28,6 +28,14 @@ PM_POST_HIBERNATION	The system memory state has been restored from a
+ 			hibernation.  Device drivers' .resume() callbacks have
+ 			been executed and tasks have been thawed.
+ 
++PM_RESTORE_PREPARE	The system is going to restore a hibernation image.
++			If all goes well the restored kernel will issue a
++			PM_POST_HIBERNATION notification.
++
++PM_POST_RESTORE		An error occurred during the hibernation restore.
++			Device drivers' .resume() callbacks have been executed
++			and tasks have been thawed.
++
+ PM_SUSPEND_PREPARE	The system is preparing for a suspend.
+ 
+ PM_POST_SUSPEND		The system has just resumed or an error occured during
+diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
+index e00c6cf..7b99636 100644
+--- a/Documentation/power/userland-swsusp.txt
++++ b/Documentation/power/userland-swsusp.txt
+@@ -14,7 +14,7 @@ are going to develop your own suspend/resume utilities.
+ 
+ The interface consists of a character device providing the open(),
+ release(), read(), and write() operations as well as several ioctl()
+-commands defined in kernel/power/power.h.  The major and minor
++commands defined in include/linux/suspend_ioctls.h .  The major and minor
+ numbers of the device are, respectively, 10 and 231, and they can
+ be read from /sys/class/misc/snapshot/dev.
+ 
+@@ -27,17 +27,17 @@ once at a time.
+ The ioctl() commands recognized by the device are:
+ 
+ SNAPSHOT_FREEZE - freeze user space processes (the current process is
+-	not frozen); this is required for SNAPSHOT_ATOMIC_SNAPSHOT
++	not frozen); this is required for SNAPSHOT_CREATE_IMAGE
+ 	and SNAPSHOT_ATOMIC_RESTORE to succeed
+ 
+ SNAPSHOT_UNFREEZE - thaw user space processes frozen by SNAPSHOT_FREEZE
+ 
+-SNAPSHOT_ATOMIC_SNAPSHOT - create a snapshot of the system memory; the
++SNAPSHOT_CREATE_IMAGE - create a snapshot of the system memory; the
+ 	last argument of ioctl() should be a pointer to an int variable,
+ 	the value of which will indicate whether the call returned after
+ 	creating the snapshot (1) or after restoring the system memory state
+ 	from it (0) (after resume the system finds itself finishing the
+-	SNAPSHOT_ATOMIC_SNAPSHOT ioctl() again); after the snapshot
++	SNAPSHOT_CREATE_IMAGE ioctl() again); after the snapshot
+ 	has been created the read() operation can be used to transfer
+ 	it out of the kernel
+ 
+@@ -49,39 +49,37 @@ SNAPSHOT_ATOMIC_RESTORE - restore the system memory state from the
+ 
+ SNAPSHOT_FREE - free memory allocated for the snapshot image
+ 
+-SNAPSHOT_SET_IMAGE_SIZE - set the preferred maximum size of the image
++SNAPSHOT_PREF_IMAGE_SIZE - set the preferred maximum size of the image
+ 	(the kernel will do its best to ensure the image size will not exceed
+ 	this number, but if it turns out to be impossible, the kernel will
+ 	create the smallest image possible)
+ 
+-SNAPSHOT_AVAIL_SWAP - return the amount of available swap in bytes (the last
+-	argument should be a pointer to an unsigned int variable that will
++SNAPSHOT_GET_IMAGE_SIZE - return the actual size of the hibernation image
++
++SNAPSHOT_AVAIL_SWAP_SIZE - return the amount of available swap in bytes (the
++	last argument should be a pointer to an unsigned int variable that will
+ 	contain the result if the call is successful).
+ 
+-SNAPSHOT_GET_SWAP_PAGE - allocate a swap page from the resume partition
++SNAPSHOT_ALLOC_SWAP_PAGE - allocate a swap page from the resume partition
+ 	(the last argument should be a pointer to a loff_t variable that
+ 	will contain the swap page offset if the call is successful)
+ 
+-SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
+-	SNAPSHOT_GET_SWAP_PAGE
+-
+-SNAPSHOT_SET_SWAP_FILE - set the resume partition (the last ioctl() argument
+-	should specify the device's major and minor numbers in the old
+-	two-byte format, as returned by the stat() function in the .st_rdev
+-	member of the stat structure)
++SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated by
++	SNAPSHOT_ALLOC_SWAP_PAGE
+ 
+ SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
+ 	units) from the beginning of the partition at which the swap header is
+ 	located (the last ioctl() argument should point to a struct
+-	resume_swap_area, as defined in kernel/power/power.h, containing the
+-	resume device specification, as for the SNAPSHOT_SET_SWAP_FILE ioctl(),
+-	and the offset); for swap partitions the offset is always 0, but it is
+-	different to zero for swap files (please see
+-	Documentation/swsusp-and-swap-files.txt for details).
+-	The SNAPSHOT_SET_SWAP_AREA ioctl() is considered as a replacement for
+-	SNAPSHOT_SET_SWAP_FILE which is regarded as obsolete.   It is
+-	recommended to always use this call, because the code to set the resume
+-	partition may be removed from future kernels
++	resume_swap_area, as defined in kernel/power/suspend_ioctls.h,
++	containing the resume device specification and the offset); for swap
++	partitions the offset is always 0, but it is different from zero for
++	swap files (see Documentation/swsusp-and-swap-files.txt for details).
++
++SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
++	depending on the argument value (enable, if the argument is nonzero)
++
++SNAPSHOT_POWER_OFF - make the kernel transition the system to the hibernation
++	state (eg. ACPI S4) using the platform (eg. ACPI) driver
+ 
+ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
+ 	immediately enter the suspend-to-RAM state, so this call must always
+@@ -93,24 +91,6 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
+ 	to resume the system from RAM if there's enough battery power or restore
+ 	its state on the basis of the saved suspend image otherwise)
+ 
+-SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
+-	hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
+-	swsusp knows these as the "platform method") which are needed on many
+-	machines to (among others) speed up the resume by letting the BIOS skip
+-	some steps or to let the system recognise the correct state of the
+-	hardware after the resume (in particular on many machines this ensures
+-	that unplugged AC adapters get correctly detected and that kacpid does
+-	not run wild after the resume).  The last ioctl() argument can take one
+-	of the three values, defined in kernel/power/power.h:
+-	PMOPS_PREPARE - make the kernel carry out the
+-		hibernation_ops->prepare() operation
+-	PMOPS_ENTER - make the kernel power off the system by calling
+-		hibernation_ops->enter()
+-	PMOPS_FINISH - make the kernel carry out the
+-		hibernation_ops->finish() operation
+-	Note that the actual constants are misnamed because they surface
+-	internal kernel implementation details that have changed.
+-
+ The device's read() operation can be used to transfer the snapshot image from
+ the kernel.  It has the following limitations:
+ - you cannot read() more than one virtual memory page at a time
+@@ -122,7 +102,7 @@ The device's write() operation is used for uploading the system memory snapshot
+ into the kernel.  It has the same limitations as the read() operation.
+ 
+ The release() operation frees all memory allocated for the snapshot image
+-and all swap pages allocated with SNAPSHOT_GET_SWAP_PAGE (if any).
++and all swap pages allocated with SNAPSHOT_ALLOC_SWAP_PAGE (if any).
+ Thus it is not necessary to use either SNAPSHOT_FREE or
+ SNAPSHOT_FREE_SWAP_PAGES before closing the device (in fact it will also
+ unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
+@@ -133,16 +113,12 @@ snapshot image from/to the kernel will use a swap parition, called the resume
+ partition, or a swap file as storage space (if a swap file is used, the resume
+ partition is the partition that holds this file).  However, this is not really
+ required, as they can use, for example, a special (blank) suspend partition or
+-a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
++a file on a partition that is unmounted before SNAPSHOT_CREATE_IMAGE and
+ mounted afterwards.
+ 
+-These utilities SHOULD NOT make any assumptions regarding the ordering of
+-data within the snapshot image, except for the image header that MAY be
+-assumed to start with an swsusp_info structure, as specified in
+-kernel/power/power.h.  This structure MAY be used by the userland utilities
+-to obtain some information about the snapshot image, such as the size
+-of the snapshot image, including the metadata and the header itself,
+-contained in the .size member of swsusp_info.
++These utilities MUST NOT make any assumptions regarding the ordering of
++data within the snapshot image.  The contents of the image are entirely owned
++by the kernel and its structure may be changed in future kernel releases.
+ 
+ The snapshot image MUST be written to the kernel unaltered (ie. all of the image
+ data, metadata and header MUST be written in _exactly_ the same amount, form
+@@ -159,7 +135,7 @@ means, such as checksums, to ensure the integrity of the snapshot image.
+ The suspending and resuming utilities MUST lock themselves in memory,
+ preferrably using mlockall(), before calling SNAPSHOT_FREEZE.
+ 
+-The suspending utility MUST check the value stored by SNAPSHOT_ATOMIC_SNAPSHOT
++The suspending utility MUST check the value stored by SNAPSHOT_CREATE_IMAGE
+ in the memory location pointed to by the last argument of ioctl() and proceed
+ in accordance with it:
+ 1. 	If the value is 1 (ie. the system memory snapshot has just been
+@@ -173,7 +149,7 @@ in accordance with it:
+ 		image has been saved.
+ 	(b)	The suspending utility SHOULD NOT attempt to perform any
+ 		file system operations (including reads) on the file systems
+-		that were mounted before SNAPSHOT_ATOMIC_SNAPSHOT has been
++		that were mounted before SNAPSHOT_CREATE_IMAGE has been
+ 		called.  However, it MAY mount a file system that was not
+ 		mounted at that time and perform some operations on it (eg.
+ 		use it for saving the image).
+diff --git a/Documentation/power_supply_class.txt b/Documentation/power_supply_class.txt
+index 9758cf4..a8686e5 100644
+--- a/Documentation/power_supply_class.txt
++++ b/Documentation/power_supply_class.txt
+@@ -87,6 +87,10 @@ batteries use voltage for very approximated calculation of capacity.
+ Battery driver also can use this attribute just to inform userspace
+ about maximal and minimal voltage thresholds of a given battery.
+ 
++VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that
++these ones should be used if hardware could only guess (measure and
++retain) the thresholds of a given power supply.
++
+ CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
+ battery considered full/empty.
+ 
+@@ -100,8 +104,6 @@ age)". I.e. these attributes represents real thresholds, not design values.
+ ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
+ 
+ CAPACITY - capacity in percents.
+-CAPACITY_LEVEL - capacity level. This corresponds to
+-POWER_SUPPLY_CAPACITY_LEVEL_*.
+ 
+ TEMP - temperature of the power supply.
+ TEMP_AMBIENT - ambient temperature.
 diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
 index 94a3c57..3be84aa 100644
 --- a/Documentation/powerpc/00-INDEX
@@ -9111,6 +10217,612 @@
  
   Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
  
+diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt
+new file mode 100644
+index 0000000..ad995bf
+--- /dev/null
++++ b/Documentation/usb/gadget_printer.txt
+@@ -0,0 +1,510 @@
++
++                       Linux USB Printer Gadget Driver
++                                 06/04/2007
++
++              Copyright (C) 2007 Craig W. Nadler <craig at nadler.us>
++
++
++
++GENERAL
++=======
++
++This driver may be used if you are writing printer firmware using Linux as
++the embedded OS. This driver has nothing to do with using a printer with
++your Linux host system.
++
++You will need a USB device controller and a Linux driver for it that accepts
++a gadget / "device class" driver using the Linux USB Gadget API. After the
++USB device controller driver is loaded then load the printer gadget driver.
++This will present a printer interface to the USB Host that your USB Device
++port is connected to.
++
++This driver is structured for printer firmware that runs in user mode. The
++user mode printer firmware will read and write data from the kernel mode
++printer gadget driver using a device file. The printer returns a printer status
++byte when the USB HOST sends a device request to get the printer status.  The
++user space firmware can read or write this status byte using a device file
++/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
++
++
++
++
++HOWTO USE THIS DRIVER
++=====================
++
++To load the USB device controller driver and the printer gadget driver. The
++following example uses the Netchip 2280 USB device controller driver:
++
++modprobe net2280
++modprobe g_printer
++
++
++The follow command line parameter can be used when loading the printer gadget
++(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
++
++idVendor - This is the Vendor ID used in the device descriptor. The default is
++	the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
++	BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
++	already have a Vendor ID please see www.usb.org for details on how to
++	get one.
++
++idProduct - This is the Product ID used in the device descriptor. The default
++	is 0xa4a8, you should change this to an ID that's not used by any of
++	your other USB products if you have any. It would be a good idea to
++	start numbering your products starting with say 0x0001.
++
++bcdDevice - This is the version number of your product. It would be a good idea
++	to put your firmware version here.
++
++iManufacturer - A string containing the name of the Vendor.
++
++iProduct - A string containing the Product Name.
++
++iSerialNum - A string containing the Serial Number. This should be changed for
++	each unit of your product.
++
++iPNPstring -  The PNP ID string used for this printer. You will want to set
++	either on the command line or hard code the PNP ID string used for
++	your printer product.
++
++qlen - The number of 8k buffers to use per endpoint. The default is 10, you
++	should tune this for your product. You may also want to tune the
++	size of each buffer for your product.
++
++
++
++
++USING THE EXAMPLE CODE
++======================
++
++This example code talks to stdout, instead of a print engine.
++
++To compile the test code below:
++
++1) save it to a file called prn_example.c
++2) compile the code with the follow command:
++	 gcc prn_example.c -o prn_example
++
++
++
++To read printer data from the host to stdout:
++
++	# prn_example -read_data
++
++
++To write printer data from a file (data_file) to the host:
++
++	# cat data_file | prn_example -write_data
++
++
++To get the current printer status for the gadget driver:
++
++	# prn_example -get_status
++
++	Printer status is:
++	     Printer is NOT Selected
++	     Paper is Out
++	     Printer OK
++
++
++To set printer to Selected/On-line:
++
++	# prn_example -selected
++
++
++To set printer to Not Selected/Off-line:
++
++	# prn_example -not_selected
++
++
++To set paper status to paper out:
++
++	# prn_example -paper_out
++
++
++To set paper status to paper loaded:
++
++	# prn_example -paper_loaded
++
++
++To set error status to printer OK:
++
++	# prn_example -no_error
++
++
++To set error status to ERROR:
++
++	# prn_example -error
++
++
++
++
++EXAMPLE CODE
++============
++
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <linux/poll.h>
++#include <sys/ioctl.h>
++#include <linux/usb/g_printer.h>
++
++#define PRINTER_FILE			"/dev/g_printer"
++#define BUF_SIZE			512
++
++
++/*
++ * 'usage()' - Show program usage.
++ */
++
++static void
++usage(const char *option)		/* I - Option string or NULL */
++{
++	if (option) {
++		fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
++				option);
++	}
++
++	fputs("\n", stderr);
++	fputs("Usage: prn_example -[options]\n", stderr);
++	fputs("Options:\n", stderr);
++	fputs("\n", stderr);
++	fputs("-get_status    Get the current printer status.\n", stderr);
++	fputs("-selected      Set the selected status to selected.\n", stderr);
++	fputs("-not_selected  Set the selected status to NOT selected.\n",
++			stderr);
++	fputs("-error         Set the error status to error.\n", stderr);
++	fputs("-no_error      Set the error status to NO error.\n", stderr);
++	fputs("-paper_out     Set the paper status to paper out.\n", stderr);
++	fputs("-paper_loaded  Set the paper status to paper loaded.\n",
++			stderr);
++	fputs("-read_data     Read printer data from driver.\n", stderr);
++	fputs("-write_data    Write printer sata to driver.\n", stderr);
++	fputs("-NB_read_data  (Non-Blocking) Read printer data from driver.\n",
++			stderr);
++	fputs("\n\n", stderr);
++
++	exit(1);
++}
++
++
++static int
++read_printer_data()
++{
++	struct pollfd	fd[1];
++
++	/* Open device file for printer gadget. */
++	fd[0].fd = open(PRINTER_FILE, O_RDWR);
++	if (fd[0].fd < 0) {
++		printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
++		close(fd[0].fd);
++		return(-1);
++	}
++
++	fd[0].events = POLLIN | POLLRDNORM;
++
++	while (1) {
++		static char buf[BUF_SIZE];
++		int bytes_read;
++		int retval;
++
++		/* Wait for up to 1 second for data. */
++		retval = poll(fd, 1, 1000);
++
++		if (retval && (fd[0].revents & POLLRDNORM)) {
++
++			/* Read data from printer gadget driver. */
++			bytes_read = read(fd[0].fd, buf, BUF_SIZE);
++
++			if (bytes_read < 0) {
++				printf("Error %d reading from %s\n",
++						fd[0].fd, PRINTER_FILE);
++				close(fd[0].fd);
++				return(-1);
++			} else if (bytes_read > 0) {
++				/* Write data to standard OUTPUT (stdout). */
++				fwrite(buf, 1, bytes_read, stdout);
++				fflush(stdout);
++			}
++
++		}
++
++	}
++
++	/* Close the device file. */
++	close(fd[0].fd);
++
++	return 0;
++}
++
++
++static int
++write_printer_data()
++{
++	struct pollfd	fd[1];
++
++	/* Open device file for printer gadget. */
++	fd[0].fd = open (PRINTER_FILE, O_RDWR);
++	if (fd[0].fd < 0) {
++		printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
++		close(fd[0].fd);
++		return(-1);
++	}
++
++	fd[0].events = POLLOUT | POLLWRNORM;
++
++	while (1) {
++		int retval;
++		static char buf[BUF_SIZE];
++		/* Read data from standard INPUT (stdin). */
++		int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
++
++		if (!bytes_read) {
++			break;
++		}
++
++		while (bytes_read) {
++
++			/* Wait for up to 1 second to sent data. */
++			retval = poll(fd, 1, 1000);
++
++			/* Write data to printer gadget driver. */
++			if (retval && (fd[0].revents & POLLWRNORM)) {
++				retval = write(fd[0].fd, buf, bytes_read);
++				if (retval < 0) {
++					printf("Error %d writing to %s\n",
++							fd[0].fd,
++							PRINTER_FILE);
++					close(fd[0].fd);
++					return(-1);
++				} else {
++					bytes_read -= retval;
++				}
++
++			}
++
++		}
++
++	}
++
++	/* Wait until the data has been sent. */
++	fsync(fd[0].fd);
++
++	/* Close the device file. */
++	close(fd[0].fd);
++
++	return 0;
++}
++
++
++static int
++read_NB_printer_data()
++{
++	int		fd;
++	static char	buf[BUF_SIZE];
++	int		bytes_read;
++
++	/* Open device file for printer gadget. */
++	fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
++	if (fd < 0) {
++		printf("Error %d opening %s\n", fd, PRINTER_FILE);
++		close(fd);
++		return(-1);
++	}
++
++	while (1) {
++		/* Read data from printer gadget driver. */
++		bytes_read = read(fd, buf, BUF_SIZE);
++		if (bytes_read <= 0) {
++			break;
++		}
++
++		/* Write data to standard OUTPUT (stdout). */
++		fwrite(buf, 1, bytes_read, stdout);
++		fflush(stdout);
++	}
++
++	/* Close the device file. */
++	close(fd);
++
++	return 0;
++}
++
++
++static int
++get_printer_status()
++{
++	int	retval;
++	int	fd;
++
++	/* Open device file for printer gadget. */
++	fd = open(PRINTER_FILE, O_RDWR);
++	if (fd < 0) {
++		printf("Error %d opening %s\n", fd, PRINTER_FILE);
++		close(fd);
++		return(-1);
++	}
++
++	/* Make the IOCTL call. */
++	retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
++	if (retval < 0) {
++		fprintf(stderr, "ERROR: Failed to set printer status\n");
++		return(-1);
++	}
++
++	/* Close the device file. */
++	close(fd);
++
++	return(retval);
++}
++
++
++static int
++set_printer_status(unsigned char buf, int clear_printer_status_bit)
++{
++	int	retval;
++	int	fd;
++
++	retval = get_printer_status();
++	if (retval < 0) {
++		fprintf(stderr, "ERROR: Failed to get printer status\n");
++		return(-1);
++	}
++
++	/* Open device file for printer gadget. */
++	fd = open(PRINTER_FILE, O_RDWR);
++
++	if (fd < 0) {
++		printf("Error %d opening %s\n", fd, PRINTER_FILE);
++		close(fd);
++		return(-1);
++	}
++
++	if (clear_printer_status_bit) {
++		retval &= ~buf;
++	} else {
++		retval |= buf;
++	}
++
++	/* Make the IOCTL call. */
++	if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
++		fprintf(stderr, "ERROR: Failed to set printer status\n");
++		return(-1);
++	}
++
++	/* Close the device file. */
++	close(fd);
++
++	return 0;
++}
++
++
++static int
++display_printer_status()
++{
++	char	printer_status;
++
++	printer_status = get_printer_status();
++	if (printer_status < 0) {
++		fprintf(stderr, "ERROR: Failed to get printer status\n");
++		return(-1);
++	}
++
++	printf("Printer status is:\n");
++	if (printer_status & PRINTER_SELECTED) {
++		printf("     Printer is Selected\n");
++	} else {
++		printf("     Printer is NOT Selected\n");
++	}
++	if (printer_status & PRINTER_PAPER_EMPTY) {
++		printf("     Paper is Out\n");
++	} else {
++		printf("     Paper is Loaded\n");
++	}
++	if (printer_status & PRINTER_NOT_ERROR) {
++		printf("     Printer OK\n");
++	} else {
++		printf("     Printer ERROR\n");
++	}
++
++	return(0);
++}
++
++
++int
++main(int  argc, char *argv[])
++{
++	int	i;		/* Looping var */
++	int	retval = 0;
++
++	/* No Args */
++	if (argc == 1) {
++		usage(0);
++		exit(0);
++	}
++
++	for (i = 1; i < argc && !retval; i ++) {
++
++		if (argv[i][0] != '-') {
++			continue;
++		}
++
++		if (!strcmp(argv[i], "-get_status")) {
++			if (display_printer_status()) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-paper_loaded")) {
++			if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-paper_out")) {
++			if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-selected")) {
++			if (set_printer_status(PRINTER_SELECTED, 0)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-not_selected")) {
++			if (set_printer_status(PRINTER_SELECTED, 1)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-error")) {
++			if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-no_error")) {
++			if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-read_data")) {
++			if (read_printer_data()) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-write_data")) {
++			if (write_printer_data()) {
++				retval = 1;
++			}
++
++		} else if (!strcmp(argv[i], "-NB_read_data")) {
++			if (read_NB_printer_data()) {
++				retval = 1;
++			}
++
++		} else {
++			usage(argv[i]);
++			retval = 1;
++		}
++	}
++
++	exit(retval);
++}
+diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt
+new file mode 100644
+index 0000000..e5f0480
+--- /dev/null
++++ b/Documentation/usb/iuu_phoenix.txt
+@@ -0,0 +1,84 @@
++Infinity Usb Unlimited Readme
++-----------------------------
++
++Hi all,
++
++
++This module provide a serial interface to use your
++IUU unit in phoenix mode. Loading this module will
++bring a ttyUSB[0-x] interface. This driver must be
++used by your favorite application to pilot the IUU
++
++This driver is still in beta stage, so bugs can
++occur and your system may freeze. As far I now,
++I never had any problem with it, but I'm not a real
++guru, so don't blame me if your system is unstable
++
++You can plug more than one IUU. Every unit will
++have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
++
++
++
++How to tune the reader speed ?
++
++ A few parameters can be used at load time
++ To use parameters, just unload the module if it is
++ already loaded and use modprobe iuu_phoenix param=value.
++ In case of prebuilt module, use the command
++ insmod iuu_phoenix param=value.
++
++ Example:
++
++ modprobe iuu_phoenix clockmode=3
++
++ The parameters are:
++
++ parm:           clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int)
++ parm:           boost:overclock boost percent 100 to 500 (int)
++ parm:           cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
++ parm:           xmas:xmas color enabled or not (bool)
++ parm:           debug:Debug enabled or not (bool)
++
++-  clockmode will provide 3 different base settings commonly adopted by
++   different software:
++ 	1. 3Mhz579
++	2. 3Mhz680
++	3. 6Mhz
++
++-  boost provide a way to overclock the reader ( my favorite :-)  )
++   For example to have best performance than a simple clockmode=3, try this:
++
++      modprobe boost=195
++
++   This will put the reader in a base of 3Mhz579 but boosted a 195 % !
++   the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
++   the speed to a score 10 to 20% better than the simple clockmode=3 !!!
++
++
++-  cdmode permit to setup the signal used to inform the userland ( ioctl answer )
++   if the card is present or not. Eight signals are possible.
++
++-  xmas is completely useless except for your eyes. This is one of my friend who was
++   so sad to have a nice device like the iuu without seeing all color range available.
++   So I have added this option to permit him to see a lot of color ( each activity change the color
++   and the frequency randomly )
++
++-  debug will produce a lot of debugging messages...
++
++
++ Last notes:
++
++ Don't worry about the serial settings, the serial emulation
++ is an abstraction, so use any speed or parity setting will
++ work. ( This will not change anything ).Later I will perhaps
++ use this settings to deduce de boost but is that feature
++ really necessary ?
++ The autodetect feature used is the serial CD. If that doesn't
++ work for your software, disable detection mechanism in it.
++
++
++ Have fun !
++
++ Alain Degreffe
++
++ eczema(at)ecze.com
 diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
 index 00cb646..0924e6e 100644
 --- a/Documentation/video4linux/CARDLIST.cx23885
@@ -12120,7 +13832,7 @@
 +参考Satyam Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
 +H. Peter Anvin,Philipp Hahn和Stefan Richter的意见改善了本档。
 diff --git a/MAINTAINERS b/MAINTAINERS
-index 2340cfb..093cf04 100644
+index 2340cfb..58b1603 100644
 --- a/MAINTAINERS
 +++ b/MAINTAINERS
 @@ -646,6 +646,17 @@ M:	ecashin at coraid.com
@@ -12262,6 +13974,15 @@
  JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
  P:	David Woodhouse
  M:	dwmw2 at infradead.org
+@@ -2214,7 +2247,7 @@ P:	J. Bruce Fields
+ M:	bfields at fieldses.org
+ P:	Neil Brown
+ M:	neilb at suse.de
+-L:	nfs at lists.sourceforge.net
++L:	linux-nfs at vger.kernel.org
+ W:	http://nfs.sourceforge.net/
+ S:	Supported
+ 
 @@ -2475,6 +2508,16 @@ W:	http://linuxwireless.org/
  T:	git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.git
  S:	Maintained
@@ -12279,7 +14000,15 @@
  MACVLAN DRIVER
  P:	Patrick McHardy
  M:	kaber at trash.net
-@@ -3176,6 +3219,12 @@ M:	mporter at kernel.crashing.org
+@@ -3010,7 +3053,6 @@ M:	cbou at mail.ru
+ P:	David Woodhouse
+ M:	dwmw2 at infradead.org
+ L:	linux-kernel at vger.kernel.org
+-L:	kernel-discuss at handhelds.org
+ T:	git git.infradead.org/battery-2.6.git
+ S:	Maintained
+ 
+@@ -3176,6 +3218,12 @@ M:	mporter at kernel.crashing.org
  L:	linux-kernel at vger.kernel.org
  S:	Maintained
  
@@ -12292,7 +14021,7 @@
  READ-COPY UPDATE (RCU)
  P:	Dipankar Sarma
  M:	dipankar at in.ibm.com
-@@ -3260,8 +3309,10 @@ W:	http://www.ibm.com/developerworks/linux/linux390/
+@@ -3260,8 +3308,10 @@ W:	http://www.ibm.com/developerworks/linux/linux390/
  S:	Supported
  
  S390 ZFCP DRIVER
@@ -12305,7 +14034,7 @@
  M:	linux390 at de.ibm.com
  L:	linux-s390 at vger.kernel.org
  W:	http://www.ibm.com/developerworks/linux/linux390/
-@@ -3520,6 +3571,9 @@ S:	Maintained
+@@ -3520,6 +3570,9 @@ S:	Maintained
  SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
  P:	Liam Girdwood
  M:	liam.girdwood at wolfsonmicro.com
@@ -12315,6 +14044,35 @@
  L:	alsa-devel at alsa-project.org (subscribers-only)
  S:	Supported
  
+@@ -4031,6 +4084,12 @@ L:	video4linux-list at redhat.com
+ W:	http://www.linux-projects.org
+ S:	Maintained
+ 
++USB WIRELESS RNDIS DRIVER (rndis_wlan)
++P:	Jussi Kivilinna
++M:	jussi.kivilinna at mbnet.fi
++L:	linux-wireless at vger.kernel.org
++S:	Maintained
++
+ USB ZC0301 DRIVER
+ P:	Luca Risolia
+ M:	luca.risolia at studio.unibo.it
+diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
+index 4c002ba..c613d5f 100644
+--- a/arch/alpha/Kconfig
++++ b/arch/alpha/Kconfig
+@@ -318,11 +318,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config PCI_DOMAINS
+ 	bool
+ 	default y
 diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
 index 55c05b5..f13249b 100644
 --- a/arch/alpha/kernel/vmlinux.lds.S
@@ -12359,7 +14117,7 @@
  	/* Slow path */
  	spin_lock(lock);
 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
-index a04f507..77201d3 100644
+index a04f507..4b1a8e3 100644
 --- a/arch/arm/Kconfig
 +++ b/arch/arm/Kconfig
 @@ -91,6 +91,11 @@ config GENERIC_IRQ_PROBE
@@ -12462,7 +14220,19 @@
  # Definitions to make life easier
  config ARCH_ACORN
  	bool
-@@ -657,6 +690,7 @@ config HZ
+@@ -544,11 +577,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config PCI_SYSCALL
+ 	def_bool PCI
+ 
+@@ -657,6 +685,7 @@ config HZ
  	default 128 if ARCH_L7200
  	default 200 if ARCH_EBSA110 || ARCH_S3C2410
  	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
@@ -12470,7 +14240,7 @@
  	default 100
  
  config AEABI
-@@ -716,7 +750,7 @@ config LEDS
+@@ -716,7 +745,7 @@ config LEDS
  		   ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
  		   ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
  		   ARCH_AT91 || MACH_TRIZEPS4 || ARCH_DAVINCI || \
@@ -12479,7 +14249,7 @@
  	help
  	  If you say Y here, the LEDs on your machine will be used
  	  to provide useful information about your current system status.
-@@ -867,7 +901,7 @@ config KEXEC
+@@ -867,7 +896,7 @@ config KEXEC
  
  endmenu
  
@@ -12488,7 +14258,7 @@
  
  menu "CPU Frequency scaling"
  
-@@ -903,6 +937,12 @@ config CPU_FREQ_IMX
+@@ -903,6 +932,12 @@ config CPU_FREQ_IMX
  
  	  If in doubt, say N.
  
@@ -12501,7 +14271,7 @@
  endmenu
  
  endif
-@@ -951,7 +991,7 @@ config FPE_FASTFPE
+@@ -951,7 +986,7 @@ config FPE_FASTFPE
  
  config VFP
  	bool "VFP-format floating point maths"
@@ -12510,7 +14280,7 @@
  	help
  	  Say Y to include VFP support code in the kernel. This is needed
  	  if your hardware includes a VFP unit.
-@@ -961,6 +1001,18 @@ config VFP
+@@ -961,6 +996,18 @@ config VFP
  
  	  Say N if your target does not have VFP hardware.
  
@@ -12529,6 +14299,16 @@
  endmenu
  
  menu "Userspace binary formats"
+@@ -983,6 +1030,9 @@ menu "Power management options"
+ 
+ source "kernel/power/Kconfig"
+ 
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++
+ endmenu
+ 
+ source "net/Kconfig"
 diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
 index 18101f5..192ee01 100644
 --- a/arch/arm/Kconfig.debug
@@ -30699,9 +32479,18 @@
 +void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
 +#endif
 diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
-index 98cb614..4b120cc 100644
+index 98cb614..a67defd 100644
 --- a/arch/arm/mach-at91/pm.c
 +++ b/arch/arm/mach-at91/pm.c
+@@ -52,7 +52,7 @@ static suspend_state_t target_state;
+ /*
+  * Called after processes are frozen, but before we shutdown devices.
+  */
+-static int at91_pm_set_target(suspend_state_t state)
++static int at91_pm_begin(suspend_state_t state)
+ {
+ 	target_state = state;
+ 	return 0;
 @@ -80,6 +80,11 @@ static int at91_pm_verify_clocks(void)
  			pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
  			return 0;
@@ -30714,6 +32503,30 @@
  	}
  
  #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+@@ -197,11 +202,20 @@ error:
+ 	return 0;
+ }
+ 
++/*
++ * Called right prior to thawing processes.
++ */
++static void at91_pm_end(void)
++{
++	target_state = PM_SUSPEND_ON;
++}
++
+ 
+ static struct platform_suspend_ops at91_pm_ops ={
+-	.valid		= at91_pm_valid_state,
+-	.set_target	= at91_pm_set_target,
+-	.enter		= at91_pm_enter,
++	.valid	= at91_pm_valid_state,
++	.begin	= at91_pm_begin,
++	.enter	= at91_pm_enter,
++	.end	= at91_pm_end,
+ };
+ 
+ static int __init at91_pm_init(void)
 diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
 index f428af7..e5dc33f 100644
 --- a/arch/arm/mach-clps711x/time.c
@@ -43038,10 +44851,28 @@
  #else
  #define pxa_timer_suspend NULL
 diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
-index 240fd04..1919756 100644
+index 240fd04..1a9c844 100644
 --- a/arch/arm/mach-pxa/tosa.c
 +++ b/arch/arm/mach-pxa/tosa.c
-@@ -184,16 +184,13 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
+@@ -157,15 +157,10 @@ static void tosa_udc_command(int cmd)
+ 	}
+ }
+ 
+-static int tosa_udc_is_connected(void)
+-{
+-	return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
+-}
+-
+-
+ static struct pxa2xx_udc_mach_info udc_info __initdata = {
+ 	.udc_command		= tosa_udc_command,
+-	.udc_is_connected	= tosa_udc_is_connected,
++	.gpio_vbus		= TOSA_GPIO_USB_IN,
++	.gpio_vbus_inverted	= 1,
+ };
+ 
+ /*
+@@ -184,16 +179,13 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
  
  	tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
  
@@ -55580,7 +57411,7 @@
 +
 +}
 diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
-index 25232ba..fc7ca86 100644
+index 25232ba..4802eb7 100644
 --- a/arch/blackfin/Kconfig
 +++ b/arch/blackfin/Kconfig
 @@ -85,11 +85,26 @@ config BF522
@@ -55812,7 +57643,18 @@
  	default n
  
  config C_B0PEN
-@@ -949,8 +918,10 @@ endchoice
+@@ -929,6 +898,10 @@ endmenu
+ menu "Power management options"
+ source "kernel/power/Kconfig"
+ 
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on !SMP
++
+ choice
+ 	prompt "Select PM Wakeup Event Source"
+ 	default PM_WAKEUP_GPIO_BY_SIC_IWR
+@@ -949,8 +922,10 @@ endchoice
  config PM_WAKEUP_SIC_IWR
  	hex "Wakeup Events (SIC_IWR)"
  	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
@@ -64072,6 +65914,34 @@
  		*(.exitcall.exit)
          }
  
+diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
+index 43153e7..e3f965c 100644
+--- a/arch/frv/Kconfig
++++ b/arch/frv/Kconfig
+@@ -322,11 +322,6 @@ config PCI
+ 	  onboard. If you have one of these boards and you wish to use the PCI
+ 	  facilities, say Y here.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config RESERVE_DMA_COHERENT
+ 	bool "Reserve DMA coherent memory"
+ 	depends on PCI && !MMU
+@@ -357,6 +352,11 @@ source "drivers/pcmcia/Kconfig"
+ #	  should probably wait a while.
+ 
+ menu "Power management options"
++
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on !SMP
++
+ source kernel/power/Kconfig
+ endmenu
+ 
 diff --git a/arch/frv/boot/Makefile b/arch/frv/boot/Makefile
 index dc6f038..6ae3254 100644
 --- a/arch/frv/boot/Makefile
@@ -64482,7 +66352,7 @@
  
  	/*
 diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
-index ab9a264..f7237c5 100644
+index ab9a264..49326e9 100644
 --- a/arch/m32r/Kconfig
 +++ b/arch/m32r/Kconfig
 @@ -235,6 +235,11 @@ config IRAM_SIZE
@@ -64497,6 +66367,18 @@
  config RWSEM_GENERIC_SPINLOCK
  	bool
  	depends on M32R
+@@ -354,11 +359,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ choice
+ 	prompt "PCI access mode"
+ 	depends on PCI
 diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
 index 942a8c7..41b0785 100644
 --- a/arch/m32r/kernel/vmlinux.lds.S
@@ -64536,6 +66418,22 @@
  	*(.exitcall.exit)
  	}
  
+diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
+index 01dee84..24e6bc0 100644
+--- a/arch/m68k/Kconfig
++++ b/arch/m68k/Kconfig
+@@ -145,11 +145,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config MAC
+ 	bool "Macintosh support"
+ 	depends on !MMU_SUN3
 diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
 index 59fe285..7537cc5 100644
 --- a/arch/m68k/kernel/vmlinux-std.lds
@@ -64592,6 +66490,157 @@
  	*(.exitcall.exit)
  	}
  
+diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
+index f4b582c..bd92137 100644
+--- a/arch/m68knommu/Kconfig
++++ b/arch/m68knommu/Kconfig
+@@ -53,6 +53,10 @@ config GENERIC_CALIBRATE_DELAY
+ 	bool
+ 	default y
+ 
++config GENERIC_TIME
++	bool
++	default y
++
+ config TIME_LOW_RES
+ 	bool
+ 	default y
+diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
+index 30aa255..e0b5f62 100644
+--- a/arch/m68knommu/Makefile
++++ b/arch/m68knommu/Makefile
+@@ -61,17 +61,17 @@ MODEL := $(model-y)
+ # for the selected cpu. ONLY need to define this for the non-base member
+ # of the family.
+ #
+-cpuclass-$(CONFIG_M5206)	:= 5307
+-cpuclass-$(CONFIG_M5206e)	:= 5307
+-cpuclass-$(CONFIG_M520x)	:= 5307
+-cpuclass-$(CONFIG_M523x)	:= 5307
+-cpuclass-$(CONFIG_M5249)	:= 5307
+-cpuclass-$(CONFIG_M527x)	:= 5307
+-cpuclass-$(CONFIG_M5272)	:= 5307
+-cpuclass-$(CONFIG_M528x)	:= 5307
+-cpuclass-$(CONFIG_M5307)	:= 5307
+-cpuclass-$(CONFIG_M532x)	:= 5307
+-cpuclass-$(CONFIG_M5407)	:= 5307
++cpuclass-$(CONFIG_M5206)	:= coldfire
++cpuclass-$(CONFIG_M5206e)	:= coldfire
++cpuclass-$(CONFIG_M520x)	:= coldfire
++cpuclass-$(CONFIG_M523x)	:= coldfire
++cpuclass-$(CONFIG_M5249)	:= coldfire
++cpuclass-$(CONFIG_M527x)	:= coldfire
++cpuclass-$(CONFIG_M5272)	:= coldfire
++cpuclass-$(CONFIG_M528x)	:= coldfire
++cpuclass-$(CONFIG_M5307)	:= coldfire
++cpuclass-$(CONFIG_M532x)	:= coldfire
++cpuclass-$(CONFIG_M5407)	:= coldfire
+ cpuclass-$(CONFIG_M68328)	:= 68328
+ cpuclass-$(CONFIG_M68EZ328)	:= 68328
+ cpuclass-$(CONFIG_M68VZ328)	:= 68328
+diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
+index 77e5375..89cdbca 100644
+--- a/arch/m68knommu/kernel/time.c
++++ b/arch/m68knommu/kernel/time.c
+@@ -22,7 +22,6 @@
+ #include <linux/timex.h>
+ 
+ #include <asm/machdep.h>
+-#include <asm/io.h>
+ #include <asm/irq_regs.h>
+ 
+ #define	TICK_SIZE (tick_nsec / 1000)
+@@ -66,29 +65,6 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy)
+ 	  else
+ 	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ 	}
+-#ifdef CONFIG_HEARTBEAT
+-	/* use power LED as a heartbeat instead -- much more useful
+-	   for debugging -- based on the version for PReP by Cort */
+-	/* acts like an actual heart beat -- ie thump-thump-pause... */
+-	if (mach_heartbeat) {
+-	    static unsigned cnt = 0, period = 0, dist = 0;
+-
+-	    if (cnt == 0 || cnt == dist)
+-		mach_heartbeat( 1 );
+-	    else if (cnt == 7 || cnt == dist+7)
+-		mach_heartbeat( 0 );
+-
+-	    if (++cnt > period) {
+-		cnt = 0;
+-		/* The hyperbolic function below modifies the heartbeat period
+-		 * length in dependency of the current (5min) load. It goes
+-		 * through the points f(0)=126, f(1)=86, f(5)=51,
+-		 * f(inf)->30. */
+-		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+-		dist = period / 4;
+-	    }
+-	}
+-#endif /* CONFIG_HEARTBEAT */
+ 
+ 	write_sequnlock(&xtime_lock);
+ 	return(IRQ_HANDLED);
+@@ -112,60 +88,3 @@ void time_init(void)
+ 	hw_timer_init();
+ }
+ 
+-/*
+- * This version of gettimeofday has near microsecond resolution.
+- */
+-void do_gettimeofday(struct timeval *tv)
+-{
+-	unsigned long flags;
+-	unsigned long seq;
+-	unsigned long usec, sec;
+-
+-	do {
+-		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+-		usec = hw_timer_offset();
+-		sec = xtime.tv_sec;
+-		usec += (xtime.tv_nsec / 1000);
+-	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+-
+-	while (usec >= 1000000) {
+-		usec -= 1000000;
+-		sec++;
+-	}
+-
+-	tv->tv_sec = sec;
+-	tv->tv_usec = usec;
+-}
+-
+-EXPORT_SYMBOL(do_gettimeofday);
+-
+-int do_settimeofday(struct timespec *tv)
+-{
+-	time_t wtm_sec, sec = tv->tv_sec;
+-	long wtm_nsec, nsec = tv->tv_nsec;
+-
+-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+-		return -EINVAL;
+-
+-	write_seqlock_irq(&xtime_lock);
+-	/*
+-	 * This is revolting. We need to set the xtime.tv_usec
+-	 * correctly. However, the value in this location is
+-	 * is value at the last tick.
+-	 * Discover what correction gettimeofday
+-	 * would have done, and then undo it!
+-	 */
+-	nsec -= (hw_timer_offset() * 1000);
+-
+-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+-
+-	set_normalized_timespec(&xtime, sec, nsec);
+-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+-
+-	ntp_clear();
+-	write_sequnlock_irq(&xtime_lock);
+-	clock_was_set();
+-	return 0;
+-}
+-EXPORT_SYMBOL(do_settimeofday);
 diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
 index 07a0055..b44edb0 100644
 --- a/arch/m68knommu/kernel/vmlinux.lds.S
@@ -64619,8 +66668,3265 @@
  		*(.exitcall.exit)
  	}
  
+diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
+index b3c4dd4..53a5920 100644
+--- a/arch/m68knommu/platform/5206/config.c
++++ b/arch/m68knommu/platform/5206/config.c
+@@ -13,12 +13,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+-#include <asm/mcftimer.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -26,15 +25,51 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
+-        MCF_MBAR + MCFDMA_BASE1,
++static struct mcf_platform_uart m5206_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	},
++	{ },
++};
++
++static struct platform_device m5206_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5206_uart_platform,
++};
++
++static struct platform_device *m5206_devices[] __initdata = {
++	&m5206_uart,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++/***************************************************************************/
++
++static void __init m5206_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
++		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
++	} else if (line == 1) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
++		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
++	}
++}
++
++static void __init m5206_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5206_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5206_uart_init_line(line, m5206_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -74,24 +109,21 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
++void __init config_BSP(char *commandp, int size)
+ {
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = MCFSIM_IMR_TIMER1; break;
+-	case 2:  imr = MCFSIM_IMR_TIMER2; break;
+-	default: break;
+-	}
+-	return (mcf_getipr() & imr);
++	mcf_setimr(MCFSIM_IMR_MASKALL);
++	mach_reset = coldfire_reset;
+ }
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++static int __init init_BSP(void)
+ {
+-	mcf_setimr(MCFSIM_IMR_MASKALL);
+-	mach_reset = coldfire_reset;
++	m5206_uarts_init();
++	platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
++	return 0;
+ }
+ 
++arch_initcall(init_BSP);
++
+ /***************************************************************************/
+diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
+index f84a4ae..a6692e9 100644
+--- a/arch/m68knommu/platform/5206e/config.c
++++ b/arch/m68knommu/platform/5206e/config.c
+@@ -10,8 +10,9 @@
+ 
+ #include <linux/kernel.h>
+ #include <linux/param.h>
++#include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+@@ -23,15 +24,51 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
+-        MCF_MBAR + MCFDMA_BASE1,
++static struct mcf_platform_uart m5206e_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	},
++	{ },
++};
++
++static struct platform_device m5206e_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5206e_uart_platform,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device *m5206e_devices[] __initdata = {
++	&m5206e_uart,
++};
++
++/***************************************************************************/
++
++static void __init m5206_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
++		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
++	} else if (line == 1) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
++		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
++	}
++}
++
++static void __init m5206e_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5206e_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5206e_uart_init_line(line, m5206e_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -71,21 +108,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
+-{
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = MCFSIM_IMR_TIMER1; break;
+-	case 2:  imr = MCFSIM_IMR_TIMER2; break;
+-	default: break;
+-	}
+-	return (mcf_getipr() & imr);
+-}
+-
+-/***************************************************************************/
+-
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_setimr(MCFSIM_IMR_MASKALL);
+ 
+@@ -99,3 +122,14 @@ void config_BSP(char *commandp, int size)
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m5206e_uarts_init();
++	platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c
+index 6edbd41..06d887c 100644
+--- a/arch/m68knommu/platform/520x/config.c
++++ b/arch/m68knommu/platform/520x/config.c
+@@ -5,7 +5,7 @@
+  *
+  *  Copyright (C) 2005,      Freescale (www.freescale.com)
+  *  Copyright (C) 2005,      Intec Automation (mike at steroidmicros.com)
+- *  Copyright (C) 1999-2003, Greg Ungerer (gerg at snapgear.com)
++ *  Copyright (C) 1999-2007, Greg Ungerer (gerg at snapgear.com)
+  *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+  */
+ 
+@@ -13,21 +13,93 @@
+ 
+ #include <linux/kernel.h>
+ #include <linux/param.h>
++#include <linux/init.h>
+ #include <linux/interrupt.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+-#include <asm/dma.h>
++#include <asm/coldfire.h>
++#include <asm/mcfsim.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS];
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-void coldfire_reset(void);
++static struct mcf_platform_uart m520x_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= MCFINT_VECBASE + MCFINT_UART1,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE3,
++		.irq		= MCFINT_VECBASE + MCFINT_UART2,
++	},
++	{ },
++};
++
++static struct platform_device m520x_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m520x_uart_platform,
++};
++
++static struct platform_device *m520x_devices[] __initdata = {
++	&m520x_uart,
++};
++
++/***************************************************************************/
++
++#define	INTC0	(MCF_MBAR + MCFICM_INTC0)
++
++static void __init m520x_uart_init_line(int line, int irq)
++{
++	u32 imr;
++	u16 par;
++	u8 par2;
++
++	writeb(0x03, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
++
++	imr = readl(INTC0 + MCFINTC_IMRL);
++	imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
++	writel(imr, INTC0 + MCFINTC_IMRL);
++
++	switch (line) {
++	case 0:
++		par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
++		par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
++		       MCF_GPIO_PAR_UART_PAR_URXD0;
++		writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART);
++		break;
++	case 1:
++		par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
++		par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
++		       MCF_GPIO_PAR_UART_PAR_URXD1;
++		writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART);
++		break;
++	case 2:
++		par2 = readb(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
++		par2 &= ~0x0F;
++		par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
++			MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
++		writeb(par2, MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
++		break;
++	}
++}
++
++static void __init m520x_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m520x_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m520x_uart_init_line(line, m520x_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -42,9 +114,20 @@ void mcf_autovector(unsigned int vec)
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mach_reset = coldfire_reset;
++	m520x_uarts_init();
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
+index e7f80c8..13f0261 100644
+--- a/arch/m68knommu/platform/523x/config.c
++++ b/arch/m68knommu/platform/523x/config.c
+@@ -16,11 +16,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -28,14 +28,58 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
++static struct mcf_platform_uart m523x_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 1,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE3,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 2,
++	},
++	{ },
++};
++
++static struct platform_device m523x_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m523x_uart_platform,
++};
++
++static struct platform_device *m523x_devices[] __initdata = {
++	&m523x_uart,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++/***************************************************************************/
++
++#define	INTC0	(MCF_MBAR + MCFICM_INTC0)
++
++static void __init m523x_uart_init_line(int line, int irq)
++{
++	u32 imr;
++
++	if ((line < 0) || (line > 2))
++		return;
++
++	writeb(0x30+line, (INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line));
++
++	imr = readl(INTC0 + MCFINTC_IMRL);
++	imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
++	writel(imr, INTC0 + MCFINTC_IMRL);
++}
++
++static void __init m523x_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m523x_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m523x_uart_init_line(line, m523x_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -49,15 +93,26 @@ void mcf_disableall(void)
+ 
+ void mcf_autovector(unsigned int vec)
+ {
+-	/* Everything is auto-vectored on the 5272 */
++	/* Everything is auto-vectored on the 523x */
+ }
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_disableall();
+ 	mach_reset = coldfire_reset;
++	m523x_uarts_init();
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c
+index d4d3943..d299f7b 100644
+--- a/arch/m68knommu/platform/5249/config.c
++++ b/arch/m68knommu/platform/5249/config.c
+@@ -12,11 +12,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -24,17 +24,51 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
+-        MCF_MBAR + MCFDMA_BASE1,
+-        MCF_MBAR + MCFDMA_BASE2,
+-        MCF_MBAR + MCFDMA_BASE3,
++static struct mcf_platform_uart m5249_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	}
++};
++
++static struct platform_device m5249_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5249_uart_platform,
++};
++
++static struct platform_device *m5249_devices[] __initdata = {
++	&m5249_uart,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++/***************************************************************************/
++
++static void __init m5249_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
++		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
++	} else if (line == 1) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
++		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
++	}
++}
++
++static void __init m5249_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5249_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5249_uart_init_line(line, m5249_uart_platform[line].irq);
++}
++
+ 
+ /***************************************************************************/
+ 
+@@ -71,24 +105,21 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
++void __init config_BSP(char *commandp, int size)
+ {
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = MCFSIM_IMR_TIMER1; break;
+-	case 2:  imr = MCFSIM_IMR_TIMER2; break;
+-	default: break;
+-	}
+-	return (mcf_getipr() & imr);
++	mcf_setimr(MCFSIM_IMR_MASKALL);
++	mach_reset = coldfire_reset;
+ }
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++static int __init init_BSP(void)
+ {
+-	mcf_setimr(MCFSIM_IMR_MASKALL);
+-	mach_reset = coldfire_reset;
++	m5249_uarts_init();
++	platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
++	return 0;
+ }
+ 
++arch_initcall(init_BSP);
++
+ /***************************************************************************/
+diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
+index 634a637..2aca599 100644
+--- a/arch/m68knommu/platform/5272/config.c
++++ b/arch/m68knommu/platform/5272/config.c
+@@ -13,11 +13,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -37,14 +37,57 @@ unsigned char ledbank = 0xff;
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
++static struct mcf_platform_uart m5272_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	},
++	{ },
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device m5272_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5272_uart_platform,
++};
++
++static struct platform_device *m5272_devices[] __initdata = {
++	&m5272_uart,
++};
++
++/***************************************************************************/
++
++static void __init m5272_uart_init_line(int line, int irq)
++{
++	u32 v;
++
++	if ((line >= 0) && (line < 2)) {
++		v = (line) ? 0x0e000000 : 0xe0000000;
++		writel(v, MCF_MBAR + MCFSIM_ICR2);
++
++		/* Enable the output lines for the serial ports */
++		v = readl(MCF_MBAR + MCFSIM_PBCNT);
++		v = (v & ~0x000000ff) | 0x00000055;
++		writel(v, MCF_MBAR + MCFSIM_PBCNT);
++
++		v = readl(MCF_MBAR + MCFSIM_PDCNT);
++		v = (v & ~0x000003fc) | 0x000002a8;
++		writel(v, MCF_MBAR + MCFSIM_PDCNT);
++	}
++}
++
++static void __init m5272_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5272_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5272_uart_init_line(line, m5272_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -80,20 +123,7 @@ void mcf_settimericr(int timer, int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
+-{
+-	volatile unsigned long *icrp;
+-
+-	if ((timer >= 1 ) && (timer <= 4)) {
+-		icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
+-		return (*icrp & (0x8 << ((4 - timer) * 4)));
+-	}
+-	return 0;
+-}
+-
+-/***************************************************************************/
+-
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ #if defined (CONFIG_MOD5272)
+ 	volatile unsigned char	*pivrp;
+@@ -125,3 +155,14 @@ void config_BSP(char *commandp, int size)
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m5272_uarts_init();
++	platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
+index 9cbfbc6..73cd1ae 100644
+--- a/arch/m68knommu/platform/527x/config.c
++++ b/arch/m68knommu/platform/527x/config.c
+@@ -16,11 +16,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -28,14 +28,72 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
++static struct mcf_platform_uart m527x_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= MCFINT_VECBASE + MCFINT_UART1,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE3,
++		.irq		= MCFINT_VECBASE + MCFINT_UART2,
++	},
++	{ },
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device m527x_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m527x_uart_platform,
++};
++
++static struct platform_device *m527x_devices[] __initdata = {
++	&m527x_uart,
++};
++
++/***************************************************************************/
++
++#define	INTC0	(MCF_MBAR + MCFICM_INTC0)
++
++static void __init m527x_uart_init_line(int line, int irq)
++{
++	u16 sepmask;
++	u32 imr;
++
++	if ((line < 0) || (line > 2))
++		return;
++
++	/* level 6, line based priority */
++	writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
++
++	imr = readl(INTC0 + MCFINTC_IMRL);
++	imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
++	writel(imr, INTC0 + MCFINTC_IMRL);
++
++	/*
++	 * External Pin Mask Setting & Enable External Pin for Interface
++	 */
++	sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
++	if (line == 0)
++		sepmask |= UART0_ENABLE_MASK;
++	else if (line == 1)
++		sepmask |= UART1_ENABLE_MASK;
++	else if (line == 2)
++		sepmask |= UART2_ENABLE_MASK;
++	writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
++}
++
++static void __init m527x_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m527x_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m527x_uart_init_line(line, m527x_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -54,10 +112,21 @@ void mcf_autovector(unsigned int vec)
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_disableall();
+ 	mach_reset = coldfire_reset;
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m527x_uarts_init();
++	platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
+index acbd434..036e1b7 100644
+--- a/arch/m68knommu/platform/528x/config.c
++++ b/arch/m68knommu/platform/528x/config.c
+@@ -16,11 +16,15 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
++#include <asm/mcfqspi.h>
+ 
+ /***************************************************************************/
+ 
+@@ -28,14 +32,67 @@ void coldfire_reset(void);
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
++static struct mcf_platform_uart m528x_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 1,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE3,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0 + 2,
++	},
++	{ },
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device m528x_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m528x_uart_platform,
++};
++
++static struct platform_device *m528x_devices[] __initdata = {
++	&m528x_uart,
++};
++
++/***************************************************************************/
++
++#define	INTC0	(MCF_MBAR + MCFICM_INTC0)
++
++static void __init m528x_uart_init_line(int line, int irq)
++{
++	u8 port;
++	u32 imr;
++
++	if ((line < 0) || (line > 2))
++		return;
++
++	/* level 6, line based priority */
++	writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
++
++	imr = readl(INTC0 + MCFINTC_IMRL);
++	imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
++	writel(imr, INTC0 + MCFINTC_IMRL);
++
++	/* make sure PUAPAR is set for UART0 and UART1 */
++	if (line < 2) {
++		port = readb(MCF_MBAR + MCF5282_GPIO_PUAPAR);
++		port |= (0x03 << (line * 2));
++		writeb(port, MCF_MBAR + MCF5282_GPIO_PUAPAR);
++	}
++}
++
++static void __init m528x_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m528x_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m528x_uart_init_line(line, m528x_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -54,10 +111,21 @@ void mcf_autovector(unsigned int vec)
+ 
+ /***************************************************************************/
+ 
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_disableall();
+ 	mach_reset = coldfire_reset;
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m528x_uarts_init();
++	platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
+index 5b60053..580fd66 100644
+--- a/arch/m68knommu/platform/5307/Makefile
++++ b/arch/m68knommu/platform/5307/Makefile
+@@ -16,17 +16,5 @@ ifdef CONFIG_FULLDEBUG
+ EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
+ endif
+ 
+-obj-$(CONFIG_COLDFIRE)	+= entry.o vectors.o
+-obj-$(CONFIG_M5206)	+= timers.o
+-obj-$(CONFIG_M5206e)	+= timers.o
+-obj-$(CONFIG_M520x)	+= pit.o
+-obj-$(CONFIG_M523x)	+= pit.o
+-obj-$(CONFIG_M5249)	+= timers.o
+-obj-$(CONFIG_M527x)     += pit.o
+-obj-$(CONFIG_M5272)	+= timers.o
+-obj-$(CONFIG_M5307)	+= config.o timers.o
+-obj-$(CONFIG_M532x)	+= timers.o
+-obj-$(CONFIG_M528x)     += pit.o
+-obj-$(CONFIG_M5407)	+= timers.o
++obj-y	+= config.o
+ 
+-extra-y := head.o
+diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
+index 6040821..92dc862 100644
+--- a/arch/m68knommu/platform/5307/config.c
++++ b/arch/m68knommu/platform/5307/config.c
+@@ -13,11 +13,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ #include <asm/mcfwdebug.h>
+ 
+ /***************************************************************************/
+@@ -38,17 +38,51 @@ unsigned char ledbank = 0xff;
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
+-        MCF_MBAR + MCFDMA_BASE1,
+-        MCF_MBAR + MCFDMA_BASE2,
+-        MCF_MBAR + MCFDMA_BASE3,
++static struct mcf_platform_uart m5307_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	},
++	{ },
++};
++
++static struct platform_device m5307_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5307_uart_platform,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device *m5307_devices[] __initdata = {
++	&m5307_uart,
++};
++
++/***************************************************************************/
++
++static void __init m5307_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
++		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
++	} else if (line == 1) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
++		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
++	}
++}
++
++static void __init m5307_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5307_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5307_uart_init_line(line, m5307_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -85,21 +119,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
+-{
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = MCFSIM_IMR_TIMER1; break;
+-	case 2:  imr = MCFSIM_IMR_TIMER2; break;
+-	default: break;
+-	}
+-	return (mcf_getipr() & imr);
+-}
+-
+-/***************************************************************************/
+-
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_setimr(MCFSIM_IMR_MASKALL);
+ 
+@@ -117,7 +137,7 @@ void config_BSP(char *commandp, int size)
+ 
+ 	mach_reset = coldfire_reset;
+ 
+-#ifdef MCF_BDM_DISABLE
++#ifdef CONFIG_BDM_DISABLE
+ 	/*
+ 	 * Disable the BDM clocking.  This also turns off most of the rest of
+ 	 * the BDM device.  This is good for EMC reasons. This option is not
+@@ -128,3 +148,14 @@ void config_BSP(char *commandp, int size)
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m5307_uarts_init();
++	platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/5307/entry.S b/arch/m68knommu/platform/5307/entry.S
+deleted file mode 100644
+index b333731..0000000
+--- a/arch/m68knommu/platform/5307/entry.S
++++ /dev/null
+@@ -1,235 +0,0 @@
+-/*
+- *  linux/arch/m68knommu/platform/5307/entry.S
+- *
+- *  Copyright (C) 1999-2007, Greg Ungerer (gerg at snapgear.com)
+- *  Copyright (C) 1998  D. Jeff Dionne <jeff at lineo.ca>,
+- *                      Kenneth Albanowski <kjahds at kjahds.com>,
+- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
+- *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
+- *
+- * Based on:
+- *
+- *  linux/arch/m68k/kernel/entry.S
+- *
+- *  Copyright (C) 1991, 1992  Linus Torvalds
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file README.legal in the main directory of this archive
+- * for more details.
+- *
+- * Linux/m68k support by Hamish Macdonald
+- *
+- * 68060 fixes by Jesper Skov
+- * ColdFire support by Greg Ungerer (gerg at snapgear.com)
+- * 5307 fixes by David W. Miller
+- * linux 2.4 support David McCullough <davidm at snapgear.com>
+- * Bug, speed and maintainability fixes by Philippe De Muyter <phdm at macqel.be>
+- */
+-
+-#include <linux/sys.h>
+-#include <linux/linkage.h>
+-#include <asm/unistd.h>
+-#include <asm/thread_info.h>
+-#include <asm/errno.h>
+-#include <asm/setup.h>
+-#include <asm/segment.h>
+-#include <asm/asm-offsets.h>
+-#include <asm/entry.h>
+-
+-.bss
+-
+-sw_ksp:
+-.long	0
+-
+-sw_usp:
+-.long	0
+-
+-.text
+-
+-.globl system_call
+-.globl resume
+-.globl ret_from_exception
+-.globl ret_from_signal
+-.globl sys_call_table
+-.globl ret_from_interrupt
+-.globl inthandler
+-.globl fasthandler
+-
+-enosys:
+-	mov.l	#sys_ni_syscall,%d3
+-	bra	1f
+-
+-ENTRY(system_call)
+-	SAVE_ALL
+-	move	#0x2000,%sr		/* enable intrs again */
+-
+-	cmpl	#NR_syscalls,%d0
+-	jcc	enosys
+-	lea	sys_call_table,%a0
+-	lsll	#2,%d0			/* movel %a0@(%d0:l:4),%d3 */
+-	movel	%a0@(%d0),%d3
+-	jeq	enosys
+-
+-1:
+-	movel	%sp,%d2			/* get thread_info pointer */
+-	andl	#-THREAD_SIZE,%d2	/* at start of kernel stack */
+-	movel	%d2,%a0
+-	movel	%a0@,%a1		/* save top of frame */
+-	movel	%sp,%a1@(TASK_THREAD+THREAD_ESP0)
+-	btst	#(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+-	bnes	1f
+-
+-	movel	%d3,%a0
+-	jbsr	%a0@
+-	movel	%d0,%sp@(PT_D0)		/* save the return value */
+-	jra	ret_from_exception
+-1:
+-	movel	#-ENOSYS,%d2		/* strace needs -ENOSYS in PT_D0 */
+-	movel	%d2,PT_D0(%sp)		/* on syscall entry */
+-	subql	#4,%sp
+-	SAVE_SWITCH_STACK
+-	jbsr	syscall_trace
+-	RESTORE_SWITCH_STACK
+-	addql	#4,%sp
+-	movel	%d3,%a0
+-	jbsr	%a0@
+-	movel	%d0,%sp@(PT_D0)		/* save the return value */
+-	subql	#4,%sp			/* dummy return address */
+-	SAVE_SWITCH_STACK
+-	jbsr	syscall_trace
+-
+-ret_from_signal:
+-	RESTORE_SWITCH_STACK
+-	addql	#4,%sp
+-
+-ret_from_exception:
+-	btst	#5,%sp@(PT_SR)		/* check if returning to kernel */
+-	jeq	Luser_return		/* if so, skip resched, signals */
+-
+-Lkernel_return:
+-	moveml	%sp@,%d1-%d5/%a0-%a2
+-	lea	%sp@(32),%sp		/* space for 8 regs */
+-	movel	%sp at +,%d0
+-	addql	#4,%sp			/* orig d0 */
+-	addl	%sp at +,%sp		/* stk adj */
+-	rte
+-
+-Luser_return:
+-	movel	%sp,%d1			/* get thread_info pointer */
+-	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
+-	movel	%d1,%a0
+-	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
+-	andl	#_TIF_WORK_MASK,%d1
+-	jne	Lwork_to_do		/* still work to do */
+-
+-Lreturn:
+-	move	#0x2700,%sr		/* disable intrs */
+-	movel	sw_usp,%a0		/* get usp */
+-	movel	%sp@(PT_PC),%a0 at -	/* copy exception program counter */
+-	movel	%sp@(PT_FORMATVEC),%a0 at -/* copy exception format/vector/sr */
+-	moveml	%sp@,%d1-%d5/%a0-%a2
+-	lea	%sp@(32),%sp		/* space for 8 regs */
+-	movel	%sp at +,%d0
+-	addql	#4,%sp			/* orig d0 */
+-	addl	%sp at +,%sp		/* stk adj */
+-	addql	#8,%sp			/* remove exception */
+-	movel	%sp,sw_ksp		/* save ksp */
+-	subql	#8,sw_usp		/* set exception */
+-	movel	sw_usp,%sp		/* restore usp */
+-	rte
+-
+-Lwork_to_do:
+-	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
+-	btst	#TIF_NEED_RESCHED,%d1
+-	jne	reschedule
+-
+-	/* GERG: do we need something here for TRACEing?? */
+-
+-Lsignal_return:
+-	subql	#4,%sp			/* dummy return address */
+-	SAVE_SWITCH_STACK
+-	pea	%sp@(SWITCH_STACK_SIZE)
+-	clrl	%sp at -
+-	jsr	do_signal
+-	addql	#8,%sp
+-	RESTORE_SWITCH_STACK
+-	addql	#4,%sp
+-	jmp	Lreturn
+-
+-/*
+- * This is the generic interrupt handler (for all hardware interrupt
+- * sources). Calls upto high level code to do all the work.
+- */
+-ENTRY(inthandler)
+-	SAVE_ALL
+-	moveq	#-1,%d0
+-	movel	%d0,%sp@(PT_ORIG_D0)
+-
+-	movew	%sp@(PT_FORMATVEC),%d0	/* put exception # in d0 */
+-	andl	#0x03fc,%d0		/* mask out vector only */
+-
+-	movel	%sp,%sp at -		/* push regs arg */
+-	lsrl	#2,%d0			/* calculate real vector # */
+-	movel	%d0,%sp at -		/* push vector number */
+-	jbsr	do_IRQ			/* call high level irq handler */
+-	lea	%sp@(8),%sp		/* pop args off stack */
+-
+-	bra	ret_from_interrupt	/* this was fallthrough */
+-
+-/*
+- * This is the fast interrupt handler (for certain hardware interrupt
+- * sources). Unlike the normal interrupt handler it just uses the
+- * current stack (doesn't care if it is user or kernel). It also
+- * doesn't bother doing the bottom half handlers.
+- */
+-ENTRY(fasthandler)
+-	SAVE_LOCAL
+-
+-	movew	%sp@(PT_FORMATVEC),%d0
+-	andl	#0x03fc,%d0		/* mask out vector only */
+-
+-	movel	%sp,%sp at -		/* push regs arg */
+-	lsrl	#2,%d0			/* calculate real vector # */
+-	movel	%d0,%sp at -		/* push vector number */
+-	jbsr	do_IRQ			/* call high level irq handler */
+-	lea	%sp@(8),%sp		/* pop args off stack */
+-
+-	RESTORE_LOCAL
+-
+-ENTRY(ret_from_interrupt)
+-	jeq	2f
+-1:
+-	RESTORE_ALL
+-2:
+-	moveb	%sp@(PT_SR),%d0
+-	andl	#0x7,%d0
+-	jhi	1b
+-
+-	/* check if we need to do software interrupts */
+-	movel	irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0
+-	jeq	ret_from_exception
+-
+-	pea	ret_from_exception
+-	jmp	do_softirq
+-
+-/*
+- * Beware - when entering resume, prev (the current task) is
+- * in a0, next (the new task) is in a1,so don't change these
+- * registers until their contents are no longer needed.
+- * This is always called in supervisor mode, so don't bother to save
+- * and restore sr; user's process sr is actually in the stack.
+- */
+-ENTRY(resume)
+-	movel	%a0, %d1			/* get prev thread in d1 */
+-
+-	movel	sw_usp,%d0			/* save usp */
+-	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
+-
+-	SAVE_SWITCH_STACK
+-	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
+-	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+-	RESTORE_SWITCH_STACK
+-
+-	movel	%a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
+-	movel	%a0, sw_usp
+-	rts
+diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S
+deleted file mode 100644
+index b9aa0ca..0000000
+--- a/arch/m68knommu/platform/5307/head.S
++++ /dev/null
+@@ -1,222 +0,0 @@
+-/*****************************************************************************/
+-
+-/*
+- *	head.S -- common startup code for ColdFire CPUs.
+- *
+- *	(C) Copyright 1999-2006, Greg Ungerer <gerg at snapgear.com>.
+- */
+-
+-/*****************************************************************************/
+-
+-#include <linux/sys.h>
+-#include <linux/linkage.h>
+-#include <asm/asm-offsets.h>
+-#include <asm/coldfire.h>
+-#include <asm/mcfcache.h>
+-#include <asm/mcfsim.h>
+-
+-/*****************************************************************************/
+-
+-/*
+- *	If we don't have a fixed memory size, then lets build in code
+- *	to auto detect the DRAM size. Obviously this is the prefered
+- *	method, and should work for most boards. It won't work for those
+- *	that do not have their RAM starting at address 0, and it only
+- *	works on SDRAM (not boards fitted with SRAM).
+- */
+-#if CONFIG_RAMSIZE != 0
+-.macro GET_MEM_SIZE
+-	movel	#CONFIG_RAMSIZE,%d0	/* hard coded memory size */
+-.endm
+-
+-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+-      defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
+-      defined(CONFIG_M528x) || defined(CONFIG_M5307) || \
+-      defined(CONFIG_M5407)
+-/*
+- *	Not all these devices have exactly the same DRAM controller,
+- *	but the DCMR register is virtually identical - give or take
+- *	a couple of bits. The only exception is the 5272 devices, their
+- *	DRAM controller is quite different.
+- */
+-.macro GET_MEM_SIZE
+-	movel	MCF_MBAR+MCFSIM_DMR0,%d0 /* get mask for 1st bank */
+-	btst	#0,%d0			/* check if region enabled */
+-	beq	1f
+-	andl	#0xfffc0000,%d0
+-	beq	1f
+-	addl	#0x00040000,%d0		/* convert mask to size */
+-1:
+-	movel	MCF_MBAR+MCFSIM_DMR1,%d1 /* get mask for 2nd bank */
+-	btst	#0,%d1			/* check if region enabled */
+-	beq	2f
+-	andl	#0xfffc0000, %d1
+-	beq	2f
+-	addl	#0x00040000,%d1
+-	addl	%d1,%d0			/* total mem size in d0 */
+-2:
+-.endm
+-
+-#elif defined(CONFIG_M5272)
+-.macro GET_MEM_SIZE
+-	movel	MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */
+-	andil	#0xfffff000,%d0		/* mask out chip select options */
+-	negl	%d0			/* negate bits */
+-.endm
+-
+-#elif defined(CONFIG_M520x)
+-.macro GET_MEM_SIZE
+-	clrl	%d0
+-	movel	MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */
+-	andl	#0x1f, %d2		/* Get only the chip select size */
+-	beq	3f			/* Check if it is enabled */
+-	addql	#1, %d2			/* Form exponent */
+-	moveql	#1, %d0
+-	lsll	%d2, %d0		/* 2 ^ exponent */
+-3:
+-	movel	MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */
+-	andl	#0x1f, %d2		/* Get only the chip select size */
+-	beq	4f			/* Check if it is enabled */
+-	addql	#1, %d2			/* Form exponent */
+-	moveql	#1, %d1
+-	lsll	%d2, %d1		/* 2 ^ exponent */
+-	addl	%d1, %d0		/* Total size of SDRAM in d0 */
+-4:
+-.endm
+-
+-#else
+-#error "ERROR: I don't know how to probe your boards memory size?"
+-#endif
+-
+-/*****************************************************************************/
+-
+-/*
+- *	Boards and platforms can do specific early hardware setup if
+- *	they need to. Most don't need this, define away if not required.
+- */
+-#ifndef PLATFORM_SETUP
+-#define	PLATFORM_SETUP
+-#endif
+-
+-/*****************************************************************************/
+-
+-.global	_start
+-.global _rambase
+-.global _ramvec
+-.global	_ramstart
+-.global	_ramend
+-
+-/*****************************************************************************/
+-
+-.data
+-
+-/*
+- *	During startup we store away the RAM setup. These are not in the
+- *	bss, since their values are determined and written before the bss
+- *	has been cleared.
+- */
+-_rambase:
+-.long	0
+-_ramvec:
+-.long	0
+-_ramstart:
+-.long	0
+-_ramend:
+-.long	0
+-
+-/*****************************************************************************/
+-
+-.text
+-
+-/*
+- *	This is the codes first entry point. This is where it all
+- *	begins...
+- */
+-
+-_start:
+-	nop					/* filler */
+-	movew	#0x2700, %sr			/* no interrupts */
+-
+-	/*
+-	 *	Do any platform or board specific setup now. Most boards
+-	 *	don't need anything. Those exceptions are define this in
+-	 *	their board specific includes.
+-	 */
+-	PLATFORM_SETUP
+-
+-	/*
+-	 *	Create basic memory configuration. Set VBR accordingly,
+-	 *	and size memory.
+-	 */
+-	movel	#CONFIG_VECTORBASE,%a7
+-	movec   %a7,%VBR			/* set vectors addr */
+-	movel	%a7,_ramvec
+-
+-	movel	#CONFIG_RAMBASE,%a7		/* mark the base of RAM */
+-	movel	%a7,_rambase
+-
+-	GET_MEM_SIZE				/* macro code determines size */
+-	addl	%a7,%d0
+-	movel	%d0,_ramend			/* set end ram addr */
+-
+-	/*
+-	 *	Now that we know what the memory is, lets enable cache
+-	 *	and get things moving. This is Coldfire CPU specific.
+-	 */
+-	CACHE_ENABLE				/* enable CPU cache */
+-
+-
+-#ifdef CONFIG_ROMFS_FS
+-	/*
+-	 *	Move ROM filesystem above bss :-)
+-	 */
+-	lea	_sbss,%a0			/* get start of bss */
+-	lea	_ebss,%a1			/* set up destination  */
+-	movel	%a0,%a2				/* copy of bss start */
+-
+-	movel	8(%a0),%d0			/* get size of ROMFS */
+-	addql	#8,%d0				/* allow for rounding */
+-	andl	#0xfffffffc, %d0		/* whole words */
+-
+-	addl	%d0,%a0				/* copy from end */
+-	addl	%d0,%a1				/* copy from end */
+-	movel	%a1,_ramstart			/* set start of ram */
+-
+-_copy_romfs:
+-	movel	-(%a0),%d0			/* copy dword */
+-	movel	%d0,-(%a1)
+-	cmpl	%a0,%a2				/* check if at end */
+-	bne	_copy_romfs
+-
+-#else /* CONFIG_ROMFS_FS */
+-	lea	_ebss,%a1
+-	movel	%a1,_ramstart
+-#endif /* CONFIG_ROMFS_FS */
+-
+-
+-	/*
+-	 *	Zero out the bss region.
+-	 */
+-	lea	_sbss,%a0			/* get start of bss */
+-	lea	_ebss,%a1			/* get end of bss */
+-	clrl	%d0				/* set value */
+-_clear_bss:
+-	movel	%d0,(%a0)+			/* clear each word */
+-	cmpl	%a0,%a1				/* check if at end */
+-	bne	_clear_bss
+-
+-	/*
+-	 *	Load the current task pointer and stack.
+-	 */
+-	lea	init_thread_union,%a0
+-	lea	THREAD_SIZE(%a0),%sp
+-
+-	/*
+-	 *	Assember start up done, start code proper.
+-	 */
+-	jsr	start_kernel			/* start Linux kernel */
+-
+-_exit:
+-	jmp	_exit				/* should never get here */
+-
+-/*****************************************************************************/
+diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c
+deleted file mode 100644
+index 173b754..0000000
+--- a/arch/m68knommu/platform/5307/pit.c
++++ /dev/null
+@@ -1,97 +0,0 @@
+-/***************************************************************************/
+-
+-/*
+- *	pit.c -- Freescale ColdFire PIT timer. Currently this type of
+- *	         hardware timer only exists in the Freescale ColdFire
+- *		 5270/5271, 5282 and other CPUs.
+- *
+- *	Copyright (C) 1999-2007, Greg Ungerer (gerg at snapgear.com)
+- *	Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+- */
+-
+-/***************************************************************************/
+-
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/param.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <asm/machdep.h>
+-#include <asm/io.h>
+-#include <asm/coldfire.h>
+-#include <asm/mcfpit.h>
+-#include <asm/mcfsim.h>
+-
+-/***************************************************************************/
+-
+-/*
+- *	By default use timer1 as the system clock timer.
+- */
+-#define	TA(a)	(MCF_IPSBAR + MCFPIT_BASE1 + (a))
+-
+-/***************************************************************************/
+-
+-static irqreturn_t hw_tick(int irq, void *dummy)
+-{
+-	unsigned short pcsr;
+-
+-	/* Reset the ColdFire timer */
+-	pcsr = __raw_readw(TA(MCFPIT_PCSR));
+-	__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
+-
+-	return arch_timer_interrupt(irq, dummy);
+-}
+-
+-/***************************************************************************/
+-
+-static struct irqaction coldfire_pit_irq = {
+-	.name	 = "timer",
+-	.flags	 = IRQF_DISABLED | IRQF_TIMER,
+-	.handler = hw_tick,
+-};
+-
+-void hw_timer_init(void)
+-{
+-	volatile unsigned char *icrp;
+-	volatile unsigned long *imrp;
+-
+-	setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
+-
+-	icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
+-		MCFINTC_ICR0 + MCFINT_PIT1);
+-	*icrp = ICR_INTRCONF;
+-
+-	imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
+-	*imrp &= ~MCFPIT_IMR_IBIT;
+-
+-	/* Set up PIT timer 1 as poll clock */
+-	__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+-	__raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
+-	__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
+-		MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
+-}
+-
+-/***************************************************************************/
+-
+-unsigned long hw_timer_offset(void)
+-{
+-	volatile unsigned long *ipr;
+-	unsigned long pmr, pcntr, offset;
+-
+-	ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
+-
+-	pmr = __raw_readw(TA(MCFPIT_PMR));
+-	pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+-
+-	/*
+-	 * If we are still in the first half of the upcount and a
+-	 * timer interrupt is pending, then add on a ticks worth of time.
+-	 */
+-	offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
+-	if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT))
+-		offset += 1000000 / HZ;
+-	return offset;	
+-}
+-
+-/***************************************************************************/
+diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c
+deleted file mode 100644
+index 489dec8..0000000
+--- a/arch/m68knommu/platform/5307/timers.c
++++ /dev/null
+@@ -1,155 +0,0 @@
+-/***************************************************************************/
+-
+-/*
+- *	timers.c -- generic ColdFire hardware timer support.
+- *
+- *	Copyright (C) 1999-2007, Greg Ungerer (gerg at snapgear.com)
+- */
+-
+-/***************************************************************************/
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <asm/io.h>
+-#include <asm/traps.h>
+-#include <asm/machdep.h>
+-#include <asm/coldfire.h>
+-#include <asm/mcftimer.h>
+-#include <asm/mcfsim.h>
+-
+-/***************************************************************************/
+-
+-/*
+- *	By default use timer1 as the system clock timer.
+- */
+-#define	TA(a)	(MCF_MBAR + MCFTIMER_BASE1 + (a))
+-
+-/*
+- *	Default the timer and vector to use for ColdFire. Some ColdFire
+- *	CPU's and some boards may want different. Their sub-architecture
+- *	startup code (in config.c) can change these if they want.
+- */
+-unsigned int	mcf_timervector = 29;
+-unsigned int	mcf_profilevector = 31;
+-unsigned int	mcf_timerlevel = 5;
+-
+-/*
+- *	These provide the underlying interrupt vector support.
+- *	Unfortunately it is a little different on each ColdFire.
+- */
+-extern void mcf_settimericr(int timer, int level);
+-extern int mcf_timerirqpending(int timer);
+-
+-#if defined(CONFIG_M532x)
+-#define	__raw_readtrr	__raw_readl
+-#define	__raw_writetrr	__raw_writel
+-#else
+-#define	__raw_readtrr	__raw_readw
+-#define	__raw_writetrr	__raw_writew
+-#endif
+-
+-/***************************************************************************/
+-
+-static irqreturn_t hw_tick(int irq, void *dummy)
+-{
+-	/* Reset the ColdFire timer */
+-	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
+-
+-	return arch_timer_interrupt(irq, dummy);
+-}
+-
+-/***************************************************************************/
+-
+-static struct irqaction coldfire_timer_irq = {
+-	.name	 = "timer",
+-	.flags	 = IRQF_DISABLED | IRQF_TIMER,
+-	.handler = hw_tick,
+-};
+-
+-/***************************************************************************/
+-
+-static int ticks_per_intr;
+-
+-void hw_timer_init(void)
+-{
+-	setup_irq(mcf_timervector, &coldfire_timer_irq);
+-
+-	__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
+-	ticks_per_intr = (MCF_BUSCLK / 16) / HZ;
+-	__raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR));
+-	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+-		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
+-
+-	mcf_settimericr(1, mcf_timerlevel);
+-
+-#ifdef CONFIG_HIGHPROFILE
+-	coldfire_profile_init();
+-#endif
+-}
+-
+-/***************************************************************************/
+-
+-unsigned long hw_timer_offset(void)
+-{
+-	unsigned long tcn, offset;
+-
+-	tcn = __raw_readw(TA(MCFTIMER_TCN));
+-	offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr;
+-
+-	/* Check if we just wrapped the counters and maybe missed a tick */
+-	if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1))
+-		offset += 1000000 / HZ;
+-	return offset;
+-}
+-
+-/***************************************************************************/
+-#ifdef CONFIG_HIGHPROFILE
+-/***************************************************************************/
+-
+-/*
+- *	By default use timer2 as the profiler clock timer.
+- */
+-#define	PA(a)	(MCF_MBAR + MCFTIMER_BASE2 + (a))
+-
+-/*
+- *	Choose a reasonably fast profile timer. Make it an odd value to
+- *	try and get good coverage of kernel operations.
+- */
+-#define	PROFILEHZ	1013
+-
+-/*
+- *	Use the other timer to provide high accuracy profiling info.
+- */
+-irqreturn_t coldfire_profile_tick(int irq, void *dummy)
+-{
+-	/* Reset ColdFire timer2 */
+-	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
+-	if (current->pid)
+-		profile_tick(CPU_PROFILING, regs);
+-	return IRQ_HANDLED;
+-}
+-
+-/***************************************************************************/
+-
+-void coldfire_profile_init(void)
+-{
+-	printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ);
+-
+-	/* Set up TIMER 2 as high speed profile clock */
+-	__raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
+-
+-	__raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
+-	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+-		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
+-
+-	request_irq(mcf_profilevector, coldfire_profile_tick,
+-		(IRQF_DISABLED | IRQ_FLG_FAST), "profile timer", NULL);
+-	mcf_settimericr(2, 7);
+-}
+-
+-/***************************************************************************/
+-#endif	/* CONFIG_HIGHPROFILE */
+-/***************************************************************************/
+diff --git a/arch/m68knommu/platform/5307/vectors.c b/arch/m68knommu/platform/5307/vectors.c
+deleted file mode 100644
+index 6cf8946..0000000
+--- a/arch/m68knommu/platform/5307/vectors.c
++++ /dev/null
+@@ -1,105 +0,0 @@
+-/***************************************************************************/
+-
+-/*
+- *	linux/arch/m68knommu/platform/5307/vectors.c
+- *
+- *	Copyright (C) 1999-2007, Greg Ungerer <gerg at snapgear.com>
+- */
+-
+-/***************************************************************************/
+-
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/irq.h>
+-#include <asm/traps.h>
+-#include <asm/machdep.h>
+-#include <asm/coldfire.h>
+-#include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
+-#include <asm/mcfwdebug.h>
+-
+-/***************************************************************************/
+-
+-#ifdef TRAP_DBG_INTERRUPT
+-
+-asmlinkage void dbginterrupt_c(struct frame *fp)
+-{
+-	extern void dump(struct pt_regs *fp);
+-	printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
+-	dump((struct pt_regs *) fp);
+-	asm("halt");
+-}
+-
+-#endif
+-
+-/***************************************************************************/
+-
+-extern e_vector	*_ramvec;
+-
+-void set_evector(int vecnum, void (*handler)(void))
+-{
+-	if (vecnum >= 0 && vecnum <= 255)
+-		_ramvec[vecnum] = handler;
+-}
+-
+-/***************************************************************************/
+-
+-/* Assembler routines */
+-asmlinkage void buserr(void);
+-asmlinkage void trap(void);
+-asmlinkage void system_call(void);
+-asmlinkage void inthandler(void);
+-
+-void __init init_vectors(void)
+-{
+-	int i;
+-
+-	/*
+-	 *	There is a common trap handler and common interrupt
+-	 *	handler that handle almost every vector. We treat
+-	 *	the system call and bus error special, they get their
+-	 *	own first level handlers.
+-	 */
+-	for (i = 3; (i <= 23); i++)
+-		_ramvec[i] = trap;
+-	for (i = 33; (i <= 63); i++)
+-		_ramvec[i] = trap;
+-	for (i = 24; (i <= 31); i++)
+-		_ramvec[i] = inthandler;
+-	for (i = 64; (i < 255); i++)
+-		_ramvec[i] = inthandler;
+-	_ramvec[255] = 0;
+-
+-	_ramvec[2] = buserr;
+-	_ramvec[32] = system_call;
+-
+-#ifdef TRAP_DBG_INTERRUPT
+-	_ramvec[12] = dbginterrupt;
+-#endif
+-}
+-
+-/***************************************************************************/
+-
+-void enable_vector(unsigned int irq)
+-{
+-	/* Currently no action on ColdFire */
+-}
+-
+-void disable_vector(unsigned int irq)
+-{
+-	/* Currently no action on ColdFire */
+-}
+-
+-void ack_vector(unsigned int irq)
+-{
+-	/* Currently no action on ColdFire */
+-}
+-
+-/***************************************************************************/
+-
+-void coldfire_reset(void)
+-{
+-	HARD_RESET_NOW();
+-}
+-
+-/***************************************************************************/
+diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
+index f77328b..4f44b63 100644
+--- a/arch/m68knommu/platform/532x/config.c
++++ b/arch/m68knommu/platform/532x/config.c
+@@ -21,10 +21,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
++#include <asm/mcfuart.h>
+ #include <asm/mcfdma.h>
+ #include <asm/mcfwdebug.h>
+ 
+@@ -38,11 +39,60 @@ extern unsigned int mcf_timerlevel;
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { };
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct mcf_platform_uart m532x_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= MCFINT_VECBASE + MCFINT_UART0,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= MCFINT_VECBASE + MCFINT_UART1,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE3,
++		.irq		= MCFINT_VECBASE + MCFINT_UART2,
++	},
++	{ },
++};
++
++static struct platform_device m532x_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m532x_uart_platform,
++};
++
++static struct platform_device *m532x_devices[] __initdata = {
++	&m532x_uart,
++};
++
++/***************************************************************************/
++
++static void __init m532x_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		MCF_INTC0_ICR26 = 0x3;
++		MCF_INTC0_CIMR = 26;
++		/* GPIO initialization */
++		MCF_GPIO_PAR_UART |= 0x000F;
++	} else if (line == 1) {
++		MCF_INTC0_ICR27 = 0x3;
++		MCF_INTC0_CIMR = 27;
++		/* GPIO initialization */
++		MCF_GPIO_PAR_UART |= 0x0FF0;
++	} else if (line == 2) {
++		MCF_INTC0_ICR28 = 0x3;
++		MCF_INTC0_CIMR = 28;
++	}
++}
++
++static void __init m532x_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m532x_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m532x_uart_init_line(line, m532x_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -66,21 +116,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
+-{
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = 0x1; break;
+-	case 2:  imr = 0x2; break;
+-	default: break;
+-	}
+-	return (mcf_getiprh() & imr);
+-}
+-
+-/***************************************************************************/
+-
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_setimr(MCFSIM_IMR_MASKALL);
+ 
+@@ -99,7 +135,7 @@ void config_BSP(char *commandp, int size)
+ 	mcf_profilevector = 64+33;
+ 	mach_reset = coldfire_reset;
+ 
+-#ifdef MCF_BDM_DISABLE
++#ifdef CONFIG_BDM_DISABLE
+ 	/*
+ 	 * Disable the BDM clocking.  This also turns off most of the rest of
+ 	 * the BDM device.  This is good for EMC reasons. This option is not
+@@ -110,9 +146,19 @@ void config_BSP(char *commandp, int size)
+ }
+ 
+ /***************************************************************************/
+-/* Board initialization */
+ 
+-/********************************************************************/
++static int __init init_BSP(void)
++{
++	m532x_uarts_init();
++	platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
++/* Board initialization */
++/***************************************************************************/
+ /* 
+  * PLL min/max specifications
+  */
+diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c
+index 2d3b62e..648b8b7 100644
+--- a/arch/m68knommu/platform/5407/config.c
++++ b/arch/m68knommu/platform/5407/config.c
+@@ -13,11 +13,11 @@
+ #include <linux/param.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+-#include <asm/dma.h>
++#include <linux/io.h>
+ #include <asm/machdep.h>
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+-#include <asm/mcfdma.h>
++#include <asm/mcfuart.h>
+ 
+ /***************************************************************************/
+ 
+@@ -29,17 +29,51 @@ extern unsigned int mcf_timerlevel;
+ 
+ /***************************************************************************/
+ 
+-/*
+- *	DMA channel base address table.
+- */
+-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+-        MCF_MBAR + MCFDMA_BASE0,
+-        MCF_MBAR + MCFDMA_BASE1,
+-        MCF_MBAR + MCFDMA_BASE2,
+-        MCF_MBAR + MCFDMA_BASE3,
++static struct mcf_platform_uart m5407_uart_platform[] = {
++	{
++		.mapbase	= MCF_MBAR + MCFUART_BASE1,
++		.irq		= 73,
++	},
++	{
++		.mapbase 	= MCF_MBAR + MCFUART_BASE2,
++		.irq		= 74,
++	},
++	{ },
++};
++
++static struct platform_device m5407_uart = {
++	.name			= "mcfuart",
++	.id			= 0,
++	.dev.platform_data	= m5407_uart_platform,
+ };
+ 
+-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++static struct platform_device *m5407_devices[] __initdata = {
++	&m5407_uart,
++};
++
++/***************************************************************************/
++
++static void __init m5407_uart_init_line(int line, int irq)
++{
++	if (line == 0) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
++		writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
++	} else if (line == 1) {
++		writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
++		writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
++		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
++	}
++}
++
++static void __init m5407_uarts_init(void)
++{
++	const int nrlines = ARRAY_SIZE(m5407_uart_platform);
++	int line;
++
++	for (line = 0; (line < nrlines); line++)
++		m5407_uart_init_line(line, m5407_uart_platform[line].irq);
++}
+ 
+ /***************************************************************************/
+ 
+@@ -76,21 +110,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
+ 
+ /***************************************************************************/
+ 
+-int mcf_timerirqpending(int timer)
+-{
+-	unsigned int imr = 0;
+-
+-	switch (timer) {
+-	case 1:  imr = MCFSIM_IMR_TIMER1; break;
+-	case 2:  imr = MCFSIM_IMR_TIMER2; break;
+-	default: break;
+-	}
+-	return (mcf_getipr() & imr);
+-}
+-
+-/***************************************************************************/
+-
+-void config_BSP(char *commandp, int size)
++void __init config_BSP(char *commandp, int size)
+ {
+ 	mcf_setimr(MCFSIM_IMR_MASKALL);
+ 
+@@ -105,3 +125,14 @@ void config_BSP(char *commandp, int size)
+ }
+ 
+ /***************************************************************************/
++
++static int __init init_BSP(void)
++{
++	m5407_uarts_init();
++	platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
++	return 0;
++}
++
++arch_initcall(init_BSP);
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/68328/timers.c b/arch/m68knommu/platform/68328/timers.c
+index 04cbc66..9159fd0 100644
+--- a/arch/m68knommu/platform/68328/timers.c
++++ b/arch/m68knommu/platform/68328/timers.c
+@@ -19,6 +19,7 @@
+ #include <linux/mm.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
++#include <linux/clocksource.h>
+ #include <asm/setup.h>
+ #include <asm/system.h>
+ #include <asm/pgtable.h>
+@@ -51,6 +52,19 @@
+ #define TICKS_PER_JIFFY	10
+ #endif
+ 
++static u32 m68328_tick_cnt;
++
++/***************************************************************************/
++
++static irqreturn_t hw_tick(int irq, void *dummy)
++{
++	/* Reset Timer1 */
++	TSTAT &= 0;
++
++	m68328_tick_cnt += TICKS_PER_JIFFY;
++	return arch_timer_interrupt(irq, dummy);
++}
++
+ /***************************************************************************/
+ 
+ static irqreturn_t hw_tick(int irq, void *dummy)
+@@ -69,6 +83,33 @@ static struct irqaction m68328_timer_irq = {
+ 	.handler = hw_tick,
+ };
+ 
++/***************************************************************************/
++
++static cycle_t m68328_read_clk(void)
++{
++	unsigned long flags;
++	u32 cycles;
++
++	local_irq_save(flags);
++	cycles = m68328_tick_cnt + TCN;
++	local_irq_restore(flags);
++
++	return cycles;
++}
++
++/***************************************************************************/
++
++static struct clocksource m68328_clk = {
++	.name	= "timer",
++	.rating	= 250,
++	.read	= m68328_read_clk,
++	.shift	= 20,
++	.mask	= CLOCKSOURCE_MASK(32),
++	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++/***************************************************************************/
++
+ void hw_timer_init(void)
+ {
+ 	/* disable timer 1 */
+@@ -84,19 +125,8 @@ void hw_timer_init(void)
+ 
+ 	/* Enable timer 1 */
+ 	TCTL |= TCTL_TEN;
+-}
+-
+-/***************************************************************************/
+-
+-unsigned long hw_timer_offset(void)
+-{
+-	unsigned long ticks = TCN, offset = 0;
+-
+-	/* check for pending interrupt */
+-	if (ticks < (TICKS_PER_JIFFY >> 1) && (ISR & (1 << TMR_IRQ_NUM)))
+-		offset = 1000000 / HZ;
+-	ticks = (ticks * 1000000 / HZ) / TICKS_PER_JIFFY;
+-	return ticks + offset;
++	m68328_clk.mult = clocksource_hz2mult(TICKS_PER_JIFFY*HZ, m68328_clk.shift);
++	clocksource_register(&m68328_clk);
+ }
+ 
+ /***************************************************************************/
+diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c
+index 2b3196a..ac629fa 100644
+--- a/arch/m68knommu/platform/68360/config.c
++++ b/arch/m68knommu/platform/68360/config.c
+@@ -103,11 +103,6 @@ void hw_timer_init(void)
+   pquicc->timer_tgcr  = tgcr_save;
+ }
+ 
+-unsigned long hw_timer_offset(void)
+-{
+-  return 0;
+-}
+-
+ void BSP_gettod (int *yearp, int *monp, int *dayp,
+ 		   int *hourp, int *minp, int *secp)
+ {
+diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
+new file mode 100644
+index 0000000..e5fff29
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/Makefile
+@@ -0,0 +1,32 @@
++#
++# Makefile for the m68knommu kernel.
++#
++
++#
++# If you want to play with the HW breakpoints then you will
++# need to add define this,  which will give you a stack backtrace
++# on the console port whenever a DBG interrupt occurs. You have to
++# set up you HW breakpoints to trigger a DBG interrupt:
++#
++# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
++# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
++#
++
++ifdef CONFIG_FULLDEBUG
++AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
++endif
++
++obj-$(CONFIG_COLDFIRE)	+= dma.o entry.o vectors.o
++obj-$(CONFIG_M5206)	+= timers.o
++obj-$(CONFIG_M5206e)	+= timers.o
++obj-$(CONFIG_M520x)	+= pit.o
++obj-$(CONFIG_M523x)	+= pit.o
++obj-$(CONFIG_M5249)	+= timers.o
++obj-$(CONFIG_M527x)	+= pit.o
++obj-$(CONFIG_M5272)	+= timers.o
++obj-$(CONFIG_M528x)	+= pit.o
++obj-$(CONFIG_M5307)	+= timers.o
++obj-$(CONFIG_M532x)	+= timers.o
++obj-$(CONFIG_M5407)	+= timers.o
++
++extra-y := head.o
+diff --git a/arch/m68knommu/platform/coldfire/dma.c b/arch/m68knommu/platform/coldfire/dma.c
+new file mode 100644
+index 0000000..2b30cf1
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/dma.c
+@@ -0,0 +1,39 @@
++/***************************************************************************/
++
++/*
++ *	dma.c -- Freescale ColdFire DMA support
++ *
++ *	Copyright (C) 2007, Greg Ungerer (gerg at snapgear.com)
++ */
++
++/***************************************************************************/
++
++#include <linux/kernel.h>
++#include <asm/dma.h>
++#include <asm/coldfire.h>
++#include <asm/mcfsim.h>
++#include <asm/mcfdma.h>
++
++/***************************************************************************/
++
++/*
++ *      DMA channel base address table.
++ */
++unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
++#ifdef MCFDMA_BASE0
++	MCF_MBAR + MCFDMA_BASE0,
++#endif
++#ifdef MCFDMA_BASE1
++	MCF_MBAR + MCFDMA_BASE1,
++#endif
++#ifdef MCFDMA_BASE2
++	MCF_MBAR + MCFDMA_BASE2,
++#endif
++#ifdef MCFDMA_BASE3
++	MCF_MBAR + MCFDMA_BASE3,
++#endif
++};
++
++unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
+new file mode 100644
+index 0000000..b333731
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/entry.S
+@@ -0,0 +1,235 @@
++/*
++ *  linux/arch/m68knommu/platform/5307/entry.S
++ *
++ *  Copyright (C) 1999-2007, Greg Ungerer (gerg at snapgear.com)
++ *  Copyright (C) 1998  D. Jeff Dionne <jeff at lineo.ca>,
++ *                      Kenneth Albanowski <kjahds at kjahds.com>,
++ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
++ *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
++ *
++ * Based on:
++ *
++ *  linux/arch/m68k/kernel/entry.S
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file README.legal in the main directory of this archive
++ * for more details.
++ *
++ * Linux/m68k support by Hamish Macdonald
++ *
++ * 68060 fixes by Jesper Skov
++ * ColdFire support by Greg Ungerer (gerg at snapgear.com)
++ * 5307 fixes by David W. Miller
++ * linux 2.4 support David McCullough <davidm at snapgear.com>
++ * Bug, speed and maintainability fixes by Philippe De Muyter <phdm at macqel.be>
++ */
++
++#include <linux/sys.h>
++#include <linux/linkage.h>
++#include <asm/unistd.h>
++#include <asm/thread_info.h>
++#include <asm/errno.h>
++#include <asm/setup.h>
++#include <asm/segment.h>
++#include <asm/asm-offsets.h>
++#include <asm/entry.h>
++
++.bss
++
++sw_ksp:
++.long	0
++
++sw_usp:
++.long	0
++
++.text
++
++.globl system_call
++.globl resume
++.globl ret_from_exception
++.globl ret_from_signal
++.globl sys_call_table
++.globl ret_from_interrupt
++.globl inthandler
++.globl fasthandler
++
++enosys:
++	mov.l	#sys_ni_syscall,%d3
++	bra	1f
++
++ENTRY(system_call)
++	SAVE_ALL
++	move	#0x2000,%sr		/* enable intrs again */
++
++	cmpl	#NR_syscalls,%d0
++	jcc	enosys
++	lea	sys_call_table,%a0
++	lsll	#2,%d0			/* movel %a0@(%d0:l:4),%d3 */
++	movel	%a0@(%d0),%d3
++	jeq	enosys
++
++1:
++	movel	%sp,%d2			/* get thread_info pointer */
++	andl	#-THREAD_SIZE,%d2	/* at start of kernel stack */
++	movel	%d2,%a0
++	movel	%a0@,%a1		/* save top of frame */
++	movel	%sp,%a1@(TASK_THREAD+THREAD_ESP0)
++	btst	#(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
++	bnes	1f
++
++	movel	%d3,%a0
++	jbsr	%a0@
++	movel	%d0,%sp@(PT_D0)		/* save the return value */
++	jra	ret_from_exception
++1:
++	movel	#-ENOSYS,%d2		/* strace needs -ENOSYS in PT_D0 */
++	movel	%d2,PT_D0(%sp)		/* on syscall entry */
++	subql	#4,%sp
++	SAVE_SWITCH_STACK
++	jbsr	syscall_trace
++	RESTORE_SWITCH_STACK
++	addql	#4,%sp
++	movel	%d3,%a0
++	jbsr	%a0@
++	movel	%d0,%sp@(PT_D0)		/* save the return value */
++	subql	#4,%sp			/* dummy return address */
++	SAVE_SWITCH_STACK
++	jbsr	syscall_trace
++
++ret_from_signal:
++	RESTORE_SWITCH_STACK
++	addql	#4,%sp
++
++ret_from_exception:
++	btst	#5,%sp@(PT_SR)		/* check if returning to kernel */
++	jeq	Luser_return		/* if so, skip resched, signals */
++
++Lkernel_return:
++	moveml	%sp@,%d1-%d5/%a0-%a2
++	lea	%sp@(32),%sp		/* space for 8 regs */
++	movel	%sp at +,%d0
++	addql	#4,%sp			/* orig d0 */
++	addl	%sp at +,%sp		/* stk adj */
++	rte
++
++Luser_return:
++	movel	%sp,%d1			/* get thread_info pointer */
++	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
++	movel	%d1,%a0
++	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
++	andl	#_TIF_WORK_MASK,%d1
++	jne	Lwork_to_do		/* still work to do */
++
++Lreturn:
++	move	#0x2700,%sr		/* disable intrs */
++	movel	sw_usp,%a0		/* get usp */
++	movel	%sp@(PT_PC),%a0 at -	/* copy exception program counter */
++	movel	%sp@(PT_FORMATVEC),%a0 at -/* copy exception format/vector/sr */
++	moveml	%sp@,%d1-%d5/%a0-%a2
++	lea	%sp@(32),%sp		/* space for 8 regs */
++	movel	%sp at +,%d0
++	addql	#4,%sp			/* orig d0 */
++	addl	%sp at +,%sp		/* stk adj */
++	addql	#8,%sp			/* remove exception */
++	movel	%sp,sw_ksp		/* save ksp */
++	subql	#8,sw_usp		/* set exception */
++	movel	sw_usp,%sp		/* restore usp */
++	rte
++
++Lwork_to_do:
++	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
++	btst	#TIF_NEED_RESCHED,%d1
++	jne	reschedule
++
++	/* GERG: do we need something here for TRACEing?? */
++
++Lsignal_return:
++	subql	#4,%sp			/* dummy return address */
++	SAVE_SWITCH_STACK
++	pea	%sp@(SWITCH_STACK_SIZE)
++	clrl	%sp at -
++	jsr	do_signal
++	addql	#8,%sp
++	RESTORE_SWITCH_STACK
++	addql	#4,%sp
++	jmp	Lreturn
++
++/*
++ * This is the generic interrupt handler (for all hardware interrupt
++ * sources). Calls upto high level code to do all the work.
++ */
++ENTRY(inthandler)
++	SAVE_ALL
++	moveq	#-1,%d0
++	movel	%d0,%sp@(PT_ORIG_D0)
++
++	movew	%sp@(PT_FORMATVEC),%d0	/* put exception # in d0 */
++	andl	#0x03fc,%d0		/* mask out vector only */
++
++	movel	%sp,%sp at -		/* push regs arg */
++	lsrl	#2,%d0			/* calculate real vector # */
++	movel	%d0,%sp at -		/* push vector number */
++	jbsr	do_IRQ			/* call high level irq handler */
++	lea	%sp@(8),%sp		/* pop args off stack */
++
++	bra	ret_from_interrupt	/* this was fallthrough */
++
++/*
++ * This is the fast interrupt handler (for certain hardware interrupt
++ * sources). Unlike the normal interrupt handler it just uses the
++ * current stack (doesn't care if it is user or kernel). It also
++ * doesn't bother doing the bottom half handlers.
++ */
++ENTRY(fasthandler)
++	SAVE_LOCAL
++
++	movew	%sp@(PT_FORMATVEC),%d0
++	andl	#0x03fc,%d0		/* mask out vector only */
++
++	movel	%sp,%sp at -		/* push regs arg */
++	lsrl	#2,%d0			/* calculate real vector # */
++	movel	%d0,%sp at -		/* push vector number */
++	jbsr	do_IRQ			/* call high level irq handler */
++	lea	%sp@(8),%sp		/* pop args off stack */
++
++	RESTORE_LOCAL
++
++ENTRY(ret_from_interrupt)
++	jeq	2f
++1:
++	RESTORE_ALL
++2:
++	moveb	%sp@(PT_SR),%d0
++	andl	#0x7,%d0
++	jhi	1b
++
++	/* check if we need to do software interrupts */
++	movel	irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0
++	jeq	ret_from_exception
++
++	pea	ret_from_exception
++	jmp	do_softirq
++
++/*
++ * Beware - when entering resume, prev (the current task) is
++ * in a0, next (the new task) is in a1,so don't change these
++ * registers until their contents are no longer needed.
++ * This is always called in supervisor mode, so don't bother to save
++ * and restore sr; user's process sr is actually in the stack.
++ */
++ENTRY(resume)
++	movel	%a0, %d1			/* get prev thread in d1 */
++
++	movel	sw_usp,%d0			/* save usp */
++	movel	%d0,%a0@(TASK_THREAD+THREAD_USP)
++
++	SAVE_SWITCH_STACK
++	movel	%sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
++	movel	%a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
++	RESTORE_SWITCH_STACK
++
++	movel	%a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
++	movel	%a0, sw_usp
++	rts
+diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68knommu/platform/coldfire/head.S
+new file mode 100644
+index 0000000..b9aa0ca
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/head.S
+@@ -0,0 +1,222 @@
++/*****************************************************************************/
++
++/*
++ *	head.S -- common startup code for ColdFire CPUs.
++ *
++ *	(C) Copyright 1999-2006, Greg Ungerer <gerg at snapgear.com>.
++ */
++
++/*****************************************************************************/
++
++#include <linux/sys.h>
++#include <linux/linkage.h>
++#include <asm/asm-offsets.h>
++#include <asm/coldfire.h>
++#include <asm/mcfcache.h>
++#include <asm/mcfsim.h>
++
++/*****************************************************************************/
++
++/*
++ *	If we don't have a fixed memory size, then lets build in code
++ *	to auto detect the DRAM size. Obviously this is the prefered
++ *	method, and should work for most boards. It won't work for those
++ *	that do not have their RAM starting at address 0, and it only
++ *	works on SDRAM (not boards fitted with SRAM).
++ */
++#if CONFIG_RAMSIZE != 0
++.macro GET_MEM_SIZE
++	movel	#CONFIG_RAMSIZE,%d0	/* hard coded memory size */
++.endm
++
++#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
++      defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
++      defined(CONFIG_M528x) || defined(CONFIG_M5307) || \
++      defined(CONFIG_M5407)
++/*
++ *	Not all these devices have exactly the same DRAM controller,
++ *	but the DCMR register is virtually identical - give or take
++ *	a couple of bits. The only exception is the 5272 devices, their
++ *	DRAM controller is quite different.
++ */
++.macro GET_MEM_SIZE
++	movel	MCF_MBAR+MCFSIM_DMR0,%d0 /* get mask for 1st bank */
++	btst	#0,%d0			/* check if region enabled */
++	beq	1f
++	andl	#0xfffc0000,%d0
++	beq	1f
++	addl	#0x00040000,%d0		/* convert mask to size */
++1:
++	movel	MCF_MBAR+MCFSIM_DMR1,%d1 /* get mask for 2nd bank */
++	btst	#0,%d1			/* check if region enabled */
++	beq	2f
++	andl	#0xfffc0000, %d1
++	beq	2f
++	addl	#0x00040000,%d1
++	addl	%d1,%d0			/* total mem size in d0 */
++2:
++.endm
++
++#elif defined(CONFIG_M5272)
++.macro GET_MEM_SIZE
++	movel	MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */
++	andil	#0xfffff000,%d0		/* mask out chip select options */
++	negl	%d0			/* negate bits */
++.endm
++
++#elif defined(CONFIG_M520x)
++.macro GET_MEM_SIZE
++	clrl	%d0
++	movel	MCF_MBAR+MCFSIM_SDCS0, %d2 /* Get SDRAM chip select 0 config */
++	andl	#0x1f, %d2		/* Get only the chip select size */
++	beq	3f			/* Check if it is enabled */
++	addql	#1, %d2			/* Form exponent */
++	moveql	#1, %d0
++	lsll	%d2, %d0		/* 2 ^ exponent */
++3:
++	movel	MCF_MBAR+MCFSIM_SDCS1, %d2 /* Get SDRAM chip select 1 config */
++	andl	#0x1f, %d2		/* Get only the chip select size */
++	beq	4f			/* Check if it is enabled */
++	addql	#1, %d2			/* Form exponent */
++	moveql	#1, %d1
++	lsll	%d2, %d1		/* 2 ^ exponent */
++	addl	%d1, %d0		/* Total size of SDRAM in d0 */
++4:
++.endm
++
++#else
++#error "ERROR: I don't know how to probe your boards memory size?"
++#endif
++
++/*****************************************************************************/
++
++/*
++ *	Boards and platforms can do specific early hardware setup if
++ *	they need to. Most don't need this, define away if not required.
++ */
++#ifndef PLATFORM_SETUP
++#define	PLATFORM_SETUP
++#endif
++
++/*****************************************************************************/
++
++.global	_start
++.global _rambase
++.global _ramvec
++.global	_ramstart
++.global	_ramend
++
++/*****************************************************************************/
++
++.data
++
++/*
++ *	During startup we store away the RAM setup. These are not in the
++ *	bss, since their values are determined and written before the bss
++ *	has been cleared.
++ */
++_rambase:
++.long	0
++_ramvec:
++.long	0
++_ramstart:
++.long	0
++_ramend:
++.long	0
++
++/*****************************************************************************/
++
++.text
++
++/*
++ *	This is the codes first entry point. This is where it all
++ *	begins...
++ */
++
++_start:
++	nop					/* filler */
++	movew	#0x2700, %sr			/* no interrupts */
++
++	/*
++	 *	Do any platform or board specific setup now. Most boards
++	 *	don't need anything. Those exceptions are define this in
++	 *	their board specific includes.
++	 */
++	PLATFORM_SETUP
++
++	/*
++	 *	Create basic memory configuration. Set VBR accordingly,
++	 *	and size memory.
++	 */
++	movel	#CONFIG_VECTORBASE,%a7
++	movec   %a7,%VBR			/* set vectors addr */
++	movel	%a7,_ramvec
++
++	movel	#CONFIG_RAMBASE,%a7		/* mark the base of RAM */
++	movel	%a7,_rambase
++
++	GET_MEM_SIZE				/* macro code determines size */
++	addl	%a7,%d0
++	movel	%d0,_ramend			/* set end ram addr */
++
++	/*
++	 *	Now that we know what the memory is, lets enable cache
++	 *	and get things moving. This is Coldfire CPU specific.
++	 */
++	CACHE_ENABLE				/* enable CPU cache */
++
++
++#ifdef CONFIG_ROMFS_FS
++	/*
++	 *	Move ROM filesystem above bss :-)
++	 */
++	lea	_sbss,%a0			/* get start of bss */
++	lea	_ebss,%a1			/* set up destination  */
++	movel	%a0,%a2				/* copy of bss start */
++
++	movel	8(%a0),%d0			/* get size of ROMFS */
++	addql	#8,%d0				/* allow for rounding */
++	andl	#0xfffffffc, %d0		/* whole words */
++
++	addl	%d0,%a0				/* copy from end */
++	addl	%d0,%a1				/* copy from end */
++	movel	%a1,_ramstart			/* set start of ram */
++
++_copy_romfs:
++	movel	-(%a0),%d0			/* copy dword */
++	movel	%d0,-(%a1)
++	cmpl	%a0,%a2				/* check if at end */
++	bne	_copy_romfs
++
++#else /* CONFIG_ROMFS_FS */
++	lea	_ebss,%a1
++	movel	%a1,_ramstart
++#endif /* CONFIG_ROMFS_FS */
++
++
++	/*
++	 *	Zero out the bss region.
++	 */
++	lea	_sbss,%a0			/* get start of bss */
++	lea	_ebss,%a1			/* get end of bss */
++	clrl	%d0				/* set value */
++_clear_bss:
++	movel	%d0,(%a0)+			/* clear each word */
++	cmpl	%a0,%a1				/* check if at end */
++	bne	_clear_bss
++
++	/*
++	 *	Load the current task pointer and stack.
++	 */
++	lea	init_thread_union,%a0
++	lea	THREAD_SIZE(%a0),%sp
++
++	/*
++	 *	Assember start up done, start code proper.
++	 */
++	jsr	start_kernel			/* start Linux kernel */
++
++_exit:
++	jmp	_exit				/* should never get here */
++
++/*****************************************************************************/
+diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c
+new file mode 100644
+index 0000000..4290638
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/pit.c
+@@ -0,0 +1,113 @@
++/***************************************************************************/
++
++/*
++ *	pit.c -- Freescale ColdFire PIT timer. Currently this type of
++ *	         hardware timer only exists in the Freescale ColdFire
++ *		 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
++ *		 family members will probably use it too.
++ *
++ *	Copyright (C) 1999-2008, Greg Ungerer (gerg at snapgear.com)
++ *	Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
++ */
++
++/***************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/param.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/clocksource.h>
++#include <asm/machdep.h>
++#include <asm/io.h>
++#include <asm/coldfire.h>
++#include <asm/mcfpit.h>
++#include <asm/mcfsim.h>
++
++/***************************************************************************/
++
++/*
++ *	By default use timer1 as the system clock timer.
++ */
++#define	FREQ	((MCF_CLK / 2) / 64)
++#define	TA(a)	(MCF_IPSBAR + MCFPIT_BASE1 + (a))
++#define	INTC0	(MCF_IPSBAR + MCFICM_INTC0)
++
++static u32 pit_cycles_per_jiffy;
++static u32 pit_cnt;
++
++/***************************************************************************/
++
++static irqreturn_t pit_tick(int irq, void *dummy)
++{
++	u16 pcsr;
++
++	/* Reset the ColdFire timer */
++	pcsr = __raw_readw(TA(MCFPIT_PCSR));
++	__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
++
++	pit_cnt += pit_cycles_per_jiffy;
++	return arch_timer_interrupt(irq, dummy);
++}
++
++/***************************************************************************/
++
++static struct irqaction pit_irq = {
++	.name	 = "timer",
++	.flags	 = IRQF_DISABLED | IRQF_TIMER,
++	.handler = pit_tick,
++};
++
++/***************************************************************************/
++
++static cycle_t pit_read_clk(void)
++{
++	unsigned long flags;
++	u32 cycles;
++	u16 pcntr;
++
++	local_irq_save(flags);
++	pcntr = __raw_readw(TA(MCFPIT_PCNTR));
++	cycles = pit_cnt;
++	local_irq_restore(flags);
++
++	return cycles + pit_cycles_per_jiffy - pcntr;
++}
++
++/***************************************************************************/
++
++static struct clocksource pit_clk = {
++	.name	= "pit",
++	.rating	= 250,
++	.read	= pit_read_clk,
++	.shift	= 20,
++	.mask	= CLOCKSOURCE_MASK(32),
++	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++/***************************************************************************/
++
++void hw_timer_init(void)
++{
++	u32 imr;
++
++	setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
++
++	__raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1);
++	imr = __raw_readl(INTC0 + MCFPIT_IMR);
++	imr &= ~MCFPIT_IMR_IBIT;
++	__raw_writel(imr, INTC0 + MCFPIT_IMR);
++
++	/* Set up PIT timer 1 as poll clock */
++	pit_cycles_per_jiffy = FREQ / HZ;
++	__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
++	__raw_writew(pit_cycles_per_jiffy, TA(MCFPIT_PMR));
++	__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
++		MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
++
++	pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
++	clocksource_register(&pit_clk);
++}
++
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c
+new file mode 100644
+index 0000000..a60213e
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/timers.c
+@@ -0,0 +1,175 @@
++/***************************************************************************/
++
++/*
++ *	timers.c -- generic ColdFire hardware timer support.
++ *
++ *	Copyright (C) 1999-2008, Greg Ungerer <gerg at snapgear.com>
++ */
++
++/***************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/profile.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/traps.h>
++#include <asm/machdep.h>
++#include <asm/coldfire.h>
++#include <asm/mcftimer.h>
++#include <asm/mcfsim.h>
++
++/***************************************************************************/
++
++/*
++ *	By default use timer1 as the system clock timer.
++ */
++#define	FREQ	(MCF_BUSCLK / 16)
++#define	TA(a)	(MCF_MBAR + MCFTIMER_BASE1 + (a))
++
++/*
++ *	Default the timer and vector to use for ColdFire. Some ColdFire
++ *	CPU's and some boards may want different. Their sub-architecture
++ *	startup code (in config.c) can change these if they want.
++ */
++unsigned int	mcf_timervector = 29;
++unsigned int	mcf_profilevector = 31;
++unsigned int	mcf_timerlevel = 5;
++
++/*
++ *	These provide the underlying interrupt vector support.
++ *	Unfortunately it is a little different on each ColdFire.
++ */
++extern void mcf_settimericr(int timer, int level);
++void coldfire_profile_init(void);
++
++#if defined(CONFIG_M532x)
++#define	__raw_readtrr	__raw_readl
++#define	__raw_writetrr	__raw_writel
++#else
++#define	__raw_readtrr	__raw_readw
++#define	__raw_writetrr	__raw_writew
++#endif
++
++static u32 mcftmr_cycles_per_jiffy;
++static u32 mcftmr_cnt;
++
++/***************************************************************************/
++
++static irqreturn_t mcftmr_tick(int irq, void *dummy)
++{
++	/* Reset the ColdFire timer */
++	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
++
++	mcftmr_cnt += mcftmr_cycles_per_jiffy;
++	return arch_timer_interrupt(irq, dummy);
++}
++
++/***************************************************************************/
++
++static struct irqaction mcftmr_timer_irq = {
++	.name	 = "timer",
++	.flags	 = IRQF_DISABLED | IRQF_TIMER,
++	.handler = mcftmr_tick,
++};
++
++/***************************************************************************/
++
++static cycle_t mcftmr_read_clk(void)
++{
++	unsigned long flags;
++	u32 cycles;
++	u16 tcn;
++
++	local_irq_save(flags);
++	tcn = __raw_readw(TA(MCFTIMER_TCN));
++	cycles = mcftmr_cnt;
++	local_irq_restore(flags);
++
++	return cycles + tcn;
++}
++
++/***************************************************************************/
++
++static struct clocksource mcftmr_clk = {
++	.name	= "tmr",
++	.rating	= 250,
++	.read	= mcftmr_read_clk,
++	.shift	= 20,
++	.mask	= CLOCKSOURCE_MASK(32),
++	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++/***************************************************************************/
++
++void hw_timer_init(void)
++{
++	setup_irq(mcf_timervector, &mcftmr_timer_irq);
++
++	__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
++	mcftmr_cycles_per_jiffy = FREQ / HZ;
++	__raw_writetrr(mcftmr_cycles_per_jiffy, TA(MCFTIMER_TRR));
++	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
++		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
++
++	mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);
++	clocksource_register(&mcftmr_clk);
++
++	mcf_settimericr(1, mcf_timerlevel);
++
++#ifdef CONFIG_HIGHPROFILE
++	coldfire_profile_init();
++#endif
++}
++
++/***************************************************************************/
++#ifdef CONFIG_HIGHPROFILE
++/***************************************************************************/
++
++/*
++ *	By default use timer2 as the profiler clock timer.
++ */
++#define	PA(a)	(MCF_MBAR + MCFTIMER_BASE2 + (a))
++
++/*
++ *	Choose a reasonably fast profile timer. Make it an odd value to
++ *	try and get good coverage of kernel operations.
++ */
++#define	PROFILEHZ	1013
++
++/*
++ *	Use the other timer to provide high accuracy profiling info.
++ */
++irqreturn_t coldfire_profile_tick(int irq, void *dummy)
++{
++	/* Reset ColdFire timer2 */
++	__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
++	if (current->pid)
++		profile_tick(CPU_PROFILING, regs);
++	return IRQ_HANDLED;
++}
++
++/***************************************************************************/
++
++void coldfire_profile_init(void)
++{
++	printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ);
++
++	/* Set up TIMER 2 as high speed profile clock */
++	__raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
++
++	__raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
++	__raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
++		MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
++
++	request_irq(mcf_profilevector, coldfire_profile_tick,
++		(IRQF_DISABLED | IRQ_FLG_FAST), "profile timer", NULL);
++	mcf_settimericr(2, 7);
++}
++
++/***************************************************************************/
++#endif	/* CONFIG_HIGHPROFILE */
++/***************************************************************************/
+diff --git a/arch/m68knommu/platform/coldfire/vectors.c b/arch/m68knommu/platform/coldfire/vectors.c
+new file mode 100644
+index 0000000..6cf8946
+--- /dev/null
++++ b/arch/m68knommu/platform/coldfire/vectors.c
+@@ -0,0 +1,105 @@
++/***************************************************************************/
++
++/*
++ *	linux/arch/m68knommu/platform/5307/vectors.c
++ *
++ *	Copyright (C) 1999-2007, Greg Ungerer <gerg at snapgear.com>
++ */
++
++/***************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <asm/traps.h>
++#include <asm/machdep.h>
++#include <asm/coldfire.h>
++#include <asm/mcfsim.h>
++#include <asm/mcfdma.h>
++#include <asm/mcfwdebug.h>
++
++/***************************************************************************/
++
++#ifdef TRAP_DBG_INTERRUPT
++
++asmlinkage void dbginterrupt_c(struct frame *fp)
++{
++	extern void dump(struct pt_regs *fp);
++	printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
++	dump((struct pt_regs *) fp);
++	asm("halt");
++}
++
++#endif
++
++/***************************************************************************/
++
++extern e_vector	*_ramvec;
++
++void set_evector(int vecnum, void (*handler)(void))
++{
++	if (vecnum >= 0 && vecnum <= 255)
++		_ramvec[vecnum] = handler;
++}
++
++/***************************************************************************/
++
++/* Assembler routines */
++asmlinkage void buserr(void);
++asmlinkage void trap(void);
++asmlinkage void system_call(void);
++asmlinkage void inthandler(void);
++
++void __init init_vectors(void)
++{
++	int i;
++
++	/*
++	 *	There is a common trap handler and common interrupt
++	 *	handler that handle almost every vector. We treat
++	 *	the system call and bus error special, they get their
++	 *	own first level handlers.
++	 */
++	for (i = 3; (i <= 23); i++)
++		_ramvec[i] = trap;
++	for (i = 33; (i <= 63); i++)
++		_ramvec[i] = trap;
++	for (i = 24; (i <= 31); i++)
++		_ramvec[i] = inthandler;
++	for (i = 64; (i < 255); i++)
++		_ramvec[i] = inthandler;
++	_ramvec[255] = 0;
++
++	_ramvec[2] = buserr;
++	_ramvec[32] = system_call;
++
++#ifdef TRAP_DBG_INTERRUPT
++	_ramvec[12] = dbginterrupt;
++#endif
++}
++
++/***************************************************************************/
++
++void enable_vector(unsigned int irq)
++{
++	/* Currently no action on ColdFire */
++}
++
++void disable_vector(unsigned int irq)
++{
++	/* Currently no action on ColdFire */
++}
++
++void ack_vector(unsigned int irq)
++{
++	/* Currently no action on ColdFire */
++}
++
++/***************************************************************************/
++
++void coldfire_reset(void)
++{
++	HARD_RESET_NOW();
++}
++
++/***************************************************************************/
 diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
-index b22c043..4fad0a3 100644
+index b22c043..36a4018 100644
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
 @@ -37,16 +37,6 @@ config BASLER_EXCITE
@@ -65007,7 +70313,19 @@
  config SYS_SUPPORTS_SMP
  	bool
  
-@@ -1978,9 +2019,6 @@ config MMU
+@@ -1920,11 +1961,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, or VESA. If you have PCI,
+ 	  say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config PCI_DOMAINS
+ 	bool
+ 
+@@ -1978,9 +2014,6 @@ config MMU
  config I8253
  	bool
  
@@ -65017,6 +70335,17 @@
  config ZONE_DMA32
  	bool
  
+@@ -2048,6 +2081,10 @@ endmenu
+ 
+ menu "Power management options"
+ 
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on !SMP
++
+ source "kernel/power/Kconfig"
+ 
+ endmenu
 diff --git a/arch/mips/Makefile b/arch/mips/Makefile
 index a1f8d8b..3fb7f30 100644
 --- a/arch/mips/Makefile
@@ -67738,6 +73067,19 @@
  	MTC0	k0, CP0_EPC
  	/* I hope three instructions between MTC0 and ERET are enough... */
  	ori	k1, _THREAD_MASK
+diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
+index 50be56c..a24fb79 100644
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -140,7 +140,7 @@ FEXPORT(__kernel_entry)
+ 	j	kernel_entry
+ #endif
+ 
+-	__INIT_REFOK
++	__REF
+ 
+ NESTED(kernel_entry, 16, sp)			# kernel entry point
+ 
 diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c
 index c2d497c..fc4aa07 100644
 --- a/arch/mips/kernel/i8253.c
@@ -71179,6 +76521,20 @@
 +	.smp_setup		= ssmtc_smp_setup,
 +	.prepare_cpus		= ssmtc_prepare_cpus,
 +};
+diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
+index 32fd5db..c6f832e 100644
+--- a/arch/mips/mm/Makefile
++++ b/arch/mips/mm/Makefile
+@@ -3,7 +3,8 @@
+ #
+ 
+ obj-y				+= cache.o dma-default.o extable.o fault.o \
+-				   init.o pgtable.o tlbex.o tlbex-fault.o
++				   init.o pgtable.o tlbex.o tlbex-fault.o \
++				   uasm.o
+ 
+ obj-$(CONFIG_32BIT)		+= ioremap.o pgtable-32.o
+ obj-$(CONFIG_64BIT)		+= pgtable-64.o
 diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
 index 9355f1c..02bd180 100644
 --- a/arch/mips/mm/c-r4k.c
@@ -71370,19 +76726,21 @@
  
  static inline void build_bne(unsigned int *dest)
 diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
-index a61246d..d026302 100644
+index a61246d..218a6cc 100644
 --- a/arch/mips/mm/tlbex.c
 +++ b/arch/mips/mm/tlbex.c
-@@ -6,7 +6,7 @@
+@@ -5,8 +5,8 @@
+  *
   * Synthesize TLB refill handlers at runtime.
   *
-  * Copyright (C) 2004,2005,2006 by Thiemo Seufer
+- * Copyright (C) 2004,2005,2006 by Thiemo Seufer
 - * Copyright (C) 2005  Maciej W. Rozycki
++ * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
 + * Copyright (C) 2005, 2007  Maciej W. Rozycki
   * Copyright (C) 2006  Ralf Baechle (ralf at linux-mips.org)
   *
   * ... and the days got worse and worse and now you see
-@@ -19,20 +19,15 @@
+@@ -19,22 +19,16 @@
   * (Condolences to Napoleon XIV)
   */
  
@@ -71396,15 +76754,18 @@
  
 -#include <asm/pgtable.h>
 -#include <asm/cacheflush.h>
-+#include <asm/bugs.h>
  #include <asm/mmu_context.h>
- #include <asm/inst.h>
- #include <asm/elf.h>
+-#include <asm/inst.h>
+-#include <asm/elf.h>
 -#include <asm/smp.h>
  #include <asm/war.h>
  
++#include "uasm.h"
++
  static inline int r45k_bvahwbug(void)
-@@ -66,7 +61,7 @@ static inline int __maybe_unused r10000_llsc_war(void)
+ {
+ 	/* XXX: We should probe for the presence of this bug, but we don't. */
+@@ -66,377 +60,15 @@ static inline int __maybe_unused r10000_llsc_war(void)
   * why; it's not an issue caused by the core RTL.
   *
   */
@@ -71413,370 +76774,678 @@
  {
  	return (current_cpu_data.processor_id & 0xffff00) ==
  	       (PRID_COMP_MIPS | PRID_IMP_4KC);
-@@ -140,7 +135,7 @@ struct insn {
- 	 | (e) << RE_SH						\
- 	 | (f) << FUNC_SH)
+ }
  
+-/*
+- * A little micro-assembler, intended for TLB refill handler
+- * synthesizing. It is intentionally kept simple, does only support
+- * a subset of instructions, and does not try to hide pipeline effects
+- * like branch delay slots.
+- */
+-
+-enum fields
+-{
+-	RS = 0x001,
+-	RT = 0x002,
+-	RD = 0x004,
+-	RE = 0x008,
+-	SIMM = 0x010,
+-	UIMM = 0x020,
+-	BIMM = 0x040,
+-	JIMM = 0x080,
+-	FUNC = 0x100,
+-	SET = 0x200
+-};
+-
+-#define OP_MASK		0x3f
+-#define OP_SH		26
+-#define RS_MASK		0x1f
+-#define RS_SH		21
+-#define RT_MASK		0x1f
+-#define RT_SH		16
+-#define RD_MASK		0x1f
+-#define RD_SH		11
+-#define RE_MASK		0x1f
+-#define RE_SH		6
+-#define IMM_MASK	0xffff
+-#define IMM_SH		0
+-#define JIMM_MASK	0x3ffffff
+-#define JIMM_SH		0
+-#define FUNC_MASK	0x3f
+-#define FUNC_SH		0
+-#define SET_MASK	0x7
+-#define SET_SH		0
+-
+-enum opcode {
+-	insn_invalid,
+-	insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
+-	insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+-	insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
+-	insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
+-	insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
+-	insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
+-	insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
+-	insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
+-	insn_tlbwr, insn_xor, insn_xori
+-};
+-
+-struct insn {
+-	enum opcode opcode;
+-	u32 match;
+-	enum fields fields;
+-};
+-
+-/* This macro sets the non-variable bits of an instruction. */
+-#define M(a, b, c, d, e, f)					\
+-	((a) << OP_SH						\
+-	 | (b) << RS_SH						\
+-	 | (c) << RT_SH						\
+-	 | (d) << RD_SH						\
+-	 | (e) << RE_SH						\
+-	 | (f) << FUNC_SH)
+-
 -static __initdata struct insn insn_table[] = {
-+static struct insn insn_table[] __initdata = {
- 	{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- 	{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
- 	{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
-@@ -193,7 +188,7 @@ static __initdata struct insn insn_table[] = {
- 
- #undef M
- 
+-	{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+-	{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
+-	{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
+-	{ insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+-	{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+-	{ insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+-	{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
+-	{ insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
+-	{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
+-	{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
+-	{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+-	{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+-	{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
+-	{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
+-	{ insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
+-	{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
+-	{ insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
+-	{ insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
+-	{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
+-	{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
+-	{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
+-	{ insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
+-	{ insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
+-	{ insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
+-	{ insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
+-	{ insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
+-	{ insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
+-	{ insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
+-	{ insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+-	{ insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
+-	{ insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
+-	{ insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
+-	{ insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
+-	{ insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
+-	{ insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+-	{ insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
+-	{ insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
+-	{ insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
+-	{ insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
+-	{ insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+-	{ insn_invalid, 0, 0 }
+-};
+-
+-#undef M
+-
 -static __init u32 build_rs(u32 arg)
-+static u32 __init build_rs(u32 arg)
- {
- 	if (arg & ~RS_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -201,7 +196,7 @@ static __init u32 build_rs(u32 arg)
- 	return (arg & RS_MASK) << RS_SH;
- }
- 
+-{
+-	if (arg & ~RS_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return (arg & RS_MASK) << RS_SH;
+-}
+-
 -static __init u32 build_rt(u32 arg)
-+static u32 __init build_rt(u32 arg)
- {
- 	if (arg & ~RT_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -209,7 +204,7 @@ static __init u32 build_rt(u32 arg)
- 	return (arg & RT_MASK) << RT_SH;
- }
- 
+-{
+-	if (arg & ~RT_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return (arg & RT_MASK) << RT_SH;
+-}
+-
 -static __init u32 build_rd(u32 arg)
-+static u32 __init build_rd(u32 arg)
- {
- 	if (arg & ~RD_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -217,7 +212,7 @@ static __init u32 build_rd(u32 arg)
- 	return (arg & RD_MASK) << RD_SH;
- }
- 
+-{
+-	if (arg & ~RD_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return (arg & RD_MASK) << RD_SH;
+-}
+-
 -static __init u32 build_re(u32 arg)
-+static u32 __init build_re(u32 arg)
- {
- 	if (arg & ~RE_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -225,7 +220,7 @@ static __init u32 build_re(u32 arg)
- 	return (arg & RE_MASK) << RE_SH;
- }
- 
+-{
+-	if (arg & ~RE_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return (arg & RE_MASK) << RE_SH;
+-}
+-
 -static __init u32 build_simm(s32 arg)
-+static u32 __init build_simm(s32 arg)
- {
- 	if (arg > 0x7fff || arg < -0x8000)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -233,7 +228,7 @@ static __init u32 build_simm(s32 arg)
- 	return arg & 0xffff;
- }
- 
+-{
+-	if (arg > 0x7fff || arg < -0x8000)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return arg & 0xffff;
+-}
+-
 -static __init u32 build_uimm(u32 arg)
-+static u32 __init build_uimm(u32 arg)
- {
- 	if (arg & ~IMM_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -241,7 +236,7 @@ static __init u32 build_uimm(u32 arg)
- 	return arg & IMM_MASK;
- }
- 
+-{
+-	if (arg & ~IMM_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return arg & IMM_MASK;
+-}
+-
 -static __init u32 build_bimm(s32 arg)
-+static u32 __init build_bimm(s32 arg)
- {
- 	if (arg > 0x1ffff || arg < -0x20000)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -252,7 +247,7 @@ static __init u32 build_bimm(s32 arg)
- 	return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
- }
- 
+-{
+-	if (arg > 0x1ffff || arg < -0x20000)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	if (arg & 0x3)
+-		printk(KERN_WARNING "Invalid TLB synthesizer branch target\n");
+-
+-	return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
+-}
+-
 -static __init u32 build_jimm(u32 arg)
-+static u32 __init build_jimm(u32 arg)
- {
- 	if (arg & ~((JIMM_MASK) << 2))
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -260,7 +255,7 @@ static __init u32 build_jimm(u32 arg)
- 	return (arg >> 2) & JIMM_MASK;
- }
- 
+-{
+-	if (arg & ~((JIMM_MASK) << 2))
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return (arg >> 2) & JIMM_MASK;
+-}
+-
 -static __init u32 build_func(u32 arg)
-+static u32 __init build_func(u32 arg)
- {
- 	if (arg & ~FUNC_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -268,7 +263,7 @@ static __init u32 build_func(u32 arg)
- 	return arg & FUNC_MASK;
- }
- 
+-{
+-	if (arg & ~FUNC_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return arg & FUNC_MASK;
+-}
+-
 -static __init u32 build_set(u32 arg)
-+static u32 __init build_set(u32 arg)
- {
- 	if (arg & ~SET_MASK)
- 		printk(KERN_WARNING "TLB synthesizer field overflow\n");
-@@ -293,7 +288,7 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
- 			break;
- 		}
- 
+-{
+-	if (arg & ~SET_MASK)
+-		printk(KERN_WARNING "TLB synthesizer field overflow\n");
+-
+-	return arg & SET_MASK;
+-}
+-
+-/*
+- * The order of opcode arguments is implicitly left to right,
+- * starting with RS and ending with FUNC or IMM.
+- */
+-static void __init build_insn(u32 **buf, enum opcode opc, ...)
+-{
+-	struct insn *ip = NULL;
+-	unsigned int i;
+-	va_list ap;
+-	u32 op;
+-
+-	for (i = 0; insn_table[i].opcode != insn_invalid; i++)
+-		if (insn_table[i].opcode == opc) {
+-			ip = &insn_table[i];
+-			break;
+-		}
+-
 -	if (!ip)
-+	if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
- 		panic("Unsupported TLB synthesizer instruction %d", opc);
- 
- 	op = ip->match;
-@@ -315,69 +310,69 @@ static void __init build_insn(u32 **buf, enum opcode opc, ...)
- }
- 
- #define I_u1u2u3(op)						\
+-		panic("Unsupported TLB synthesizer instruction %d", opc);
+-
+-	op = ip->match;
+-	va_start(ap, opc);
+-	if (ip->fields & RS) op |= build_rs(va_arg(ap, u32));
+-	if (ip->fields & RT) op |= build_rt(va_arg(ap, u32));
+-	if (ip->fields & RD) op |= build_rd(va_arg(ap, u32));
+-	if (ip->fields & RE) op |= build_re(va_arg(ap, u32));
+-	if (ip->fields & SIMM) op |= build_simm(va_arg(ap, s32));
+-	if (ip->fields & UIMM) op |= build_uimm(va_arg(ap, u32));
+-	if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
+-	if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
+-	if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
+-	if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
+-	va_end(ap);
+-
+-	**buf = op;
+-	(*buf)++;
+-}
+-
+-#define I_u1u2u3(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b, unsigned int c)			\
- 	{							\
- 		build_insn(buf, insn##op, a, b, c);		\
- 	}
- 
- #define I_u2u1u3(op)						\
+-	 	unsigned int b, unsigned int c)			\
+-	{							\
+-		build_insn(buf, insn##op, a, b, c);		\
+-	}
+-
+-#define I_u2u1u3(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b, unsigned int c)			\
- 	{							\
- 		build_insn(buf, insn##op, b, a, c);		\
- 	}
- 
- #define I_u3u1u2(op)						\
+-	 	unsigned int b, unsigned int c)			\
+-	{							\
+-		build_insn(buf, insn##op, b, a, c);		\
+-	}
+-
+-#define I_u3u1u2(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b, unsigned int c)			\
- 	{							\
- 		build_insn(buf, insn##op, b, c, a);		\
- 	}
- 
- #define I_u1u2s3(op)						\
+-	 	unsigned int b, unsigned int c)			\
+-	{							\
+-		build_insn(buf, insn##op, b, c, a);		\
+-	}
+-
+-#define I_u1u2s3(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b, signed int c)			\
- 	{							\
- 		build_insn(buf, insn##op, a, b, c);		\
- 	}
- 
- #define I_u2s3u1(op)						\
+-	 	unsigned int b, signed int c)			\
+-	{							\
+-		build_insn(buf, insn##op, a, b, c);		\
+-	}
+-
+-#define I_u2s3u1(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	signed int b, unsigned int c)			\
- 	{							\
- 		build_insn(buf, insn##op, c, a, b);		\
- 	}
- 
- #define I_u2u1s3(op)						\
+-	 	signed int b, unsigned int c)			\
+-	{							\
+-		build_insn(buf, insn##op, c, a, b);		\
+-	}
+-
+-#define I_u2u1s3(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b, signed int c)			\
- 	{							\
- 		build_insn(buf, insn##op, b, a, c);		\
- 	}
- 
- #define I_u1u2(op)						\
+-	 	unsigned int b, signed int c)			\
+-	{							\
+-		build_insn(buf, insn##op, b, a, c);		\
+-	}
+-
+-#define I_u1u2(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	unsigned int b)					\
- 	{							\
- 		build_insn(buf, insn##op, a, b);		\
- 	}
- 
- #define I_u1s2(op)						\
+-	 	unsigned int b)					\
+-	{							\
+-		build_insn(buf, insn##op, a, b);		\
+-	}
+-
+-#define I_u1s2(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a,	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- 	 	signed int b)					\
- 	{							\
- 		build_insn(buf, insn##op, a, b);		\
- 	}
- 
- #define I_u1(op)						\
+-	 	signed int b)					\
+-	{							\
+-		build_insn(buf, insn##op, a, b);		\
+-	}
+-
+-#define I_u1(op)						\
 -	static inline void __init i##op(u32 **buf, unsigned int a)	\
-+	static void __init __maybe_unused i##op(u32 **buf, unsigned int a) \
- 	{							\
- 		build_insn(buf, insn##op, a);			\
- 	}
- 
- #define I_0(op)							\
+-	{							\
+-		build_insn(buf, insn##op, a);			\
+-	}
+-
+-#define I_0(op)							\
 -	static inline void __init i##op(u32 **buf)		\
-+	static void __init __maybe_unused i##op(u32 **buf)	\
- 	{							\
- 		build_insn(buf, insn##op);			\
- 	}
-@@ -457,7 +452,7 @@ struct label {
- 	enum label_id lab;
- };
- 
+-	{							\
+-		build_insn(buf, insn##op);			\
+-	}
+-
+-I_u2u1s3(_addiu);
+-I_u3u1u2(_addu);
+-I_u2u1u3(_andi);
+-I_u3u1u2(_and);
+-I_u1u2s3(_beq);
+-I_u1u2s3(_beql);
+-I_u1s2(_bgez);
+-I_u1s2(_bgezl);
+-I_u1s2(_bltz);
+-I_u1s2(_bltzl);
+-I_u1u2s3(_bne);
+-I_u1u2u3(_dmfc0);
+-I_u1u2u3(_dmtc0);
+-I_u2u1s3(_daddiu);
+-I_u3u1u2(_daddu);
+-I_u2u1u3(_dsll);
+-I_u2u1u3(_dsll32);
+-I_u2u1u3(_dsra);
+-I_u2u1u3(_dsrl);
+-I_u2u1u3(_dsrl32);
+-I_u3u1u2(_dsubu);
+-I_0(_eret);
+-I_u1(_j);
+-I_u1(_jal);
+-I_u1(_jr);
+-I_u2s3u1(_ld);
+-I_u2s3u1(_ll);
+-I_u2s3u1(_lld);
+-I_u1s2(_lui);
+-I_u2s3u1(_lw);
+-I_u1u2u3(_mfc0);
+-I_u1u2u3(_mtc0);
+-I_u2u1u3(_ori);
+-I_0(_rfe);
+-I_u2s3u1(_sc);
+-I_u2s3u1(_scd);
+-I_u2s3u1(_sd);
+-I_u2u1u3(_sll);
+-I_u2u1u3(_sra);
+-I_u2u1u3(_srl);
+-I_u3u1u2(_subu);
+-I_u2s3u1(_sw);
+-I_0(_tlbp);
+-I_0(_tlbwi);
+-I_0(_tlbwr);
+-I_u3u1u2(_xor)
+-I_u2u1u3(_xori);
+-
+-/*
+- * handling labels
+- */
+-
++/* Handle labels (which must be positive integers). */
+ enum label_id {
+-	label_invalid,
+-	label_second_part,
++	label_second_part = 1,
+ 	label_leave,
+ #ifdef MODULE_START
+ 	label_module_alloc,
+@@ -452,266 +84,35 @@ enum label_id {
+ 	label_r3000_write_probe_fail,
+ };
+ 
+-struct label {
+-	u32 *addr;
+-	enum label_id lab;
+-};
+-
 -static __init void build_label(struct label **lab, u32 *addr,
-+static void __init build_label(struct label **lab, u32 *addr,
- 			       enum label_id l)
- {
- 	(*lab)->addr = addr;
-@@ -466,7 +461,7 @@ static __init void build_label(struct label **lab, u32 *addr,
- }
- 
- #define L_LA(lb)						\
+-			       enum label_id l)
+-{
+-	(*lab)->addr = addr;
+-	(*lab)->lab = l;
+-	(*lab)++;
+-}
+-
+-#define L_LA(lb)						\
 -	static inline void l##lb(struct label **lab, u32 *addr) \
-+	static inline void __init l##lb(struct label **lab, u32 *addr) \
- 	{							\
- 		build_label(lab, addr, label##lb);		\
- 	}
-@@ -525,37 +520,46 @@ L_LA(_r3000_write_probe_fail)
- #define i_ssnop(buf) i_sll(buf, 0, 0, 1)
- #define i_ehb(buf) i_sll(buf, 0, 0, 3)
- 
+-	{							\
+-		build_label(lab, addr, label##lb);		\
+-	}
+-
+-L_LA(_second_part)
+-L_LA(_leave)
++UASM_L_LA(_second_part)
++UASM_L_LA(_leave)
+ #ifdef MODULE_START
+-L_LA(_module_alloc)
+-#endif
+-L_LA(_vmalloc)
+-L_LA(_vmalloc_done)
+-L_LA(_tlbw_hazard)
+-L_LA(_split)
+-L_LA(_nopage_tlbl)
+-L_LA(_nopage_tlbs)
+-L_LA(_nopage_tlbm)
+-L_LA(_smp_pgtable_change)
+-L_LA(_r3000_write_probe_fail)
+-
+-/* convenience macros for instructions */
+-#ifdef CONFIG_64BIT
+-# define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
+-# define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
+-# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
+-# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
+-# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
+-# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
+-# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
+-# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
+-# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
+-# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
+-# define i_LL(buf, rs, rt, off) i_lld(buf, rs, rt, off)
+-# define i_SC(buf, rs, rt, off) i_scd(buf, rs, rt, off)
+-#else
+-# define i_LW(buf, rs, rt, off) i_lw(buf, rs, rt, off)
+-# define i_SW(buf, rs, rt, off) i_sw(buf, rs, rt, off)
+-# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
+-# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
+-# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
+-# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
+-# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
+-# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
+-# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
+-# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
+-# define i_LL(buf, rs, rt, off) i_ll(buf, rs, rt, off)
+-# define i_SC(buf, rs, rt, off) i_sc(buf, rs, rt, off)
+-#endif
+-
+-#define i_b(buf, off) i_beq(buf, 0, 0, off)
+-#define i_beqz(buf, rs, off) i_beq(buf, rs, 0, off)
+-#define i_beqzl(buf, rs, off) i_beql(buf, rs, 0, off)
+-#define i_bnez(buf, rs, off) i_bne(buf, rs, 0, off)
+-#define i_bnezl(buf, rs, off) i_bnel(buf, rs, 0, off)
+-#define i_move(buf, a, b) i_ADDU(buf, a, 0, b)
+-#define i_nop(buf) i_sll(buf, 0, 0, 0)
+-#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
+-#define i_ehb(buf) i_sll(buf, 0, 0, 3)
+-
 -#ifdef CONFIG_64BIT
 -static __init int __maybe_unused in_compat_space_p(long addr)
-+static int __init __maybe_unused in_compat_space_p(long addr)
- {
- 	/* Is this address in 32bit compat space? */
-+#ifdef CONFIG_64BIT
- 	return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
-+#else
-+	return 1;
-+#endif
- }
- 
+-{
+-	/* Is this address in 32bit compat space? */
+-	return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
+-}
+-
 -static __init int __maybe_unused rel_highest(long val)
-+static int __init __maybe_unused rel_highest(long val)
- {
-+#ifdef CONFIG_64BIT
- 	return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
-+#else
-+	return 0;
-+#endif
- }
- 
+-{
+-	return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
+-}
+-
 -static __init int __maybe_unused rel_higher(long val)
-+static int __init __maybe_unused rel_higher(long val)
- {
-+#ifdef CONFIG_64BIT
- 	return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
+-{
+-	return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
 -}
-+#else
-+	return 0;
- #endif
-+}
- 
+-#endif
+-
 -static __init int rel_hi(long val)
-+static int __init rel_hi(long val)
- {
- 	return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
- }
- 
+-{
+-	return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
+-}
+-
 -static __init int rel_lo(long val)
-+static int __init rel_lo(long val)
- {
- 	return ((val & 0xffff) ^ 0x8000) - 0x8000;
- }
- 
+-{
+-	return ((val & 0xffff) ^ 0x8000) - 0x8000;
+-}
+-
 -static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
-+static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
- {
+-{
 -#ifdef CONFIG_64BIT
- 	if (!in_compat_space_p(addr)) {
- 		i_lui(buf, rs, rel_highest(addr));
- 		if (rel_higher(addr))
-@@ -567,16 +571,18 @@ static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
- 		} else
- 			i_dsll32(buf, rs, rs, 0);
- 	} else
--#endif
- 		i_lui(buf, rs, rel_hi(addr));
- }
- 
+-	if (!in_compat_space_p(addr)) {
+-		i_lui(buf, rs, rel_highest(addr));
+-		if (rel_higher(addr))
+-			i_daddiu(buf, rs, rs, rel_higher(addr));
+-		if (rel_hi(addr)) {
+-			i_dsll(buf, rs, rs, 16);
+-			i_daddiu(buf, rs, rs, rel_hi(addr));
+-			i_dsll(buf, rs, rs, 16);
+-		} else
+-			i_dsll32(buf, rs, rs, 0);
+-	} else
++UASM_L_LA(_module_alloc)
+ #endif
+-		i_lui(buf, rs, rel_hi(addr));
+-}
+-
 -static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs,
 -					     long addr)
-+static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs, long addr)
- {
- 	i_LA_mostly(buf, rs, addr);
+-{
+-	i_LA_mostly(buf, rs, addr);
 -	if (rel_lo(addr))
 -		i_ADDIU(buf, rs, rs, rel_lo(addr));
-+	if (rel_lo(addr)) {
-+		if (!in_compat_space_p(addr))
-+			i_daddiu(buf, rs, rs, rel_lo(addr));
-+		else
-+			i_addiu(buf, rs, rs, rel_lo(addr));
-+	}
- }
+-}
++UASM_L_LA(_vmalloc)
++UASM_L_LA(_vmalloc_done)
++UASM_L_LA(_tlbw_hazard)
++UASM_L_LA(_split)
++UASM_L_LA(_nopage_tlbl)
++UASM_L_LA(_nopage_tlbs)
++UASM_L_LA(_nopage_tlbm)
++UASM_L_LA(_smp_pgtable_change)
++UASM_L_LA(_r3000_write_probe_fail)
  
  /*
-@@ -589,7 +595,7 @@ struct reloc {
- 	enum label_id lab;
- };
- 
+- * handle relocations
++ * For debug purposes.
+  */
+-
+-struct reloc {
+-	u32 *addr;
+-	unsigned int type;
+-	enum label_id lab;
+-};
+-
 -static __init void r_mips_pc16(struct reloc **rel, u32 *addr,
-+static void __init r_mips_pc16(struct reloc **rel, u32 *addr,
- 			       enum label_id l)
- {
- 	(*rel)->addr = addr;
-@@ -614,7 +620,7 @@ static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
- 	}
- }
- 
+-			       enum label_id l)
+-{
+-	(*rel)->addr = addr;
+-	(*rel)->type = R_MIPS_PC16;
+-	(*rel)->lab = l;
+-	(*rel)++;
+-}
+-
+-static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
+-{
+-	long laddr = (long)lab->addr;
+-	long raddr = (long)rel->addr;
+-
+-	switch (rel->type) {
+-	case R_MIPS_PC16:
+-		*rel->addr |= build_bimm(laddr - (raddr + 4));
+-		break;
+-
+-	default:
+-		panic("Unsupported TLB synthesizer relocation %d",
+-		      rel->type);
+-	}
+-}
+-
 -static __init void resolve_relocs(struct reloc *rel, struct label *lab)
-+static void __init resolve_relocs(struct reloc *rel, struct label *lab)
++static inline void dump_handler(const u32 *handler, int count)
  {
- 	struct label *l;
- 
-@@ -624,7 +630,7 @@ static __init void resolve_relocs(struct reloc *rel, struct label *lab)
- 				__resolve_relocs(rel, l);
- }
- 
+-	struct label *l;
+-
+-	for (; rel->lab != label_invalid; rel++)
+-		for (l = lab; l->lab != label_invalid; l++)
+-			if (rel->lab == l->lab)
+-				__resolve_relocs(rel, l);
+-}
+-
 -static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end,
-+static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
- 			       long off)
- {
- 	for (; rel->lab != label_invalid; rel++)
-@@ -632,7 +638,7 @@ static __init void move_relocs(struct reloc *rel, u32 *first, u32 *end,
- 			rel->addr += off;
- }
- 
+-			       long off)
+-{
+-	for (; rel->lab != label_invalid; rel++)
+-		if (rel->addr >= first && rel->addr < end)
+-			rel->addr += off;
+-}
+-
 -static __init void move_labels(struct label *lab, u32 *first, u32 *end,
-+static void __init move_labels(struct label *lab, u32 *first, u32 *end,
- 			       long off)
- {
- 	for (; lab->lab != label_invalid; lab++)
-@@ -640,7 +646,7 @@ static __init void move_labels(struct label *lab, u32 *first, u32 *end,
- 			lab->addr += off;
- }
- 
+-			       long off)
+-{
+-	for (; lab->lab != label_invalid; lab++)
+-		if (lab->addr >= first && lab->addr < end)
+-			lab->addr += off;
+-}
+-
 -static __init void copy_handler(struct reloc *rel, struct label *lab,
-+static void __init copy_handler(struct reloc *rel, struct label *lab,
- 				u32 *first, u32 *end, u32 *target)
- {
- 	long off = (long)(target - first);
-@@ -651,7 +657,7 @@ static __init void copy_handler(struct reloc *rel, struct label *lab,
- 	move_labels(lab, first, end, off);
- }
- 
+-				u32 *first, u32 *end, u32 *target)
+-{
+-	long off = (long)(target - first);
+-
+-	memcpy(target, first, (end - first) * sizeof(u32));
+-
+-	move_relocs(rel, first, end, off);
+-	move_labels(lab, first, end, off);
+-}
+-
 -static __init int __maybe_unused insn_has_bdelay(struct reloc *rel,
-+static int __init __maybe_unused insn_has_bdelay(struct reloc *rel,
- 						       u32 *addr)
- {
- 	for (; rel->lab != label_invalid; rel++) {
-@@ -714,6 +720,22 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
- 	i_bgez(p, reg, 0);
- }
- 
-+/*
-+ * For debug purposes.
-+ */
-+static inline void dump_handler(const u32 *handler, int count)
-+{
+-						       u32 *addr)
+-{
+-	for (; rel->lab != label_invalid; rel++) {
+-		if (rel->addr == addr
+-		    && (rel->type == R_MIPS_PC16
+-			|| rel->type == R_MIPS_26))
+-			return 1;
+-	}
+-
+-	return 0;
+-}
+-
+-/* convenience functions for labeled branches */
+-static void __init __maybe_unused
+-	il_bltz(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_bltz(p, reg, 0);
+-}
+-
+-static void __init __maybe_unused il_b(u32 **p, struct reloc **r,
+-					     enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_b(p, 0);
+-}
+-
+-static void __init il_beqz(u32 **p, struct reloc **r, unsigned int reg,
+-		    enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_beqz(p, reg, 0);
+-}
 +	int i;
-+
+ 
+-static void __init __maybe_unused
+-il_beqzl(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_beqzl(p, reg, 0);
+-}
 +	pr_debug("\t.set push\n");
 +	pr_debug("\t.set noreorder\n");
-+
+ 
+-static void __init il_bnez(u32 **p, struct reloc **r, unsigned int reg,
+-		    enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_bnez(p, reg, 0);
+-}
 +	for (i = 0; i < count; i++)
 +		pr_debug("\t%p\t.word 0x%08x\n", &handler[i], handler[i]);
-+
+ 
+-static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
+-		     enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_bgezl(p, reg, 0);
+-}
+-
+-static void __init __maybe_unused
+-il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
+-{
+-	r_mips_pc16(r, *p, l);
+-	i_bgez(p, reg, 0);
 +	pr_debug("\t.set pop\n");
-+}
-+
+ }
+ 
  /* The only general purpose registers allowed in TLB handlers. */
- #define K0		26
- #define K1		27
-@@ -743,11 +765,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
+@@ -730,9 +131,9 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
+ #define C0_XCONTEXT	20, 0
+ 
+ #ifdef CONFIG_64BIT
+-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
++# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_XCONTEXT)
+ #else
+-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
++# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_CONTEXT)
+ #endif
+ 
+ /* The worst case length of the handler is around 18 instructions for
+@@ -743,11 +144,11 @@ il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
   * We deliberately chose a buffer size of 128, so we won't scribble
   * over anything important on overflow before we panic.
   */
@@ -71786,12 +77455,12 @@
  /* simply assume worst case size for labels and relocs */
 -static __initdata struct label labels[128];
 -static __initdata struct reloc relocs[128];
-+static struct label labels[128] __initdata;
-+static struct reloc relocs[128] __initdata;
++static struct uasm_label labels[128] __initdata;
++static struct uasm_reloc relocs[128] __initdata;
  
  /*
   * The R3000 TLB handler is simple.
-@@ -756,7 +778,6 @@ static void __init build_r3000_tlb_refill_handler(void)
+@@ -756,42 +157,37 @@ static void __init build_r3000_tlb_refill_handler(void)
  {
  	long pgdc = (long)pgd_current;
  	u32 *p;
@@ -71799,23 +77468,63 @@
  
  	memset(tlb_handler, 0, sizeof(tlb_handler));
  	p = tlb_handler;
-@@ -785,13 +806,9 @@ static void __init build_r3000_tlb_refill_handler(void)
- 	pr_info("Synthesized TLB refill handler (%u instructions).\n",
- 		(unsigned int)(p - tlb_handler));
  
+-	i_mfc0(&p, K0, C0_BADVADDR);
+-	i_lui(&p, K1, rel_hi(pgdc)); /* cp0 delay */
+-	i_lw(&p, K1, rel_lo(pgdc), K1);
+-	i_srl(&p, K0, K0, 22); /* load delay */
+-	i_sll(&p, K0, K0, 2);
+-	i_addu(&p, K1, K1, K0);
+-	i_mfc0(&p, K0, C0_CONTEXT);
+-	i_lw(&p, K1, 0, K1); /* cp0 delay */
+-	i_andi(&p, K0, K0, 0xffc); /* load delay */
+-	i_addu(&p, K1, K1, K0);
+-	i_lw(&p, K0, 0, K1);
+-	i_nop(&p); /* load delay */
+-	i_mtc0(&p, K0, C0_ENTRYLO0);
+-	i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
+-	i_tlbwr(&p); /* cp0 delay */
+-	i_jr(&p, K1);
+-	i_rfe(&p); /* branch delay */
++	uasm_i_mfc0(&p, K0, C0_BADVADDR);
++	uasm_i_lui(&p, K1, uasm_rel_hi(pgdc)); /* cp0 delay */
++	uasm_i_lw(&p, K1, uasm_rel_lo(pgdc), K1);
++	uasm_i_srl(&p, K0, K0, 22); /* load delay */
++	uasm_i_sll(&p, K0, K0, 2);
++	uasm_i_addu(&p, K1, K1, K0);
++	uasm_i_mfc0(&p, K0, C0_CONTEXT);
++	uasm_i_lw(&p, K1, 0, K1); /* cp0 delay */
++	uasm_i_andi(&p, K0, K0, 0xffc); /* load delay */
++	uasm_i_addu(&p, K1, K1, K0);
++	uasm_i_lw(&p, K0, 0, K1);
++	uasm_i_nop(&p); /* load delay */
++	uasm_i_mtc0(&p, K0, C0_ENTRYLO0);
++	uasm_i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
++	uasm_i_tlbwr(&p); /* cp0 delay */
++	uasm_i_jr(&p, K1);
++	uasm_i_rfe(&p); /* branch delay */
+ 
+ 	if (p > tlb_handler + 32)
+ 		panic("TLB refill handler space exceeded");
+ 
+-	pr_info("Synthesized TLB refill handler (%u instructions).\n",
+-		(unsigned int)(p - tlb_handler));
+-
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
 -	for (i = 0; i < (p - tlb_handler); i++)
 -		pr_debug("\t.word 0x%08x\n", tlb_handler[i]);
 -	pr_debug("\t.set pop\n");
--
++	pr_debug("Wrote TLB refill handler (%u instructions).\n",
++		 (unsigned int)(p - tlb_handler));
+ 
  	memcpy((void *)ebase, tlb_handler, 0x80);
 +
 +	dump_handler((u32 *)ebase, 32);
  }
  
  /*
-@@ -801,7 +818,7 @@ static void __init build_r3000_tlb_refill_handler(void)
+@@ -801,7 +197,7 @@ static void __init build_r3000_tlb_refill_handler(void)
   * other one.To keep things simple, we first assume linear space,
   * then we relocate it to the final handler layout as needed.
   */
@@ -71824,7 +77533,7 @@
  
  /*
   * Hazards
-@@ -825,7 +842,7 @@ static __initdata u32 final_handler[64];
+@@ -825,7 +221,7 @@ static __initdata u32 final_handler[64];
   *
   * As if we MIPS hackers wouldn't know how to nop pipelines happy ...
   */
@@ -71833,95 +77542,365 @@
  {
  	switch (current_cpu_type()) {
  	/* Found by experiment: R4600 v2.0 needs this, too.  */
-@@ -849,7 +866,7 @@ static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
+@@ -833,12 +229,12 @@ static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
+ 	case CPU_R5000:
+ 	case CPU_R5000A:
+ 	case CPU_NEVADA:
+-		i_nop(p);
+-		i_tlbp(p);
++		uasm_i_nop(p);
++		uasm_i_tlbp(p);
+ 		break;
+ 
+ 	default:
+-		i_tlbp(p);
++		uasm_i_tlbp(p);
+ 		break;
+ 	}
+ }
+@@ -849,15 +245,21 @@ static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
   */
  enum tlb_write_entry { tlb_random, tlb_indexed };
  
 -static __init void build_tlb_write_entry(u32 **p, struct label **l,
-+static void __init build_tlb_write_entry(u32 **p, struct label **l,
- 					 struct reloc **r,
+-					 struct reloc **r,
++static void __init build_tlb_write_entry(u32 **p, struct uasm_label **l,
++					 struct uasm_reloc **r,
  					 enum tlb_write_entry wmode)
  {
-@@ -860,6 +877,12 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
- 	case tlb_indexed: tlbw = i_tlbwi; break;
- 	}
+ 	void(*tlbw)(u32 **) = NULL;
  
+ 	switch (wmode) {
+-	case tlb_random: tlbw = i_tlbwr; break;
+-	case tlb_indexed: tlbw = i_tlbwi; break;
++	case tlb_random: tlbw = uasm_i_tlbwr; break;
++	case tlb_indexed: tlbw = uasm_i_tlbwi; break;
++	}
++
 +	if (cpu_has_mips_r2) {
-+		i_ehb(p);
++		uasm_i_ehb(p);
 +		tlbw(p);
 +		return;
-+	}
-+
+ 	}
+ 
  	switch (current_cpu_type()) {
- 	case CPU_R4000PC:
- 	case CPU_R4000SC:
-@@ -894,6 +917,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+@@ -871,19 +273,19 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+ 		 * This branch uses up a mtc0 hazard nop slot and saves
+ 		 * two nops after the tlbw instruction.
+ 		 */
+-		il_bgezl(p, r, 0, label_tlbw_hazard);
++		uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
+ 		tlbw(p);
+-		l_tlbw_hazard(l, *p);
+-		i_nop(p);
++		uasm_l_tlbw_hazard(l, *p);
++		uasm_i_nop(p);
+ 		break;
+ 
+ 	case CPU_R4600:
+ 	case CPU_R4700:
+ 	case CPU_R5000:
+ 	case CPU_R5000A:
+-		i_nop(p);
++		uasm_i_nop(p);
+ 		tlbw(p);
+-		i_nop(p);
++		uasm_i_nop(p);
+ 		break;
+ 
+ 	case CPU_R4300:
+@@ -894,8 +296,10 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
  	case CPU_AU1500:
  	case CPU_AU1550:
  	case CPU_AU1200:
 +	case CPU_AU1210:
 +	case CPU_AU1250:
  	case CPU_PR4450:
- 		i_nop(p);
+-		i_nop(p);
++		uasm_i_nop(p);
+ 		tlbw(p);
+ 		break;
+ 
+@@ -912,34 +316,26 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+ 	case CPU_BCM4710:
+ 	case CPU_LOONGSON2:
+ 		if (m4kc_tlbp_war())
+-			i_nop(p);
++			uasm_i_nop(p);
  		tlbw(p);
-@@ -935,14 +960,6 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+ 		break;
+ 
+ 	case CPU_NEVADA:
+-		i_nop(p); /* QED specifies 2 nops hazard */
++		uasm_i_nop(p); /* QED specifies 2 nops hazard */
+ 		/*
+ 		 * This branch uses up a mtc0 hazard nop slot and saves
+ 		 * a nop after the tlbw instruction.
+ 		 */
+-		il_bgezl(p, r, 0, label_tlbw_hazard);
++		uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
  		tlbw(p);
+-		l_tlbw_hazard(l, *p);
++		uasm_l_tlbw_hazard(l, *p);
  		break;
  
+ 	case CPU_RM7000:
+-		i_nop(p);
+-		i_nop(p);
+-		i_nop(p);
+-		i_nop(p);
+-		tlbw(p);
+-		break;
+-
 -	case CPU_4KEC:
 -	case CPU_24K:
 -	case CPU_34K:
 -	case CPU_74K:
 -		i_ehb(p);
--		tlbw(p);
--		break;
--
- 	case CPU_RM9000:
- 		/*
- 		 * When the JTLB is updated by tlbwi or tlbwr, a subsequent
-@@ -993,7 +1010,7 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
++		uasm_i_nop(p);
++		uasm_i_nop(p);
++		uasm_i_nop(p);
++		uasm_i_nop(p);
+ 		tlbw(p);
+ 		break;
+ 
+@@ -950,15 +346,15 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+ 		 * cpu cycles and use for data translations should not occur
+ 		 * for 3 cpu cycles.
+ 		 */
+-		i_ssnop(p);
+-		i_ssnop(p);
+-		i_ssnop(p);
+-		i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
+ 		tlbw(p);
+-		i_ssnop(p);
+-		i_ssnop(p);
+-		i_ssnop(p);
+-		i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
++		uasm_i_ssnop(p);
+ 		break;
+ 
+ 	case CPU_VR4111:
+@@ -966,18 +362,18 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
+ 	case CPU_VR4122:
+ 	case CPU_VR4181:
+ 	case CPU_VR4181A:
+-		i_nop(p);
+-		i_nop(p);
++		uasm_i_nop(p);
++		uasm_i_nop(p);
+ 		tlbw(p);
+-		i_nop(p);
+-		i_nop(p);
++		uasm_i_nop(p);
++		uasm_i_nop(p);
+ 		break;
+ 
+ 	case CPU_VR4131:
+ 	case CPU_VR4133:
+ 	case CPU_R5432:
+-		i_nop(p);
+-		i_nop(p);
++		uasm_i_nop(p);
++		uasm_i_nop(p);
+ 		tlbw(p);
+ 		break;
+ 
+@@ -993,8 +389,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
   * TMP and PTR are scratch.
   * TMP will be clobbered, PTR will hold the pmd entry.
   */
 -static __init void
+-build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
 +static void __init
- build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
++build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
  		 unsigned int tmp, unsigned int ptr)
  {
-@@ -1054,7 +1071,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
+ 	long pgdc = (long)pgd_current;
+@@ -1002,60 +398,60 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
+ 	/*
+ 	 * The vmalloc handling is not in the hotpath.
+ 	 */
+-	i_dmfc0(p, tmp, C0_BADVADDR);
++	uasm_i_dmfc0(p, tmp, C0_BADVADDR);
+ #ifdef MODULE_START
+-	il_bltz(p, r, tmp, label_module_alloc);
++	uasm_il_bltz(p, r, tmp, label_module_alloc);
+ #else
+-	il_bltz(p, r, tmp, label_vmalloc);
++	uasm_il_bltz(p, r, tmp, label_vmalloc);
+ #endif
+-	/* No i_nop needed here, since the next insn doesn't touch TMP. */
++	/* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
+ 
+ #ifdef CONFIG_SMP
+ # ifdef  CONFIG_MIPS_MT_SMTC
+ 	/*
+ 	 * SMTC uses TCBind value as "CPU" index
+ 	 */
+-	i_mfc0(p, ptr, C0_TCBIND);
+-	i_dsrl(p, ptr, ptr, 19);
++	uasm_i_mfc0(p, ptr, C0_TCBIND);
++	uasm_i_dsrl(p, ptr, ptr, 19);
+ # else
+ 	/*
+ 	 * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
+ 	 * stored in CONTEXT.
+ 	 */
+-	i_dmfc0(p, ptr, C0_CONTEXT);
+-	i_dsrl(p, ptr, ptr, 23);
++	uasm_i_dmfc0(p, ptr, C0_CONTEXT);
++	uasm_i_dsrl(p, ptr, ptr, 23);
+ #endif
+-	i_LA_mostly(p, tmp, pgdc);
+-	i_daddu(p, ptr, ptr, tmp);
+-	i_dmfc0(p, tmp, C0_BADVADDR);
+-	i_ld(p, ptr, rel_lo(pgdc), ptr);
++	UASM_i_LA_mostly(p, tmp, pgdc);
++	uasm_i_daddu(p, ptr, ptr, tmp);
++	uasm_i_dmfc0(p, tmp, C0_BADVADDR);
++	uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+ #else
+-	i_LA_mostly(p, ptr, pgdc);
+-	i_ld(p, ptr, rel_lo(pgdc), ptr);
++	UASM_i_LA_mostly(p, ptr, pgdc);
++	uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
+ #endif
+ 
+-	l_vmalloc_done(l, *p);
++	uasm_l_vmalloc_done(l, *p);
+ 
+ 	if (PGDIR_SHIFT - 3 < 32)		/* get pgd offset in bytes */
+-		i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
++		uasm_i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
+ 	else
+-		i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
+-
+-	i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
+-	i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
+-	i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+-	i_ld(p, ptr, 0, ptr); /* get pmd pointer */
+-	i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
+-	i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
+-	i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
++		uasm_i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
++
++	uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
++	uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
++	uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
++	uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */
++	uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
++	uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
++	uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
+ }
+ 
+ /*
   * BVADDR is the faulting address, PTR is scratch.
   * PTR will hold the pgd for vmalloc.
   */
 -static __init void
+-build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
 +static void __init
- build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
++build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
  			unsigned int bvaddr, unsigned int ptr)
  {
-@@ -1087,7 +1104,10 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+ 	long swpd = (long)swapper_pg_dir;
+@@ -1063,52 +459,60 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+ #ifdef MODULE_START
+ 	long modd = (long)module_pg_dir;
+ 
+-	l_module_alloc(l, *p);
++	uasm_l_module_alloc(l, *p);
+ 	/*
+ 	 * Assumption:
+ 	 * VMALLOC_START >= 0xc000000000000000UL
+ 	 * MODULE_START >= 0xe000000000000000UL
+ 	 */
+-	i_SLL(p, ptr, bvaddr, 2);
+-	il_bgez(p, r, ptr, label_vmalloc);
++	UASM_i_SLL(p, ptr, bvaddr, 2);
++	uasm_il_bgez(p, r, ptr, label_vmalloc);
+ 
+-	if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START)) {
+-		i_lui(p, ptr, rel_hi(MODULE_START)); /* delay slot */
++	if (uasm_in_compat_space_p(MODULE_START) &&
++	    !uasm_rel_lo(MODULE_START)) {
++		uasm_i_lui(p, ptr, uasm_rel_hi(MODULE_START)); /* delay slot */
+ 	} else {
+ 		/* unlikely configuration */
+-		i_nop(p); /* delay slot */
+-		i_LA(p, ptr, MODULE_START);
++		uasm_i_nop(p); /* delay slot */
++		UASM_i_LA(p, ptr, MODULE_START);
+ 	}
+-	i_dsubu(p, bvaddr, bvaddr, ptr);
++	uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
+ 
+-	if (in_compat_space_p(modd) && !rel_lo(modd)) {
+-		il_b(p, r, label_vmalloc_done);
+-		i_lui(p, ptr, rel_hi(modd));
++	if (uasm_in_compat_space_p(modd) && !uasm_rel_lo(modd)) {
++		uasm_il_b(p, r, label_vmalloc_done);
++		uasm_i_lui(p, ptr, uasm_rel_hi(modd));
  	} else {
- 		i_LA_mostly(p, ptr, modd);
- 		il_b(p, r, label_vmalloc_done);
+-		i_LA_mostly(p, ptr, modd);
+-		il_b(p, r, label_vmalloc_done);
 -		i_daddiu(p, ptr, ptr, rel_lo(modd));
-+		if (in_compat_space_p(modd))
-+			i_addiu(p, ptr, ptr, rel_lo(modd));
++		UASM_i_LA_mostly(p, ptr, modd);
++		uasm_il_b(p, r, label_vmalloc_done);
++		if (uasm_in_compat_space_p(modd))
++			uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(modd));
 +		else
-+			i_daddiu(p, ptr, ptr, rel_lo(modd));
++			uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(modd));
  	}
  
- 	l_vmalloc(l, *p);
-@@ -1108,7 +1128,10 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+-	l_vmalloc(l, *p);
+-	if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START) &&
++	uasm_l_vmalloc(l, *p);
++	if (uasm_in_compat_space_p(MODULE_START) &&
++	    !uasm_rel_lo(MODULE_START) &&
+ 	    MODULE_START << 32 == VMALLOC_START)
+-		i_dsll32(p, ptr, ptr, 0);	/* typical case */
++		uasm_i_dsll32(p, ptr, ptr, 0);	/* typical case */
+ 	else
+-		i_LA(p, ptr, VMALLOC_START);
++		UASM_i_LA(p, ptr, VMALLOC_START);
+ #else
+-	l_vmalloc(l, *p);
+-	i_LA(p, ptr, VMALLOC_START);
++	uasm_l_vmalloc(l, *p);
++	UASM_i_LA(p, ptr, VMALLOC_START);
+ #endif
+-	i_dsubu(p, bvaddr, bvaddr, ptr);
++	uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
+ 
+-	if (in_compat_space_p(swpd) && !rel_lo(swpd)) {
+-		il_b(p, r, label_vmalloc_done);
+-		i_lui(p, ptr, rel_hi(swpd));
++	if (uasm_in_compat_space_p(swpd) && !uasm_rel_lo(swpd)) {
++		uasm_il_b(p, r, label_vmalloc_done);
++		uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
  	} else {
- 		i_LA_mostly(p, ptr, swpd);
- 		il_b(p, r, label_vmalloc_done);
+-		i_LA_mostly(p, ptr, swpd);
+-		il_b(p, r, label_vmalloc_done);
 -		i_daddiu(p, ptr, ptr, rel_lo(swpd));
-+		if (in_compat_space_p(swpd))
-+			i_addiu(p, ptr, ptr, rel_lo(swpd));
++		UASM_i_LA_mostly(p, ptr, swpd);
++		uasm_il_b(p, r, label_vmalloc_done);
++		if (uasm_in_compat_space_p(swpd))
++			uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(swpd));
 +		else
-+			i_daddiu(p, ptr, ptr, rel_lo(swpd));
++			uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd));
  	}
  }
  
-@@ -1118,7 +1141,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+@@ -1118,7 +522,7 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
   * TMP and PTR are scratch.
   * TMP will be clobbered, PTR will hold the pgd entry.
   */
@@ -71930,7 +77909,44 @@
  build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
  {
  	long pgdc = (long)pgd_current;
-@@ -1153,7 +1176,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
+@@ -1129,31 +533,31 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
+ 	/*
+ 	 * SMTC uses TCBind value as "CPU" index
+ 	 */
+-	i_mfc0(p, ptr, C0_TCBIND);
+-	i_LA_mostly(p, tmp, pgdc);
+-	i_srl(p, ptr, ptr, 19);
++	uasm_i_mfc0(p, ptr, C0_TCBIND);
++	UASM_i_LA_mostly(p, tmp, pgdc);
++	uasm_i_srl(p, ptr, ptr, 19);
+ #else
+ 	/*
+ 	 * smp_processor_id() << 3 is stored in CONTEXT.
+          */
+-	i_mfc0(p, ptr, C0_CONTEXT);
+-	i_LA_mostly(p, tmp, pgdc);
+-	i_srl(p, ptr, ptr, 23);
++	uasm_i_mfc0(p, ptr, C0_CONTEXT);
++	UASM_i_LA_mostly(p, tmp, pgdc);
++	uasm_i_srl(p, ptr, ptr, 23);
+ #endif
+-	i_addu(p, ptr, tmp, ptr);
++	uasm_i_addu(p, ptr, tmp, ptr);
+ #else
+-	i_LA_mostly(p, ptr, pgdc);
++	UASM_i_LA_mostly(p, ptr, pgdc);
+ #endif
+-	i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+-	i_lw(p, ptr, rel_lo(pgdc), ptr);
+-	i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
+-	i_sll(p, tmp, tmp, PGD_T_LOG2);
+-	i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
++	uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
++	uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
++	uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
++	uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
++	uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
+ }
  
  #endif /* !CONFIG_64BIT */
  
@@ -71939,8 +77955,14 @@
  {
  	unsigned int shift = 4 - (PTE_T_LOG2 + 1) + PAGE_SHIFT - 12;
  	unsigned int mask = (PTRS_PER_PTE / 2 - 1) << (PTE_T_LOG2 + 1);
-@@ -1179,7 +1202,7 @@ static __init void build_adjust_context(u32 **p, unsigned int ctx)
- 	i_andi(p, ctx, ctx, mask);
+@@ -1175,11 +579,11 @@ static __init void build_adjust_context(u32 **p, unsigned int ctx)
+ 	}
+ 
+ 	if (shift)
+-		i_SRL(p, ctx, ctx, shift);
+-	i_andi(p, ctx, ctx, mask);
++		UASM_i_SRL(p, ctx, ctx, shift);
++	uasm_i_andi(p, ctx, ctx, mask);
  }
  
 -static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
@@ -71948,8 +77970,25 @@
  {
  	/*
  	 * Bug workaround for the Nevada. It seems as if under certain
-@@ -1204,7 +1227,7 @@ static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
- 	i_ADDU(p, ptr, ptr, tmp); /* add in offset */
+@@ -1190,21 +594,21 @@ static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
+ 	 */
+ 	switch (current_cpu_type()) {
+ 	case CPU_NEVADA:
+-		i_LW(p, ptr, 0, ptr);
++		UASM_i_LW(p, ptr, 0, ptr);
+ 		GET_CONTEXT(p, tmp); /* get context reg */
+ 		break;
+ 
+ 	default:
+ 		GET_CONTEXT(p, tmp); /* get context reg */
+-		i_LW(p, ptr, 0, ptr);
++		UASM_i_LW(p, ptr, 0, ptr);
+ 		break;
+ 	}
+ 
+ 	build_adjust_context(p, tmp);
+-	i_ADDU(p, ptr, ptr, tmp); /* add in offset */
++	UASM_i_ADDU(p, ptr, ptr, tmp); /* add in offset */
  }
  
 -static __init void build_update_entries(u32 **p, unsigned int tmp,
@@ -71957,18 +77996,173 @@
  					unsigned int ptep)
  {
  	/*
-@@ -1254,7 +1277,6 @@ static void __init build_r4000_tlb_refill_handler(void)
- 	struct reloc *r = relocs;
+@@ -1213,48 +617,47 @@ static __init void build_update_entries(u32 **p, unsigned int tmp,
+ 	 */
+ #ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (cpu_has_64bits) {
+-		i_ld(p, tmp, 0, ptep); /* get even pte */
+-		i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+-		i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
+-		i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+-		i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
+-		i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
++		uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
++		uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
++		uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
++		uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
++		uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
++		uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ 	} else {
+ 		int pte_off_even = sizeof(pte_t) / 2;
+ 		int pte_off_odd = pte_off_even + sizeof(pte_t);
+ 
+ 		/* The pte entries are pre-shifted */
+-		i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
+-		i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+-		i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
+-		i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
++		uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
++		uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
++		uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
++		uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ 	}
+ #else
+-	i_LW(p, tmp, 0, ptep); /* get even pte */
+-	i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
++	UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
++	UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+ 	if (r45k_bvahwbug())
+ 		build_tlb_probe_entry(p);
+-	i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
++	UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
+ 	if (r4k_250MHZhwbug())
+-		i_mtc0(p, 0, C0_ENTRYLO0);
+-	i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+-	i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
++		uasm_i_mtc0(p, 0, C0_ENTRYLO0);
++	uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
++	UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
+ 	if (r45k_bvahwbug())
+-		i_mfc0(p, tmp, C0_INDEX);
++		uasm_i_mfc0(p, tmp, C0_INDEX);
+ 	if (r4k_250MHZhwbug())
+-		i_mtc0(p, 0, C0_ENTRYLO1);
+-	i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
++		uasm_i_mtc0(p, 0, C0_ENTRYLO1);
++	uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ #endif
+ }
+ 
+ static void __init build_r4000_tlb_refill_handler(void)
+ {
+ 	u32 *p = tlb_handler;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  	u32 *f;
  	unsigned int final_len;
 -	int i;
  
  	memset(tlb_handler, 0, sizeof(tlb_handler));
  	memset(labels, 0, sizeof(labels));
-@@ -1356,20 +1378,9 @@ static void __init build_r4000_tlb_refill_handler(void)
- 	pr_info("Synthesized TLB refill handler (%u instructions).\n",
- 		final_len);
+@@ -1265,12 +668,12 @@ static void __init build_r4000_tlb_refill_handler(void)
+ 	 * create the plain linear handler
+ 	 */
+ 	if (bcm1250_m3_war()) {
+-		i_MFC0(&p, K0, C0_BADVADDR);
+-		i_MFC0(&p, K1, C0_ENTRYHI);
+-		i_xor(&p, K0, K0, K1);
+-		i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+-		il_bnez(&p, &r, K0, label_leave);
+-		/* No need for i_nop */
++		UASM_i_MFC0(&p, K0, C0_BADVADDR);
++		UASM_i_MFC0(&p, K1, C0_ENTRYHI);
++		uasm_i_xor(&p, K0, K0, K1);
++		UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
++		uasm_il_bnez(&p, &r, K0, label_leave);
++		/* No need for uasm_i_nop */
+ 	}
+ 
+ #ifdef CONFIG_64BIT
+@@ -1282,8 +685,8 @@ static void __init build_r4000_tlb_refill_handler(void)
+ 	build_get_ptep(&p, K0, K1);
+ 	build_update_entries(&p, K0, K1);
+ 	build_tlb_write_entry(&p, &l, &r, tlb_random);
+-	l_leave(&l, p);
+-	i_eret(&p); /* return from trap */
++	uasm_l_leave(&l, p);
++	uasm_i_eret(&p); /* return from trap */
+ 
+ #ifdef CONFIG_64BIT
+ 	build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
+@@ -1303,7 +706,7 @@ static void __init build_r4000_tlb_refill_handler(void)
+ #else
+ 	if (((p - tlb_handler) > 63)
+ 	    || (((p - tlb_handler) > 61)
+-		&& insn_has_bdelay(relocs, tlb_handler + 29)))
++		&& uasm_insn_has_bdelay(relocs, tlb_handler + 29)))
+ 		panic("TLB refill handler space exceeded");
+ #endif
+ 
+@@ -1313,13 +716,13 @@ static void __init build_r4000_tlb_refill_handler(void)
+ #if defined(CONFIG_32BIT) || defined(CONFIG_CPU_LOONGSON2)
+ 	f = final_handler;
+ 	/* Simplest case, just copy the handler. */
+-	copy_handler(relocs, labels, tlb_handler, p, f);
++	uasm_copy_handler(relocs, labels, tlb_handler, p, f);
+ 	final_len = p - tlb_handler;
+ #else /* CONFIG_64BIT */
+ 	f = final_handler + 32;
+ 	if ((p - tlb_handler) <= 32) {
+ 		/* Just copy the handler. */
+-		copy_handler(relocs, labels, tlb_handler, p, f);
++		uasm_copy_handler(relocs, labels, tlb_handler, p, f);
+ 		final_len = p - tlb_handler;
+ 	} else {
+ 		u32 *split = tlb_handler + 30;
+@@ -1327,49 +730,38 @@ static void __init build_r4000_tlb_refill_handler(void)
+ 		/*
+ 		 * Find the split point.
+ 		 */
+-		if (insn_has_bdelay(relocs, split - 1))
++		if (uasm_insn_has_bdelay(relocs, split - 1))
+ 			split--;
+ 
+ 		/* Copy first part of the handler. */
+-		copy_handler(relocs, labels, tlb_handler, split, f);
++		uasm_copy_handler(relocs, labels, tlb_handler, split, f);
+ 		f += split - tlb_handler;
+ 
+ 		/* Insert branch. */
+-		l_split(&l, final_handler);
+-		il_b(&f, &r, label_split);
+-		if (insn_has_bdelay(relocs, split))
+-			i_nop(&f);
++		uasm_l_split(&l, final_handler);
++		uasm_il_b(&f, &r, label_split);
++		if (uasm_insn_has_bdelay(relocs, split))
++			uasm_i_nop(&f);
+ 		else {
+-			copy_handler(relocs, labels, split, split + 1, f);
+-			move_labels(labels, f, f + 1, -1);
++			uasm_copy_handler(relocs, labels, split, split + 1, f);
++			uasm_move_labels(labels, f, f + 1, -1);
+ 			f++;
+ 			split++;
+ 		}
+ 
+ 		/* Copy the rest of the handler. */
+-		copy_handler(relocs, labels, split, p, final_handler);
++		uasm_copy_handler(relocs, labels, split, p, final_handler);
+ 		final_len = (f - (final_handler + 32)) + (p - split);
+ 	}
+ #endif /* CONFIG_64BIT */
  
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB refill handler (%u instructions).\n",
+-		final_len);
+-
 -	f = final_handler;
 -#if defined(CONFIG_64BIT) && !defined(CONFIG_CPU_LOONGSON2)
 -	if (final_len > 32)
@@ -71981,14 +78175,17 @@
 -	for (i = 0; i < final_len; i++)
 -		pr_debug("\t.word 0x%08x\n", f[i]);
 -	pr_debug("\t.set pop\n");
--
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB refill handler (%u instructions).\n",
++		 final_len);
+ 
  	memcpy((void *)ebase, final_handler, 0x100);
 +
 +	dump_handler((u32 *)ebase, 64);
  }
  
  /*
-@@ -1381,18 +1392,15 @@ static void __init build_r4000_tlb_refill_handler(void)
+@@ -1381,89 +773,86 @@ static void __init build_r4000_tlb_refill_handler(void)
  extern void tlb_do_page_fault_0(void);
  extern void tlb_do_page_fault_1(void);
  
@@ -72009,18 +78206,288 @@
 +u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
  
  static void __init
- iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr)
-@@ -1600,7 +1608,6 @@ static void __init build_r3000_tlb_load_handler(void)
+-iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr)
++iPTE_LW(u32 **p, struct uasm_label **l, unsigned int pte, unsigned int ptr)
+ {
+ #ifdef CONFIG_SMP
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (cpu_has_64bits)
+-		i_lld(p, pte, 0, ptr);
++		uasm_i_lld(p, pte, 0, ptr);
+ 	else
+ # endif
+-		i_LL(p, pte, 0, ptr);
++		UASM_i_LL(p, pte, 0, ptr);
+ #else
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (cpu_has_64bits)
+-		i_ld(p, pte, 0, ptr);
++		uasm_i_ld(p, pte, 0, ptr);
+ 	else
+ # endif
+-		i_LW(p, pte, 0, ptr);
++		UASM_i_LW(p, pte, 0, ptr);
+ #endif
+ }
+ 
+ static void __init
+-iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
++iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
+ 	unsigned int mode)
+ {
+ #ifdef CONFIG_64BIT_PHYS_ADDR
+ 	unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY);
+ #endif
+ 
+-	i_ori(p, pte, pte, mode);
++	uasm_i_ori(p, pte, pte, mode);
+ #ifdef CONFIG_SMP
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (cpu_has_64bits)
+-		i_scd(p, pte, 0, ptr);
++		uasm_i_scd(p, pte, 0, ptr);
+ 	else
+ # endif
+-		i_SC(p, pte, 0, ptr);
++		UASM_i_SC(p, pte, 0, ptr);
+ 
+ 	if (r10000_llsc_war())
+-		il_beqzl(p, r, pte, label_smp_pgtable_change);
++		uasm_il_beqzl(p, r, pte, label_smp_pgtable_change);
+ 	else
+-		il_beqz(p, r, pte, label_smp_pgtable_change);
++		uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
+ 
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (!cpu_has_64bits) {
+-		/* no i_nop needed */
+-		i_ll(p, pte, sizeof(pte_t) / 2, ptr);
+-		i_ori(p, pte, pte, hwmode);
+-		i_sc(p, pte, sizeof(pte_t) / 2, ptr);
+-		il_beqz(p, r, pte, label_smp_pgtable_change);
+-		/* no i_nop needed */
+-		i_lw(p, pte, 0, ptr);
++		/* no uasm_i_nop needed */
++		uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr);
++		uasm_i_ori(p, pte, pte, hwmode);
++		uasm_i_sc(p, pte, sizeof(pte_t) / 2, ptr);
++		uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
++		/* no uasm_i_nop needed */
++		uasm_i_lw(p, pte, 0, ptr);
+ 	} else
+-		i_nop(p);
++		uasm_i_nop(p);
+ # else
+-	i_nop(p);
++	uasm_i_nop(p);
+ # endif
+ #else
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (cpu_has_64bits)
+-		i_sd(p, pte, 0, ptr);
++		uasm_i_sd(p, pte, 0, ptr);
+ 	else
+ # endif
+-		i_SW(p, pte, 0, ptr);
++		UASM_i_SW(p, pte, 0, ptr);
+ 
+ # ifdef CONFIG_64BIT_PHYS_ADDR
+ 	if (!cpu_has_64bits) {
+-		i_lw(p, pte, sizeof(pte_t) / 2, ptr);
+-		i_ori(p, pte, pte, hwmode);
+-		i_sw(p, pte, sizeof(pte_t) / 2, ptr);
+-		i_lw(p, pte, 0, ptr);
++		uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr);
++		uasm_i_ori(p, pte, pte, hwmode);
++		uasm_i_sw(p, pte, sizeof(pte_t) / 2, ptr);
++		uasm_i_lw(p, pte, 0, ptr);
+ 	}
+ # endif
+ #endif
+@@ -1475,18 +864,18 @@ iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
+  * with it's original value.
+  */
+ static void __init
+-build_pte_present(u32 **p, struct label **l, struct reloc **r,
++build_pte_present(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
+ 		  unsigned int pte, unsigned int ptr, enum label_id lid)
+ {
+-	i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+-	i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+-	il_bnez(p, r, pte, lid);
++	uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
++	uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
++	uasm_il_bnez(p, r, pte, lid);
+ 	iPTE_LW(p, l, pte, ptr);
+ }
+ 
+ /* Make PTE valid, store result in PTR. */
+ static void __init
+-build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
++build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte,
+ 		 unsigned int ptr)
+ {
+ 	unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED;
+@@ -1499,12 +888,12 @@ build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
+  * restore PTE with value from PTR when done.
+  */
+ static void __init
+-build_pte_writable(u32 **p, struct label **l, struct reloc **r,
++build_pte_writable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
+ 		   unsigned int pte, unsigned int ptr, enum label_id lid)
+ {
+-	i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+-	i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+-	il_bnez(p, r, pte, lid);
++	uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
++	uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
++	uasm_il_bnez(p, r, pte, lid);
+ 	iPTE_LW(p, l, pte, ptr);
+ }
+ 
+@@ -1512,7 +901,7 @@ build_pte_writable(u32 **p, struct label **l, struct reloc **r,
+  * at PTR.
+  */
+ static void __init
+-build_make_write(u32 **p, struct reloc **r, unsigned int pte,
++build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte,
+ 		 unsigned int ptr)
+ {
+ 	unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID
+@@ -1526,11 +915,11 @@ build_make_write(u32 **p, struct reloc **r, unsigned int pte,
+  * restore PTE with value from PTR when done.
+  */
+ static void __init
+-build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
++build_pte_modifiable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
+ 		     unsigned int pte, unsigned int ptr, enum label_id lid)
+ {
+-	i_andi(p, pte, pte, _PAGE_WRITE);
+-	il_beqz(p, r, pte, lid);
++	uasm_i_andi(p, pte, pte, _PAGE_WRITE);
++	uasm_il_beqz(p, r, pte, lid);
+ 	iPTE_LW(p, l, pte, ptr);
+ }
+ 
+@@ -1545,11 +934,11 @@ build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
+ static void __init
+ build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
+ {
+-	i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+-	i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
+-	i_tlbwi(p);
+-	i_jr(p, tmp);
+-	i_rfe(p); /* branch delay */
++	uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
++	uasm_i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
++	uasm_i_tlbwi(p);
++	uasm_i_jr(p, tmp);
++	uasm_i_rfe(p); /* branch delay */
+ }
+ 
+ /*
+@@ -1559,20 +948,21 @@ build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
+  * kseg2 access, i.e. without refill.  Then it returns.
+  */
+ static void __init
+-build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r,
+-			     unsigned int pte, unsigned int tmp)
+-{
+-	i_mfc0(p, tmp, C0_INDEX);
+-	i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+-	il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
+-	i_mfc0(p, tmp, C0_EPC); /* branch delay */
+-	i_tlbwi(p); /* cp0 delay */
+-	i_jr(p, tmp);
+-	i_rfe(p); /* branch delay */
+-	l_r3000_write_probe_fail(l, *p);
+-	i_tlbwr(p); /* cp0 delay */
+-	i_jr(p, tmp);
+-	i_rfe(p); /* branch delay */
++build_r3000_tlb_reload_write(u32 **p, struct uasm_label **l,
++			     struct uasm_reloc **r, unsigned int pte,
++			     unsigned int tmp)
++{
++	uasm_i_mfc0(p, tmp, C0_INDEX);
++	uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
++	uasm_il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
++	uasm_i_mfc0(p, tmp, C0_EPC); /* branch delay */
++	uasm_i_tlbwi(p); /* cp0 delay */
++	uasm_i_jr(p, tmp);
++	uasm_i_rfe(p); /* branch delay */
++	uasm_l_r3000_write_probe_fail(l, *p);
++	uasm_i_tlbwr(p); /* cp0 delay */
++	uasm_i_jr(p, tmp);
++	uasm_i_rfe(p); /* branch delay */
+ }
+ 
+ static void __init
+@@ -1581,26 +971,25 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte,
+ {
+ 	long pgdc = (long)pgd_current;
+ 
+-	i_mfc0(p, pte, C0_BADVADDR);
+-	i_lui(p, ptr, rel_hi(pgdc)); /* cp0 delay */
+-	i_lw(p, ptr, rel_lo(pgdc), ptr);
+-	i_srl(p, pte, pte, 22); /* load delay */
+-	i_sll(p, pte, pte, 2);
+-	i_addu(p, ptr, ptr, pte);
+-	i_mfc0(p, pte, C0_CONTEXT);
+-	i_lw(p, ptr, 0, ptr); /* cp0 delay */
+-	i_andi(p, pte, pte, 0xffc); /* load delay */
+-	i_addu(p, ptr, ptr, pte);
+-	i_lw(p, pte, 0, ptr);
+-	i_tlbp(p); /* load delay */
++	uasm_i_mfc0(p, pte, C0_BADVADDR);
++	uasm_i_lui(p, ptr, uasm_rel_hi(pgdc)); /* cp0 delay */
++	uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
++	uasm_i_srl(p, pte, pte, 22); /* load delay */
++	uasm_i_sll(p, pte, pte, 2);
++	uasm_i_addu(p, ptr, ptr, pte);
++	uasm_i_mfc0(p, pte, C0_CONTEXT);
++	uasm_i_lw(p, ptr, 0, ptr); /* cp0 delay */
++	uasm_i_andi(p, pte, pte, 0xffc); /* load delay */
++	uasm_i_addu(p, ptr, ptr, pte);
++	uasm_i_lw(p, pte, 0, ptr);
++	uasm_i_tlbp(p); /* load delay */
+ }
+ 
+ static void __init build_r3000_tlb_load_handler(void)
+ {
  	u32 *p = handle_tlbl;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbl, 0, sizeof(handle_tlbl));
  	memset(labels, 0, sizeof(labels));
-@@ -1623,11 +1630,7 @@ static void __init build_r3000_tlb_load_handler(void)
- 	pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbl));
+@@ -1608,34 +997,29 @@ static void __init build_r3000_tlb_load_handler(void)
+ 
+ 	build_r3000_tlbchange_handler_head(&p, K0, K1);
+ 	build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
+-	i_nop(&p); /* load delay */
++	uasm_i_nop(&p); /* load delay */
+ 	build_make_valid(&p, &r, K0, K1);
+ 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
+ 
+-	l_nopage_tlbl(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbl(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbl) > FASTPATH_SIZE)
+ 		panic("TLB load handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbl));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbl));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72031,17 +78498,41 @@
  }
  
  static void __init build_r3000_tlb_store_handler(void)
-@@ -1635,7 +1638,6 @@ static void __init build_r3000_tlb_store_handler(void)
+ {
  	u32 *p = handle_tlbs;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbs, 0, sizeof(handle_tlbs));
  	memset(labels, 0, sizeof(labels));
-@@ -1658,11 +1660,7 @@ static void __init build_r3000_tlb_store_handler(void)
- 	pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbs));
+@@ -1643,34 +1027,29 @@ static void __init build_r3000_tlb_store_handler(void)
+ 
+ 	build_r3000_tlbchange_handler_head(&p, K0, K1);
+ 	build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
+-	i_nop(&p); /* load delay */
++	uasm_i_nop(&p); /* load delay */
+ 	build_make_write(&p, &r, K0, K1);
+ 	build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
+ 
+-	l_nopage_tlbs(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbs(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbs) > FASTPATH_SIZE)
+ 		panic("TLB store handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbs));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbs));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72052,17 +78543,41 @@
  }
  
  static void __init build_r3000_tlb_modify_handler(void)
-@@ -1670,7 +1668,6 @@ static void __init build_r3000_tlb_modify_handler(void)
+ {
  	u32 *p = handle_tlbm;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbm, 0, sizeof(handle_tlbm));
  	memset(labels, 0, sizeof(labels));
-@@ -1693,11 +1690,7 @@ static void __init build_r3000_tlb_modify_handler(void)
- 	pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbm));
+@@ -1678,34 +1057,30 @@ static void __init build_r3000_tlb_modify_handler(void)
+ 
+ 	build_r3000_tlbchange_handler_head(&p, K0, K1);
+ 	build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
+-	i_nop(&p); /* load delay */
++	uasm_i_nop(&p); /* load delay */
+ 	build_make_write(&p, &r, K0, K1);
+ 	build_r3000_pte_reload_tlbwi(&p, K0, K1);
+ 
+-	l_nopage_tlbm(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbm(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbm) > FASTPATH_SIZE)
+ 		panic("TLB modify handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbm));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbm));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72073,17 +78588,111 @@
  }
  
  /*
-@@ -1750,7 +1743,6 @@ static void __init build_r4000_tlb_load_handler(void)
+  * R4000 style TLB load/store/modify handlers.
+  */
+ static void __init
+-build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
+-				   struct reloc **r, unsigned int pte,
++build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
++				   struct uasm_reloc **r, unsigned int pte,
+ 				   unsigned int ptr)
+ {
+ #ifdef CONFIG_64BIT
+@@ -1714,31 +1089,31 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
+ 	build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
+ #endif
+ 
+-	i_MFC0(p, pte, C0_BADVADDR);
+-	i_LW(p, ptr, 0, ptr);
+-	i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
+-	i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
+-	i_ADDU(p, ptr, ptr, pte);
++	UASM_i_MFC0(p, pte, C0_BADVADDR);
++	UASM_i_LW(p, ptr, 0, ptr);
++	UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
++	uasm_i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
++	UASM_i_ADDU(p, ptr, ptr, pte);
+ 
+ #ifdef CONFIG_SMP
+-	l_smp_pgtable_change(l, *p);
+-# endif
++	uasm_l_smp_pgtable_change(l, *p);
++#endif
+ 	iPTE_LW(p, l, pte, ptr); /* get even pte */
+ 	if (!m4kc_tlbp_war())
+ 		build_tlb_probe_entry(p);
+ }
+ 
+ static void __init
+-build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
+-				   struct reloc **r, unsigned int tmp,
++build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
++				   struct uasm_reloc **r, unsigned int tmp,
+ 				   unsigned int ptr)
+ {
+-	i_ori(p, ptr, ptr, sizeof(pte_t));
+-	i_xori(p, ptr, ptr, sizeof(pte_t));
++	uasm_i_ori(p, ptr, ptr, sizeof(pte_t));
++	uasm_i_xori(p, ptr, ptr, sizeof(pte_t));
+ 	build_update_entries(p, tmp, ptr);
+ 	build_tlb_write_entry(p, l, r, tlb_indexed);
+-	l_leave(l, *p);
+-	i_eret(p); /* return from trap */
++	uasm_l_leave(l, *p);
++	uasm_i_eret(p); /* return from trap */
+ 
+ #ifdef CONFIG_64BIT
+ 	build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
+@@ -1748,21 +1123,20 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
+ static void __init build_r4000_tlb_load_handler(void)
+ {
  	u32 *p = handle_tlbl;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbl, 0, sizeof(handle_tlbl));
  	memset(labels, 0, sizeof(labels));
-@@ -1783,11 +1775,7 @@ static void __init build_r4000_tlb_load_handler(void)
- 	pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbl));
+ 	memset(relocs, 0, sizeof(relocs));
+ 
+ 	if (bcm1250_m3_war()) {
+-		i_MFC0(&p, K0, C0_BADVADDR);
+-		i_MFC0(&p, K1, C0_ENTRYHI);
+-		i_xor(&p, K0, K0, K1);
+-		i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+-		il_bnez(&p, &r, K0, label_leave);
+-		/* No need for i_nop */
++		UASM_i_MFC0(&p, K0, C0_BADVADDR);
++		UASM_i_MFC0(&p, K1, C0_ENTRYHI);
++		uasm_i_xor(&p, K0, K0, K1);
++		UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
++		uasm_il_bnez(&p, &r, K0, label_leave);
++		/* No need for uasm_i_nop */
+ 	}
+ 
+ 	build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
+@@ -1772,30 +1146,25 @@ static void __init build_r4000_tlb_load_handler(void)
+ 	build_make_valid(&p, &r, K0, K1);
+ 	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+ 
+-	l_nopage_tlbl(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbl(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbl) > FASTPATH_SIZE)
+ 		panic("TLB load handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbl));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbl));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72094,17 +78703,36 @@
  }
  
  static void __init build_r4000_tlb_store_handler(void)
-@@ -1795,7 +1783,6 @@ static void __init build_r4000_tlb_store_handler(void)
+ {
  	u32 *p = handle_tlbs;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbs, 0, sizeof(handle_tlbs));
  	memset(labels, 0, sizeof(labels));
-@@ -1819,11 +1806,7 @@ static void __init build_r4000_tlb_store_handler(void)
- 	pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbs));
+@@ -1808,30 +1177,25 @@ static void __init build_r4000_tlb_store_handler(void)
+ 	build_make_write(&p, &r, K0, K1);
+ 	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+ 
+-	l_nopage_tlbs(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbs(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbs) > FASTPATH_SIZE)
+ 		panic("TLB store handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbs));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbs));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72115,17 +78743,36 @@
  }
  
  static void __init build_r4000_tlb_modify_handler(void)
-@@ -1831,7 +1814,6 @@ static void __init build_r4000_tlb_modify_handler(void)
+ {
  	u32 *p = handle_tlbm;
- 	struct label *l = labels;
- 	struct reloc *r = relocs;
+-	struct label *l = labels;
+-	struct reloc *r = relocs;
 -	int i;
++	struct uasm_label *l = labels;
++	struct uasm_reloc *r = relocs;
  
  	memset(handle_tlbm, 0, sizeof(handle_tlbm));
  	memset(labels, 0, sizeof(labels));
-@@ -1856,11 +1838,7 @@ static void __init build_r4000_tlb_modify_handler(void)
- 	pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
- 		(unsigned int)(p - handle_tlbm));
+@@ -1845,22 +1209,18 @@ static void __init build_r4000_tlb_modify_handler(void)
+ 	build_make_write(&p, &r, K0, K1);
+ 	build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
+ 
+-	l_nopage_tlbm(&l, p);
+-	i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+-	i_nop(&p);
++	uasm_l_nopage_tlbm(&l, p);
++	uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
++	uasm_i_nop(&p);
+ 
+ 	if ((p - handle_tlbm) > FASTPATH_SIZE)
+ 		panic("TLB modify handler fastpath space exceeded");
+ 
+-	resolve_relocs(relocs, labels);
+-	pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
+-		(unsigned int)(p - handle_tlbm));
++	uasm_resolve_relocs(relocs, labels);
++	pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
++		 (unsigned int)(p - handle_tlbm));
  
 -	pr_debug("\t.set push\n");
 -	pr_debug("\t.set noreorder\n");
@@ -72136,6 +78783,786 @@
  }
  
  void __init build_tlb_refill_handler(void)
+diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
+new file mode 100644
+index 0000000..e3f74ed
+--- /dev/null
++++ b/arch/mips/mm/uasm.c
+@@ -0,0 +1,576 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * A small micro-assembler. It is intentionally kept simple, does only
++ * support a subset of instructions, and does not try to hide pipeline
++ * effects like branch delay slots.
++ *
++ * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
++ * Copyright (C) 2005, 2007  Maciej W. Rozycki
++ * Copyright (C) 2006  Ralf Baechle (ralf at linux-mips.org)
++ */
++
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/init.h>
++
++#include <asm/inst.h>
++#include <asm/elf.h>
++#include <asm/bugs.h>
++
++#include "uasm.h"
++
++enum fields {
++	RS = 0x001,
++	RT = 0x002,
++	RD = 0x004,
++	RE = 0x008,
++	SIMM = 0x010,
++	UIMM = 0x020,
++	BIMM = 0x040,
++	JIMM = 0x080,
++	FUNC = 0x100,
++	SET = 0x200
++};
++
++#define OP_MASK		0x3f
++#define OP_SH		26
++#define RS_MASK		0x1f
++#define RS_SH		21
++#define RT_MASK		0x1f
++#define RT_SH		16
++#define RD_MASK		0x1f
++#define RD_SH		11
++#define RE_MASK		0x1f
++#define RE_SH		6
++#define IMM_MASK	0xffff
++#define IMM_SH		0
++#define JIMM_MASK	0x3ffffff
++#define JIMM_SH		0
++#define FUNC_MASK	0x3f
++#define FUNC_SH		0
++#define SET_MASK	0x7
++#define SET_SH		0
++
++enum opcode {
++	insn_invalid,
++	insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
++	insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
++	insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
++	insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
++	insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
++	insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
++	insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
++	insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
++	insn_tlbwr, insn_xor, insn_xori
++};
++
++struct insn {
++	enum opcode opcode;
++	u32 match;
++	enum fields fields;
++};
++
++/* This macro sets the non-variable bits of an instruction. */
++#define M(a, b, c, d, e, f)					\
++	((a) << OP_SH						\
++	 | (b) << RS_SH						\
++	 | (c) << RT_SH						\
++	 | (d) << RD_SH						\
++	 | (e) << RE_SH						\
++	 | (f) << FUNC_SH)
++
++static struct insn insn_table[] __initdata = {
++	{ insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
++	{ insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
++	{ insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
++	{ insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
++	{ insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
++	{ insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
++	{ insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
++	{ insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
++	{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
++	{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
++	{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
++	{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
++	{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
++	{ insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
++	{ insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
++	{ insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
++	{ insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
++	{ insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
++	{ insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
++	{ insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
++	{ insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
++	{ insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
++	{ insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
++	{ insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
++	{ insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
++	{ insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
++	{ insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
++	{ insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
++	{ insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
++	{ insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
++	{ insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
++	{ insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
++	{ insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
++	{ insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
++	{ insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
++	{ insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
++	{ insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
++	{ insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
++	{ insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
++	{ insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
++	{ insn_invalid, 0, 0 }
++};
++
++#undef M
++
++static inline __init u32 build_rs(u32 arg)
++{
++	if (arg & ~RS_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return (arg & RS_MASK) << RS_SH;
++}
++
++static inline __init u32 build_rt(u32 arg)
++{
++	if (arg & ~RT_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return (arg & RT_MASK) << RT_SH;
++}
++
++static inline __init u32 build_rd(u32 arg)
++{
++	if (arg & ~RD_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return (arg & RD_MASK) << RD_SH;
++}
++
++static inline __init u32 build_re(u32 arg)
++{
++	if (arg & ~RE_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return (arg & RE_MASK) << RE_SH;
++}
++
++static inline __init u32 build_simm(s32 arg)
++{
++	if (arg > 0x7fff || arg < -0x8000)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return arg & 0xffff;
++}
++
++static inline __init u32 build_uimm(u32 arg)
++{
++	if (arg & ~IMM_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return arg & IMM_MASK;
++}
++
++static inline __init u32 build_bimm(s32 arg)
++{
++	if (arg > 0x1ffff || arg < -0x20000)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	if (arg & 0x3)
++		printk(KERN_WARNING "Invalid micro-assembler branch target\n");
++
++	return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
++}
++
++static inline __init u32 build_jimm(u32 arg)
++{
++	if (arg & ~((JIMM_MASK) << 2))
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return (arg >> 2) & JIMM_MASK;
++}
++
++static inline __init u32 build_func(u32 arg)
++{
++	if (arg & ~FUNC_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return arg & FUNC_MASK;
++}
++
++static inline __init u32 build_set(u32 arg)
++{
++	if (arg & ~SET_MASK)
++		printk(KERN_WARNING "Micro-assembler field overflow\n");
++
++	return arg & SET_MASK;
++}
++
++/*
++ * The order of opcode arguments is implicitly left to right,
++ * starting with RS and ending with FUNC or IMM.
++ */
++static void __init build_insn(u32 **buf, enum opcode opc, ...)
++{
++	struct insn *ip = NULL;
++	unsigned int i;
++	va_list ap;
++	u32 op;
++
++	for (i = 0; insn_table[i].opcode != insn_invalid; i++)
++		if (insn_table[i].opcode == opc) {
++			ip = &insn_table[i];
++			break;
++		}
++
++	if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
++		panic("Unsupported Micro-assembler instruction %d", opc);
++
++	op = ip->match;
++	va_start(ap, opc);
++	if (ip->fields & RS)
++		op |= build_rs(va_arg(ap, u32));
++	if (ip->fields & RT)
++		op |= build_rt(va_arg(ap, u32));
++	if (ip->fields & RD)
++		op |= build_rd(va_arg(ap, u32));
++	if (ip->fields & RE)
++		op |= build_re(va_arg(ap, u32));
++	if (ip->fields & SIMM)
++		op |= build_simm(va_arg(ap, s32));
++	if (ip->fields & UIMM)
++		op |= build_uimm(va_arg(ap, u32));
++	if (ip->fields & BIMM)
++		op |= build_bimm(va_arg(ap, s32));
++	if (ip->fields & JIMM)
++		op |= build_jimm(va_arg(ap, u32));
++	if (ip->fields & FUNC)
++		op |= build_func(va_arg(ap, u32));
++	if (ip->fields & SET)
++		op |= build_set(va_arg(ap, u32));
++	va_end(ap);
++
++	**buf = op;
++	(*buf)++;
++}
++
++#define I_u1u2u3(op)					\
++Ip_u1u2u3(op)						\
++{							\
++	build_insn(buf, insn##op, a, b, c);		\
++}
++
++#define I_u2u1u3(op)					\
++Ip_u2u1u3(op)						\
++{							\
++	build_insn(buf, insn##op, b, a, c);		\
++}
++
++#define I_u3u1u2(op)					\
++Ip_u3u1u2(op)						\
++{							\
++	build_insn(buf, insn##op, b, c, a);		\
++}
++
++#define I_u1u2s3(op)					\
++Ip_u1u2s3(op)						\
++{							\
++	build_insn(buf, insn##op, a, b, c);		\
++}
++
++#define I_u2s3u1(op)					\
++Ip_u2s3u1(op)						\
++{							\
++	build_insn(buf, insn##op, c, a, b);		\
++}
++
++#define I_u2u1s3(op)					\
++Ip_u2u1s3(op)						\
++{							\
++	build_insn(buf, insn##op, b, a, c);		\
++}
++
++#define I_u1u2(op)					\
++Ip_u1u2(op)						\
++{							\
++	build_insn(buf, insn##op, a, b);		\
++}
++
++#define I_u1s2(op)					\
++Ip_u1s2(op)						\
++{							\
++	build_insn(buf, insn##op, a, b);		\
++}
++
++#define I_u1(op)					\
++Ip_u1(op)						\
++{							\
++	build_insn(buf, insn##op, a);			\
++}
++
++#define I_0(op)						\
++Ip_0(op)						\
++{							\
++	build_insn(buf, insn##op);			\
++}
++
++I_u2u1s3(_addiu)
++I_u3u1u2(_addu)
++I_u2u1u3(_andi)
++I_u3u1u2(_and)
++I_u1u2s3(_beq)
++I_u1u2s3(_beql)
++I_u1s2(_bgez)
++I_u1s2(_bgezl)
++I_u1s2(_bltz)
++I_u1s2(_bltzl)
++I_u1u2s3(_bne)
++I_u1u2u3(_dmfc0)
++I_u1u2u3(_dmtc0)
++I_u2u1s3(_daddiu)
++I_u3u1u2(_daddu)
++I_u2u1u3(_dsll)
++I_u2u1u3(_dsll32)
++I_u2u1u3(_dsra)
++I_u2u1u3(_dsrl)
++I_u2u1u3(_dsrl32)
++I_u3u1u2(_dsubu)
++I_0(_eret)
++I_u1(_j)
++I_u1(_jal)
++I_u1(_jr)
++I_u2s3u1(_ld)
++I_u2s3u1(_ll)
++I_u2s3u1(_lld)
++I_u1s2(_lui)
++I_u2s3u1(_lw)
++I_u1u2u3(_mfc0)
++I_u1u2u3(_mtc0)
++I_u2u1u3(_ori)
++I_0(_rfe)
++I_u2s3u1(_sc)
++I_u2s3u1(_scd)
++I_u2s3u1(_sd)
++I_u2u1u3(_sll)
++I_u2u1u3(_sra)
++I_u2u1u3(_srl)
++I_u3u1u2(_subu)
++I_u2s3u1(_sw)
++I_0(_tlbp)
++I_0(_tlbwi)
++I_0(_tlbwr)
++I_u3u1u2(_xor)
++I_u2u1u3(_xori)
++
++/* Handle labels. */
++void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
++{
++	(*lab)->addr = addr;
++	(*lab)->lab = lid;
++	(*lab)++;
++}
++
++int __init uasm_in_compat_space_p(long addr)
++{
++	/* Is this address in 32bit compat space? */
++#ifdef CONFIG_64BIT
++	return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
++#else
++	return 1;
++#endif
++}
++
++int __init uasm_rel_highest(long val)
++{
++#ifdef CONFIG_64BIT
++	return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
++#else
++	return 0;
++#endif
++}
++
++int __init uasm_rel_higher(long val)
++{
++#ifdef CONFIG_64BIT
++	return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
++#else
++	return 0;
++#endif
++}
++
++int __init uasm_rel_hi(long val)
++{
++	return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
++}
++
++int __init uasm_rel_lo(long val)
++{
++	return ((val & 0xffff) ^ 0x8000) - 0x8000;
++}
++
++void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
++{
++	if (!uasm_in_compat_space_p(addr)) {
++		uasm_i_lui(buf, rs, uasm_rel_highest(addr));
++		if (uasm_rel_higher(addr))
++			uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr));
++		if (uasm_rel_hi(addr)) {
++			uasm_i_dsll(buf, rs, rs, 16);
++			uasm_i_daddiu(buf, rs, rs, uasm_rel_hi(addr));
++			uasm_i_dsll(buf, rs, rs, 16);
++		} else
++			uasm_i_dsll32(buf, rs, rs, 0);
++	} else
++		uasm_i_lui(buf, rs, uasm_rel_hi(addr));
++}
++
++void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr)
++{
++	UASM_i_LA_mostly(buf, rs, addr);
++	if (uasm_rel_lo(addr)) {
++		if (!uasm_in_compat_space_p(addr))
++			uasm_i_daddiu(buf, rs, rs, uasm_rel_lo(addr));
++		else
++			uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr));
++	}
++}
++
++/* Handle relocations. */
++void __init
++uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
++{
++	(*rel)->addr = addr;
++	(*rel)->type = R_MIPS_PC16;
++	(*rel)->lab = lid;
++	(*rel)++;
++}
++
++static inline void __init
++__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
++{
++	long laddr = (long)lab->addr;
++	long raddr = (long)rel->addr;
++
++	switch (rel->type) {
++	case R_MIPS_PC16:
++		*rel->addr |= build_bimm(laddr - (raddr + 4));
++		break;
++
++	default:
++		panic("Unsupported Micro-assembler relocation %d",
++		      rel->type);
++	}
++}
++
++void __init
++uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
++{
++	struct uasm_label *l;
++
++	for (; rel->lab != UASM_LABEL_INVALID; rel++)
++		for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
++			if (rel->lab == l->lab)
++				__resolve_relocs(rel, l);
++}
++
++void __init
++uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
++{
++	for (; rel->lab != UASM_LABEL_INVALID; rel++)
++		if (rel->addr >= first && rel->addr < end)
++			rel->addr += off;
++}
++
++void __init
++uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off)
++{
++	for (; lab->lab != UASM_LABEL_INVALID; lab++)
++		if (lab->addr >= first && lab->addr < end)
++			lab->addr += off;
++}
++
++void __init
++uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
++		  u32 *end, u32 *target)
++{
++	long off = (long)(target - first);
++
++	memcpy(target, first, (end - first) * sizeof(u32));
++
++	uasm_move_relocs(rel, first, end, off);
++	uasm_move_labels(lab, first, end, off);
++}
++
++int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
++{
++	for (; rel->lab != UASM_LABEL_INVALID; rel++) {
++		if (rel->addr == addr
++		    && (rel->type == R_MIPS_PC16
++			|| rel->type == R_MIPS_26))
++			return 1;
++	}
++
++	return 0;
++}
++
++/* Convenience functions for labeled branches. */
++void __init
++uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_bltz(p, reg, 0);
++}
++
++void __init
++uasm_il_b(u32 **p, struct uasm_reloc **r, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_b(p, 0);
++}
++
++void __init
++uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_beqz(p, reg, 0);
++}
++
++void __init
++uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_beqzl(p, reg, 0);
++}
++
++void __init
++uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_bnez(p, reg, 0);
++}
++
++void __init
++uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_bgezl(p, reg, 0);
++}
++
++void __init
++uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
++{
++	uasm_r_mips_pc16(r, *p, lid);
++	uasm_i_bgez(p, reg, 0);
++}
+diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h
+new file mode 100644
+index 0000000..a10fc11
+--- /dev/null
++++ b/arch/mips/mm/uasm.h
+@@ -0,0 +1,192 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
++ * Copyright (C) 2005  Maciej W. Rozycki
++ * Copyright (C) 2006  Ralf Baechle (ralf at linux-mips.org)
++ */
++
++#include <linux/types.h>
++
++#define Ip_u1u2u3(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
++
++#define Ip_u2u1u3(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
++
++#define Ip_u3u1u2(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
++
++#define Ip_u1u2s3(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
++
++#define Ip_u2s3u1(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c)
++
++#define Ip_u2u1s3(op)							\
++void __init								\
++uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
++
++#define Ip_u1u2(op)							\
++void __init uasm_i##op(u32 **buf, unsigned int a, unsigned int b)
++
++#define Ip_u1s2(op)							\
++void __init uasm_i##op(u32 **buf, unsigned int a, signed int b)
++
++#define Ip_u1(op) void __init uasm_i##op(u32 **buf, unsigned int a)
++
++#define Ip_0(op) void __init uasm_i##op(u32 **buf)
++
++Ip_u2u1s3(_addiu);
++Ip_u3u1u2(_addu);
++Ip_u2u1u3(_andi);
++Ip_u3u1u2(_and);
++Ip_u1u2s3(_beq);
++Ip_u1u2s3(_beql);
++Ip_u1s2(_bgez);
++Ip_u1s2(_bgezl);
++Ip_u1s2(_bltz);
++Ip_u1s2(_bltzl);
++Ip_u1u2s3(_bne);
++Ip_u1u2u3(_dmfc0);
++Ip_u1u2u3(_dmtc0);
++Ip_u2u1s3(_daddiu);
++Ip_u3u1u2(_daddu);
++Ip_u2u1u3(_dsll);
++Ip_u2u1u3(_dsll32);
++Ip_u2u1u3(_dsra);
++Ip_u2u1u3(_dsrl);
++Ip_u2u1u3(_dsrl32);
++Ip_u3u1u2(_dsubu);
++Ip_0(_eret);
++Ip_u1(_j);
++Ip_u1(_jal);
++Ip_u1(_jr);
++Ip_u2s3u1(_ld);
++Ip_u2s3u1(_ll);
++Ip_u2s3u1(_lld);
++Ip_u1s2(_lui);
++Ip_u2s3u1(_lw);
++Ip_u1u2u3(_mfc0);
++Ip_u1u2u3(_mtc0);
++Ip_u2u1u3(_ori);
++Ip_0(_rfe);
++Ip_u2s3u1(_sc);
++Ip_u2s3u1(_scd);
++Ip_u2s3u1(_sd);
++Ip_u2u1u3(_sll);
++Ip_u2u1u3(_sra);
++Ip_u2u1u3(_srl);
++Ip_u3u1u2(_subu);
++Ip_u2s3u1(_sw);
++Ip_0(_tlbp);
++Ip_0(_tlbwi);
++Ip_0(_tlbwr);
++Ip_u3u1u2(_xor);
++Ip_u2u1u3(_xori);
++
++/* Handle labels. */
++struct uasm_label {
++	u32 *addr;
++	int lab;
++};
++
++void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid);
++#ifdef CONFIG_64BIT
++int __init uasm_in_compat_space_p(long addr);
++int __init uasm_rel_highest(long val);
++int __init uasm_rel_higher(long val);
++#endif
++int __init uasm_rel_hi(long val);
++int __init uasm_rel_lo(long val);
++void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr);
++void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr);
++
++#define UASM_L_LA(lb)							\
++static inline void __init uasm_l##lb(struct uasm_label **lab, u32 *addr) \
++{									\
++	uasm_build_label(lab, addr, label##lb);				\
++}
++
++/* convenience macros for instructions */
++#ifdef CONFIG_64BIT
++# define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off)
++# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
++# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
++# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
++# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
++# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
++# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
++# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
++# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
++# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
++# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
++# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
++#else
++# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
++# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
++# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
++# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
++# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
++# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
++# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
++# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
++# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
++# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
++# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
++# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
++#endif
++
++#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
++#define uasm_i_beqz(buf, rs, off) uasm_i_beq(buf, rs, 0, off)
++#define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off)
++#define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off)
++#define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
++#define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
++#define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
++#define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
++#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
++
++/* Handle relocations. */
++struct uasm_reloc {
++	u32 *addr;
++	unsigned int type;
++	int lab;
++};
++
++/* This is zero so we can use zeroed label arrays. */
++#define UASM_LABEL_INVALID 0
++
++void __init uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid);
++void __init
++uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab);
++void __init
++uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off);
++void __init
++uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off);
++void __init
++uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
++		  u32 *end, u32 *target);
++int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr);
++
++/* Convenience functions for labeled branches. */
++void __init
++uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
++void __init uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
++void __init
++uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
++void __init
++uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
++void __init
++uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
++void __init
++uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
++void __init
++uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
 index bdfa07a..ccbea22 100644
 --- a/arch/mips/oprofile/op_model_mipsxx.c
@@ -75657,7 +83084,7 @@
  #ifdef CONFIG_BLK_DEV_INITRD
  	. = ALIGN(PAGE_SIZE);
 diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
-index 232c298..9c44af3 100644
+index 232c298..4a22c99 100644
 --- a/arch/powerpc/Kconfig
 +++ b/arch/powerpc/Kconfig
 @@ -42,6 +42,9 @@ config GENERIC_HARDIRQS
@@ -75682,17 +83109,38 @@
  config ARCH_HAS_ILOG2_U32
  	bool
  	default y
-@@ -140,6 +148,9 @@ config DEFAULT_UIMAGE
+@@ -140,11 +148,28 @@ config DEFAULT_UIMAGE
  	  Used to allow a board to specify it wants a uImage built by default
  	default n
  
+-config PPC64_SWSUSP
 +config REDBOOT
+ 	bool
+-	depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
++
++config HIBERNATE_32
++	bool
++	depends on (PPC_PMAC && !SMP) || BROKEN
+ 	default y
+ 
++config HIBERNATE_64
++	bool
++	depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
++	default y
++
++config ARCH_HIBERNATION_POSSIBLE
 +	bool
++	depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
++	default y
++
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
 +
- config PPC64_SWSUSP
+ config PPC_DCR_NATIVE
  	bool
- 	depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
-@@ -160,11 +171,13 @@ config PPC_DCR
+ 	default n
+@@ -160,11 +185,13 @@ config PPC_DCR
  
  config PPC_OF_PLATFORM_PCI
  	bool
@@ -75706,7 +83154,7 @@
  source "arch/powerpc/platforms/Kconfig"
  
  menu "Kernel options"
-@@ -340,6 +353,14 @@ config PPC_64K_PAGES
+@@ -340,6 +367,14 @@ config PPC_64K_PAGES
  	  while on hardware with such support, it will be used to map
  	  normal application pages.
  
@@ -75721,7 +83169,18 @@
  config SCHED_SMT
  	bool "SMT (Hyperthreading) scheduler support"
  	depends on PPC64 && SMP
-@@ -417,7 +438,7 @@ endmenu
+@@ -370,6 +405,10 @@ config CMDLINE
+ 	  most cases you will need to specify the root device here.
+ 
+ if !44x || BROKEN
++config ARCH_WANTS_FREEZER_CONTROL
++	def_bool y
++	depends on ADB_PMU
++
+ source kernel/power/Kconfig
+ endif
+ 
+@@ -417,7 +456,7 @@ endmenu
  
  config ISA_DMA_API
  	bool
@@ -75730,7 +83189,7 @@
  
  menu "Bus options"
  
-@@ -467,7 +488,7 @@ config MCA
+@@ -467,7 +506,7 @@ config MCA
  config PCI
  	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
  		|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
@@ -139128,9 +146587,18 @@
  
  /*
 diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
-index ffa14af..c0f13e8 100644
+index ffa14af..41c7fd9 100644
 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c
 +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
+@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state)
+ 	}
+ }
+ 
+-static int lite5200_pm_set_target(suspend_state_t state)
++static int lite5200_pm_begin(suspend_state_t state)
+ {
+ 	if (lite5200_pm_valid(state)) {
+ 		lite5200_pm_target_state = state;
 @@ -42,6 +42,15 @@ static int lite5200_pm_set_target(suspend_state_t state)
  
  static int lite5200_pm_prepare(void)
@@ -139158,6 +146626,26 @@
  	if (!mbar) {
  		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
  		return -ENOSYS;
+@@ -208,12 +219,18 @@ static void lite5200_pm_finish(void)
+ 		mpc52xx_pm_finish();
+ }
+ 
++static void lite5200_pm_end(void)
++{
++	lite5200_pm_target_state = PM_SUSPEND_ON;
++}
++
+ static struct platform_suspend_ops lite5200_pm_ops = {
+ 	.valid		= lite5200_pm_valid,
+-	.set_target	= lite5200_pm_set_target,
++	.begin		= lite5200_pm_begin,
+ 	.prepare	= lite5200_pm_prepare,
+ 	.enter		= lite5200_pm_enter,
+ 	.finish		= lite5200_pm_finish,
++	.end		= lite5200_pm_end,
+ };
+ 
+ int __init lite5200_pm_init(void)
 diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
 new file mode 100644
 index 0000000..c48b82b
@@ -150468,7 +157956,7 @@
  static int __init idle_param(char *p)
  {
 diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
-index 9916a0f..c5cfd4b 100644
+index 9916a0f..5803f11 100644
 --- a/arch/powerpc/platforms/pasemi/iommu.c
 +++ b/arch/powerpc/platforms/pasemi/iommu.c
 @@ -182,8 +182,10 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
@@ -150478,7 +157966,7 @@
 -	    !firmware_has_feature(FW_FEATURE_LPAR))
 +	    !firmware_has_feature(FW_FEATURE_LPAR)) {
  		dev->dev.archdata.dma_ops = &dma_direct_ops;
-+		dev->dev.archdata.dma_data = 0;
++		return;
 +	}
  #endif
  
@@ -184669,7 +192157,7 @@
  			continue;
  		seg = kzalloc(sizeof(*seg), GFP_KERNEL);
 diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
-index 496d635..1cd9c8f 100644
+index 496d635..b30c4c3 100644
 --- a/arch/sh/Kconfig
 +++ b/arch/sh/Kconfig
 @@ -6,8 +6,7 @@
@@ -184767,8 +192255,7 @@
 +#
 +config CPU_SH2
 +	bool
- 
--menu "Processor features"
++
 +config CPU_SH2A
 +	bool
 +	select CPU_SH2
@@ -184800,7 +192287,8 @@
 +
 +config CPU_SHX2
 +	bool
-+
+ 
+-menu "Processor features"
 +config CPU_SHX3
 +	bool
  
@@ -184837,18 +192325,18 @@
 +config CPU_SUBTYPE_SH7206
 +	bool "Support SH7206 processor"
 +	select CPU_SH2A
- 
--config SH_FPU
--	bool "FPU support"
--	depends on CPU_HAS_FPU
--	default y
++
 +config CPU_SUBTYPE_SH7263
 +	bool "Support SH7263 processor"
 +	select CPU_SH2A
 +	select CPU_HAS_FPU
 +
 +# SH-3 Processor Support
-+
+ 
+-config SH_FPU
+-	bool "FPU support"
+-	depends on CPU_HAS_FPU
+-	default y
 +config CPU_SUBTYPE_SH7705
 +	bool "Support SH7705 processor"
 +	select CPU_SH3
@@ -184934,12 +192422,12 @@
 -	  Selecting this option will enable an in-kernel API for manipulating
 -	  the store queues integrated in the SH-4 processors.
 +	  Select SH7721 if you have a SH3-DSP SH7721 CPU.
++
++# SH-4 Processor Support
  
 -config SPECULATIVE_EXECUTION
 -	bool "Speculative subroutine return"
 -	depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
-+# SH-4 Processor Support
-+
 +config CPU_SUBTYPE_SH7750
 +	bool "Support SH7750 processor"
 +	select CPU_SH4
@@ -185205,6 +192693,17 @@
  endmenu
  
  menu "Boot options"
+@@ -746,6 +882,10 @@ endmenu
+ menu "Power management options (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && SYS_SUPPORTS_PM
+ 
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on !SMP
++
+ source kernel/power/Kconfig
+ 
+ endmenu
 diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
 new file mode 100644
 index 0000000..d850184
@@ -194307,6 +201806,22 @@
  };
  EXPORT_SYMBOL(dma_sysclass);
  
+diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
+index fbc6f2c..7e816ed 100644
+--- a/arch/sh/drivers/pci/Kconfig
++++ b/arch/sh/drivers/pci/Kconfig
+@@ -6,11 +6,6 @@ config PCI
+ 	  bus system, i.e. the way the CPU talks to the other stuff inside
+ 	  your box. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config SH_PCIDMA_NONCOHERENT
+ 	bool "Cache and PCI noncoherent"
+ 	depends on PCI
 diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
 index fba6b5b..0718805 100644
 --- a/arch/sh/drivers/pci/Makefile
@@ -241131,8 +248646,21 @@
  		*(.exitcall.exit)
  	}
  
+diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S
+index 2065774..f406b1f 100644
+--- a/arch/sparc/lib/rwsem.S
++++ b/arch/sparc/lib/rwsem.S
+@@ -7,7 +7,7 @@
+ #include <asm/ptrace.h>
+ #include <asm/psr.h>
+ 
+-	.section .sched.text
++	.section .sched.text, "ax"
+ 	.align	4
+ 
+ 	.globl		___down_read
 diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
-index 10b212a..73fc05d 100644
+index 10b212a..158522f 100644
 --- a/arch/sparc64/Kconfig
 +++ b/arch/sparc64/Kconfig
 @@ -66,6 +66,9 @@ config AUDIT_ARCH
@@ -241157,6 +248685,18 @@
  config RWSEM_GENERIC_SPINLOCK
  	bool
  
+@@ -343,11 +351,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ config PCI_DOMAINS
+ 	def_bool PCI
+ 
 diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
 index 953be81..dc7bf1b 100644
 --- a/arch/sparc64/kernel/unaligned.c
@@ -241199,6 +248739,45 @@
  		*(.exitcall.exit)
  	}
  
+diff --git a/arch/sparc64/lib/GENbzero.S b/arch/sparc64/lib/GENbzero.S
+index f9c71d6..6a4f956 100644
+--- a/arch/sparc64/lib/GENbzero.S
++++ b/arch/sparc64/lib/GENbzero.S
+@@ -10,7 +10,7 @@
+ 	.align 4;		\
+ 99:	retl;			\
+ 	 mov	%o1, %o0;	\
+-	.section __ex_table;	\
++	.section __ex_table,"a";\
+ 	.align 4;		\
+ 	.word 98b, 99b;		\
+ 	.text;			\
+diff --git a/arch/sparc64/lib/NGbzero.S b/arch/sparc64/lib/NGbzero.S
+index f10e452..814d5f7 100644
+--- a/arch/sparc64/lib/NGbzero.S
++++ b/arch/sparc64/lib/NGbzero.S
+@@ -10,7 +10,7 @@
+ 	.align 4;		\
+ 99:	retl;			\
+ 	 mov	%o1, %o0;	\
+-	.section __ex_table;	\
++	.section __ex_table,"a";\
+ 	.align 4;		\
+ 	.word 98b, 99b;		\
+ 	.text;			\
+diff --git a/arch/sparc64/lib/rwsem.S b/arch/sparc64/lib/rwsem.S
+index 75f0e6b..1a4cc56 100644
+--- a/arch/sparc64/lib/rwsem.S
++++ b/arch/sparc64/lib/rwsem.S
+@@ -6,7 +6,7 @@
+ 
+ #include <asm/rwsem-const.h>
+ 
+-	.section	.sched.text
++	.section	.sched.text, "ax"
+ 
+ 	.globl		__down_read
+ __down_read:
 diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
 index fbeb55d..523e993 100644
 --- a/arch/sparc64/mm/init.c
@@ -241606,10 +249185,10 @@
  			*(.text.init)	/* 2.4 convention */		      \
  		INITCALL_CONTENTS					      \
 diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
-index 80b7ba4..65b4491 100644
+index 80b7ba4..7109037 100644
 --- a/arch/x86/Kconfig
 +++ b/arch/x86/Kconfig
-@@ -17,81 +17,69 @@ config X86_64
+@@ -17,81 +17,72 @@ config X86_64
  
  ### Arch settings
  config X86
@@ -241655,6 +249234,9 @@
 -	bool
 -	default y
 +	def_bool y
++
++config HAVE_LATENCYTOP_SUPPORT
++	def_bool y
  
  config SEMAPHORE_SLEEPERS
 -	bool
@@ -241715,7 +249297,7 @@
  
  config RWSEM_GENERIC_SPINLOCK
  	def_bool !X86_XADD
-@@ -112,10 +100,14 @@ config GENERIC_TIME_VSYSCALL
+@@ -112,10 +103,22 @@ config GENERIC_TIME_VSYSCALL
  	bool
  	default X86_64
  
@@ -241727,10 +249309,18 @@
  	default y
  
 +select HAVE_KVM
++
++config ARCH_HIBERNATION_POSSIBLE
++	def_bool y
++	depends on !SMP || !X86_VOYAGER
++
++config ARCH_SUSPEND_POSSIBLE
++	def_bool y
++	depends on !X86_VOYAGER
  
  config ZONE_DMA32
  	bool
-@@ -144,9 +136,17 @@ config GENERIC_PENDING_IRQ
+@@ -144,9 +147,17 @@ config GENERIC_PENDING_IRQ
  
  config X86_SMP
  	bool
@@ -241749,7 +249339,7 @@
  config X86_HT
  	bool
  	depends on SMP
-@@ -292,6 +292,18 @@ config X86_ES7000
+@@ -292,6 +303,18 @@ config X86_ES7000
  	  Only choose this option if you have such a system, otherwise you
  	  should say N here.
  
@@ -241768,7 +249358,7 @@
  config X86_VSMP
  	bool "Support for ScaleMP vSMP"
  	depends on X86_64 && PCI
-@@ -303,8 +315,8 @@ config X86_VSMP
+@@ -303,8 +326,8 @@ config X86_VSMP
  endchoice
  
  config SCHED_NO_NO_OMIT_FRAME_POINTER
@@ -241779,7 +249369,7 @@
  	depends on X86_32
  	help
  	  Calculate simpler /proc/<PID>/wchan values. If this option
-@@ -314,18 +326,8 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
+@@ -314,18 +337,8 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
  
  	  If in doubt, say "Y".
  
@@ -241798,7 +249388,7 @@
  	help
  	  Say Y here to get to see options related to running Linux under
  	  various hypervisors.  This option alone does not add any kernel code.
-@@ -339,6 +341,7 @@ source "arch/x86/xen/Kconfig"
+@@ -339,6 +352,7 @@ source "arch/x86/xen/Kconfig"
  config VMI
  	bool "VMI Guest support"
  	select PARAVIRT
@@ -241806,7 +249396,7 @@
  	depends on !(X86_VISWS || X86_VOYAGER)
  	help
  	  VMI provides a paravirtualized interface to the VMware ESX server
-@@ -348,40 +351,43 @@ config VMI
+@@ -348,40 +362,43 @@ config VMI
  
  source "arch/x86/lguest/Kconfig"
  
@@ -241863,7 +249453,7 @@
  	help
           Use the IA-PC HPET (High Precision Event Timer) to manage
           time in preference to the PIT and RTC, if a HPET is
-@@ -399,9 +405,8 @@ config HPET_TIMER
+@@ -399,9 +416,8 @@ config HPET_TIMER
           Choose N to continue using the legacy 8254 timer.
  
  config HPET_EMULATE_RTC
@@ -241875,7 +249465,7 @@
  
  # Mark as embedded because too many people got it wrong.
  # The code disables itself when not needed.
-@@ -441,8 +446,8 @@ config CALGARY_IOMMU
+@@ -441,8 +457,8 @@ config CALGARY_IOMMU
  	  If unsure, say Y.
  
  config CALGARY_IOMMU_ENABLED_BY_DEFAULT
@@ -241886,7 +249476,7 @@
  	depends on CALGARY_IOMMU
  	help
  	  Should Calgary be enabled by default? if you choose 'y', Calgary
-@@ -486,9 +491,9 @@ config SCHED_SMT
+@@ -486,9 +502,9 @@ config SCHED_SMT
  	  N here.
  
  config SCHED_MC
@@ -241898,7 +249488,7 @@
  	help
  	  Multi-core scheduler support improves the CPU scheduler's decision
  	  making when dealing with multi-core CPU chips at a cost of slightly
-@@ -522,19 +527,16 @@ config X86_UP_IOAPIC
+@@ -522,19 +538,16 @@ config X86_UP_IOAPIC
  	  an IO-APIC, then the kernel will still run with no slowdown at all.
  
  config X86_LOCAL_APIC
@@ -241921,7 +249511,7 @@
  
  config X86_MCE
  	bool "Machine Check Exception"
-@@ -554,17 +556,17 @@ config X86_MCE
+@@ -554,17 +567,17 @@ config X86_MCE
  	  the 386 and 486, so nearly everyone can say Y here.
  
  config X86_MCE_INTEL
@@ -241943,7 +249533,7 @@
  	help
  	   Additional support for AMD specific MCE features such as
  	   the DRAM Error Threshold.
-@@ -637,9 +639,9 @@ config I8K
+@@ -637,9 +650,9 @@ config I8K
  	  Say N otherwise.
  
  config X86_REBOOTFIXUPS
@@ -241955,7 +249545,7 @@
  	---help---
  	  This enables chipset and/or board specific fixups to be done
  	  in order to get reboot to work correctly. This is only needed on
-@@ -648,7 +650,7 @@ config X86_REBOOTFIXUPS
+@@ -648,7 +661,7 @@ config X86_REBOOTFIXUPS
  	  system.
  
  	  Currently, the only fixup is for the Geode machines using
@@ -241964,7 +249554,7 @@
  
  	  Say Y if you want to enable the fixup. Currently, it's safe to
  	  enable this option even if you don't need it.
-@@ -672,9 +674,8 @@ config MICROCODE
+@@ -672,9 +685,8 @@ config MICROCODE
  	  module will be called microcode.
  
  config MICROCODE_OLD_INTERFACE
@@ -241975,7 +249565,7 @@
  
  config X86_MSR
  	tristate "/dev/cpu/*/msr - Model-specific register support"
-@@ -798,13 +799,12 @@ config PAGE_OFFSET
+@@ -798,13 +810,12 @@ config PAGE_OFFSET
  	depends on X86_32
  
  config HIGHMEM
@@ -241992,7 +249582,7 @@
  	depends on X86_32 && !HIGHMEM4G
  	select RESOURCES_64BIT
  	help
-@@ -836,10 +836,10 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
+@@ -836,10 +847,10 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
  	depends on X86_32 && X86_SUMMIT && (!HIGHMEM64G || !ACPI)
  
  config K8_NUMA
@@ -242007,7 +249597,7 @@
  	 Enable K8 NUMA node topology detection.  You should say Y here if
  	 you have a multi processor AMD K8 system. This uses an old
  	 method to read the NUMA configuration directly from the builtin
-@@ -847,10 +847,10 @@ config K8_NUMA
+@@ -847,10 +858,10 @@ config K8_NUMA
  	 instead, which also takes priority if both are compiled in.
  
  config X86_64_ACPI_NUMA
@@ -242020,7 +249610,7 @@
  	help
  	  Enable ACPI SRAT based node topology detection.
  
-@@ -864,52 +864,53 @@ config NUMA_EMU
+@@ -864,52 +875,53 @@ config NUMA_EMU
  
  config NODES_SHIFT
  	int
@@ -242087,7 +249677,7 @@
  
  config ARCH_MEMORY_PROBE
  	def_bool X86_64
-@@ -987,42 +988,32 @@ config MTRR
+@@ -987,42 +999,32 @@ config MTRR
  	  See <file:Documentation/mtrr.txt> for more information.
  
  config EFI
@@ -242144,7 +249734,7 @@
  	help
  	  This kernel feature is useful for number crunching applications
  	  that may need to compute untrusted bytecode during their
-@@ -1189,11 +1180,11 @@ config HOTPLUG_CPU
+@@ -1189,11 +1191,11 @@ config HOTPLUG_CPU
  	  suspend.
  
  config COMPAT_VDSO
@@ -242160,7 +249750,7 @@
  	---help---
  	  Say N here if you are running a sufficiently recent glibc
  	  version (2.3.3 or later), to remove the high-mapped
-@@ -1207,30 +1198,26 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
+@@ -1207,30 +1209,26 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
  	def_bool y
  	depends on X86_64 || (X86_32 && HIGHMEM)
  
@@ -242197,7 +249787,7 @@
  menuconfig APM
  	tristate "APM (Advanced Power Management) BIOS support"
  	depends on X86_32 && PM_SLEEP && !X86_VISWS
-@@ -1371,7 +1358,7 @@ menu "Bus options (PCI etc.)"
+@@ -1371,7 +1369,7 @@ menu "Bus options (PCI etc.)"
  config PCI
  	bool "PCI support" if !X86_VISWS
  	depends on !X86_VOYAGER
@@ -242206,7 +249796,19 @@
  	select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
  	help
  	  Find out whether you have a PCI motherboard. PCI is the name of a
-@@ -1418,25 +1405,21 @@ config PCI_GOANY
+@@ -1379,11 +1377,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.tldp.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't.
+-
+ choice
+ 	prompt "PCI access mode"
+ 	depends on X86_32 && PCI && !X86_VISWS
+@@ -1418,25 +1411,21 @@ config PCI_GOANY
  endchoice
  
  config PCI_BIOS
@@ -242236,7 +249838,7 @@
  
  config PCI_MMCONFIG
  	bool "Support mmconfig PCI config space access"
-@@ -1453,9 +1436,9 @@ config DMAR
+@@ -1453,9 +1442,9 @@ config DMAR
  	  remapping devices.
  
  config DMAR_GFX_WA
@@ -242248,7 +249850,7 @@
  	help
  	 Current Graphics drivers tend to use physical address
  	 for DMA and avoid using DMA APIs. Setting this config
-@@ -1464,9 +1447,8 @@ config DMAR_GFX_WA
+@@ -1464,9 +1453,8 @@ config DMAR_GFX_WA
  	 to use physical addresses for DMA.
  
  config DMAR_FLOPPY_WA
@@ -242259,7 +249861,7 @@
  	help
  	 Floppy disk drivers are know to bypass DMA API calls
  	 thereby failing to work when IOMMU is enabled. This
-@@ -1479,8 +1461,7 @@ source "drivers/pci/Kconfig"
+@@ -1479,8 +1467,7 @@ source "drivers/pci/Kconfig"
  
  # x86_64 have no ISA slots, but do have ISA-style DMA.
  config ISA_DMA_API
@@ -242269,7 +249871,7 @@
  
  if X86_32
  
-@@ -1546,9 +1527,9 @@ config SCx200HR_TIMER
+@@ -1546,9 +1533,9 @@ config SCx200HR_TIMER
  	  other workaround is idle=poll boot option.
  
  config GEODE_MFGPT_TIMER
@@ -242281,7 +249883,7 @@
  	help
  	  This driver provides a clock event source based on the MFGPT
  	  timer(s) in the CS5535 and CS5536 companion chip for the geode.
-@@ -1575,6 +1556,7 @@ source "fs/Kconfig.binfmt"
+@@ -1575,6 +1562,7 @@ source "fs/Kconfig.binfmt"
  config IA32_EMULATION
  	bool "IA32 Emulation"
  	depends on X86_64
@@ -242289,7 +249891,7 @@
  	help
  	  Include code to run 32-bit programs under a 64-bit kernel. You should
  	  likely turn this on, unless you're 100% sure that you don't have any
-@@ -1587,18 +1569,16 @@ config IA32_AOUT
+@@ -1587,18 +1575,16 @@ config IA32_AOUT
           Support old a.out binaries in the 32bit emulation.
  
  config COMPAT
@@ -242310,7 +249912,7 @@
  
  endmenu
  
-@@ -1619,4 +1599,6 @@ source "security/Kconfig"
+@@ -1619,4 +1605,6 @@ source "security/Kconfig"
  
  source "crypto/Kconfig"
  
@@ -242628,7 +250230,7 @@
 +
  endmenu
 diff --git a/arch/x86/Makefile b/arch/x86/Makefile
-index 7aa1dc6..da8f412 100644
+index 7aa1dc6..8978e98 100644
 --- a/arch/x86/Makefile
 +++ b/arch/x86/Makefile
 @@ -7,13 +7,254 @@ else
@@ -242775,7 +250377,7 @@
 +
 +# RDC R-321x subarch support
 +mflags-$(CONFIG_X86_RDC321X)	:= -Iinclude/asm-x86/mach-rdc321x
-+mcore-$(CONFIG_X86_RDC321X)	:= arch/x86/mach-default
++mcore-$(CONFIG_X86_RDC321X)	:= arch/x86/mach-default/
 +core-$(CONFIG_X86_RDC321X)	+= arch/x86/mach-rdc321x/
 +
 +# default subarch .h files
@@ -244846,7 +252448,7 @@
 -	}
 -}
 diff --git a/arch/x86/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux_64.lds
-index 94c13e5..f6e5b44 100644
+index 94c13e5..7e5c720 100644
 --- a/arch/x86/boot/compressed/vmlinux_64.lds
 +++ b/arch/x86/boot/compressed/vmlinux_64.lds
 @@ -3,15 +3,19 @@ OUTPUT_ARCH(i386:x86-64)
@@ -244855,7 +252457,7 @@
  {
 -	/* Be careful parts of head.S assume startup_32 is at
 - 	 * address 0.
-+	/* Be careful parts of head_64.S assume startup_64 is at
++	/* Be careful parts of head_64.S assume startup_32 is at
 +	 * address 0.
  	 */
  	. = 0;
@@ -253328,6 +260930,32 @@
  
  ifneq ($(CONFIG_ACPI_PROCESSOR),)
  obj-y				+= cstate.o processor.o
+diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
+index 0ca27c7..d2a5843 100644
+--- a/arch/x86/kernel/acpi/boot.c
++++ b/arch/x86/kernel/acpi/boot.c
+@@ -496,7 +496,8 @@ EXPORT_SYMBOL(acpi_register_gsi);
+  *  ACPI based hotplug support for CPU
+  */
+ #ifdef CONFIG_ACPI_HOTPLUG_CPU
+-int acpi_map_lsapic(acpi_handle handle, int *pcpu)
++
++static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
+ {
+ 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ 	union acpi_object *obj;
+@@ -551,6 +552,11 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
+ 	return 0;
+ }
+ 
++/* wrapper to silence section mismatch warning */
++int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
++{
++	return _acpi_map_lsapic(handle, pcpu);
++}
+ EXPORT_SYMBOL(acpi_map_lsapic);
+ 
+ int acpi_unmap_lsapic(int cpu)
 diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
 new file mode 100644
 index 0000000..6bc815c
@@ -257430,7 +265058,7 @@
  	}
  }
 diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
-index 1ff88c7..06fa159 100644
+index 1ff88c7..693e353 100644
 --- a/arch/x86/kernel/cpu/amd.c
 +++ b/arch/x86/kernel/cpu/amd.c
 @@ -63,6 +63,15 @@ static __cpuinit int amd_apic_timer_broken(void)
@@ -257482,7 +265110,7 @@
  	if (c->x86 < 6)
  		clear_bit(X86_FEATURE_MCE, c->x86_capability);
 +
-+	if (cpu_has_xmm)
++	if (cpu_has_xmm2)
 +		set_bit(X86_FEATURE_MFENCE_RDTSC, c->x86_capability);
  }
  
@@ -257518,7 +265146,7 @@
  #endif
  
 diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
-index e2fcf20..d608c9e 100644
+index e2fcf20..b7b2142 100644
 --- a/arch/x86/kernel/cpu/common.c
 +++ b/arch/x86/kernel/cpu/common.c
 @@ -22,43 +22,48 @@
@@ -257616,7 +265244,22 @@
  	return 1;
  }
  __setup("nosep", x86_sep_setup);
-@@ -277,10 +274,39 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
+@@ -261,10 +258,10 @@ static int __cpuinit have_cpuid_p(void)
+ void __init cpu_detect(struct cpuinfo_x86 *c)
+ {
+ 	/* Get vendor name */
+-	cpuid(0x00000000, &c->cpuid_level,
+-	      (int *)&c->x86_vendor_id[0],
+-	      (int *)&c->x86_vendor_id[8],
+-	      (int *)&c->x86_vendor_id[4]);
++	cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
++	      (unsigned int *)&c->x86_vendor_id[0],
++	      (unsigned int *)&c->x86_vendor_id[8],
++	      (unsigned int *)&c->x86_vendor_id[4]);
+ 
+ 	c->x86 = 4;
+ 	if (c->cpuid_level >= 0x00000001) {
+@@ -277,9 +274,38 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
  		if (c->x86 >= 0x6)
  			c->x86_model += ((tfms >> 16) & 0xF) << 4;
  		c->x86_mask = tfms & 15;
@@ -257625,12 +265268,12 @@
  			c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
 +			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
 +		}
- 	}
- }
++	}
++}
 +static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
 +{
 +	u32 tfms, xlvl;
-+	int ebx;
++	unsigned int ebx;
 +
 +	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 +	if (have_cpuid_p()) {
@@ -257651,12 +265294,11 @@
 +			}
 +		}
 +
-+	}
+ 	}
 +
-+}
+ }
  
  /* Do minimum CPU detection early.
-    Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
 @@ -293,6 +319,7 @@ static void __init early_cpu_detect(void)
  	struct cpuinfo_x86 *c = &boot_cpu_data;
  
@@ -257665,7 +265307,7 @@
  
  	if (!have_cpuid_p())
  		return;
-@@ -300,6 +327,17 @@ static void __init early_cpu_detect(void)
+@@ -300,19 +327,30 @@ static void __init early_cpu_detect(void)
  	cpu_detect(c);
  
  	get_cpu_vendor(c, 1);
@@ -257683,6 +265325,24 @@
  }
  
  static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
+ {
+ 	u32 tfms, xlvl;
+-	int ebx;
++	unsigned int ebx;
+ 
+ 	if (have_cpuid_p()) {
+ 		/* Get vendor name */
+-		cpuid(0x00000000, &c->cpuid_level,
+-		      (int *)&c->x86_vendor_id[0],
+-		      (int *)&c->x86_vendor_id[8],
+-		      (int *)&c->x86_vendor_id[4]);
++		cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
++		      (unsigned int *)&c->x86_vendor_id[0],
++		      (unsigned int *)&c->x86_vendor_id[8],
++		      (unsigned int *)&c->x86_vendor_id[4]);
+ 		
+ 		get_cpu_vendor(c, 0);
+ 		/* Initialize the standard set of capabilities */
 @@ -357,8 +395,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
  		init_scattered_cpuid_features(c);
  	}
@@ -259431,7 +267091,7 @@
  	.next	= c_next,
  	.stop	= c_stop,
 diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
-index 05c9936..dec66e4 100644
+index 05c9936..a63432d 100644
 --- a/arch/x86/kernel/cpuid.c
 +++ b/arch/x86/kernel/cpuid.c
 @@ -50,7 +50,7 @@ struct cpuid_command {
@@ -259443,7 +267103,7 @@
  
  	cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2],
  		      &cmd->data[3]);
-@@ -157,15 +157,15 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
+@@ -157,20 +157,20 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
  
  	switch (action) {
  	case CPU_UP_PREPARE:
@@ -259462,6 +267122,12 @@
  	}
  	return err ? NOTIFY_BAD : NOTIFY_OK;
  }
+ 
+-static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
++static struct notifier_block __refdata cpuid_class_cpu_notifier =
+ {
+ 	.notifier_call = cpuid_class_cpu_callback,
+ };
 diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
 index 40978af..a47798b 100644
 --- a/arch/x86/kernel/doublefault_32.c
@@ -260326,7 +267992,7 @@
 +	print_memory_map("modified");
 +}
 diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
-index 04698e0..c617174 100644
+index 04698e0..9f65b4c 100644
 --- a/arch/x86/kernel/e820_64.c
 +++ b/arch/x86/kernel/e820_64.c
 @@ -1,4 +1,4 @@
@@ -260335,7 +268001,7 @@
   * Handle the memory map.
   * The functions here do the job until bootmem takes over.
   *
-@@ -26,80 +26,87 @@
+@@ -26,80 +26,92 @@
  #include <asm/proto.h>
  #include <asm/setup.h>
  #include <asm/sections.h>
@@ -260405,11 +268071,12 @@
 +
 +struct early_res {
 +	unsigned long start, end;
++	char name[16];
 +};
 +static struct early_res early_res[MAX_EARLY_RES] __initdata = {
-+	{ 0, PAGE_SIZE },			/* BIOS data page */
++	{ 0, PAGE_SIZE, "BIOS data page" },			/* BIOS data page */
 +#ifdef CONFIG_SMP
-+	{ SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE },
++	{ SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" },
  #endif
 -	/* kernel code */
 -	if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) {
@@ -260418,21 +268085,23 @@
 +	{}
 +};
 +
-+void __init reserve_early(unsigned long start, unsigned long end)
++void __init reserve_early(unsigned long start, unsigned long end, char *name)
 +{
 +	int i;
 +	struct early_res *r;
 +	for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
 +		r = &early_res[i];
 +		if (end > r->start && start < r->end)
-+			panic("Overlapping early reservations %lx-%lx to %lx-%lx\n",
-+			      start, end, r->start, r->end);
++			panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n",
++			      start, end - 1, name?name:"", r->start, r->end - 1, r->name);
  	}
 +	if (i >= MAX_EARLY_RES)
 +		panic("Too many early reservations");
 +	r = &early_res[i];
 +	r->start = start;
 +	r->end = end;
++	if (name)
++		strncpy(r->name, name, sizeof(r->name) - 1);
 +}
  
 -	if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
@@ -260443,6 +268112,8 @@
 +	int i;
 +	for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
 +		struct early_res *r = &early_res[i];
++		printk(KERN_INFO "early res: %d [%lx-%lx] %s\n", i,
++			r->start, r->end - 1, r->name);
 +		reserve_bootmem_generic(r->start, r->end - r->start);
  	}
 +}
@@ -260477,7 +268148,7 @@
  
  /*
   * This function checks if any part of the range <start,end> is mapped
-@@ -107,16 +114,18 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size)
+@@ -107,16 +119,18 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size)
   */
  int
  e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
@@ -260503,7 +268174,7 @@
  	return 0;
  }
  EXPORT_SYMBOL_GPL(e820_any_mapped);
-@@ -127,11 +136,14 @@ EXPORT_SYMBOL_GPL(e820_any_mapped);
+@@ -127,11 +141,14 @@ EXPORT_SYMBOL_GPL(e820_any_mapped);
   * Note: this function only works correct if the e820 table is sorted and
   * not-overlapping, which is the case
   */
@@ -260519,7 +268190,7 @@
  		if (type && ei->type != type)
  			continue;
  		/* is the region (part) in overlap with the current region ?*/
-@@ -143,65 +155,73 @@ int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type
+@@ -143,65 +160,75 @@ int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type
  		 */
  		if (ei->addr <= start)
  			start = ei->addr + ei->size;
@@ -260548,12 +268219,13 @@
 -			continue; 
 -		if (addr < start) 
 +/*
-+ * Find a free area in a specific range.
++ * Find a free area with specified alignment in a specific range.
 + */
 +unsigned long __init find_e820_area(unsigned long start, unsigned long end,
-+				    unsigned size)
++				    unsigned size, unsigned long align)
 +{
 +	int i;
++	unsigned long mask = ~(align - 1);
 +
 +	for (i = 0; i < e820.nr_map; i++) {
 +		struct e820entry *ei = &e820.map[i];
@@ -260569,7 +268241,9 @@
 +			continue;
  		while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
  			;
- 		last = PAGE_ALIGN(addr) + size;
+-		last = PAGE_ALIGN(addr) + size;
++		addr = (addr + align - 1) & mask;
++		last = addr + size;
  		if (last > ei->addr + ei->size)
  			continue;
 -		if (last > end) 
@@ -260622,7 +268296,7 @@
  {
  	int i;
  	for (i = 0; i < e820.nr_map; i++) {
-@@ -219,13 +239,13 @@ void __init e820_reserve_resources(void)
+@@ -219,13 +246,13 @@ void __init e820_reserve_resources(void)
  		request_resource(&iomem_resource, res);
  		if (e820.map[i].type == E820_RAM) {
  			/*
@@ -260642,7 +268316,7 @@
  #ifdef CONFIG_KEXEC
  			if (crashk_res.start != crashk_res.end)
  				request_resource(res, &crashk_res);
-@@ -322,9 +342,9 @@ e820_register_active_regions(int nid, unsigned long start_pfn,
+@@ -322,9 +349,9 @@ e820_register_active_regions(int nid, unsigned long start_pfn,
  			add_active_range(nid, ei_startpfn, ei_endpfn);
  }
  
@@ -260654,7 +268328,7 @@
  void __init add_memory_region(unsigned long start, unsigned long size, int type)
  {
  	int x = e820.nr_map;
-@@ -349,9 +369,7 @@ unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
+@@ -349,9 +376,7 @@ unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
  {
  	unsigned long start_pfn = start >> PAGE_SHIFT;
  	unsigned long end_pfn = end >> PAGE_SHIFT;
@@ -260665,7 +268339,7 @@
  	int i;
  
  	for (i = 0; i < e820.nr_map; i++) {
-@@ -363,28 +381,31 @@ unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
+@@ -363,28 +388,31 @@ unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
  	return end - start - (ram << PAGE_SHIFT);
  }
  
@@ -260710,7 +268384,7 @@
  		}
  	}
  }
-@@ -392,11 +413,11 @@ void __init e820_print_map(char *who)
+@@ -392,11 +420,11 @@ void __init e820_print_map(char *who)
  /*
   * Sanitize the BIOS e820 map.
   *
@@ -260724,7 +268398,7 @@
  {
  	struct change_member {
  		struct e820entry *pbios; /* pointer to original bios entry */
-@@ -416,7 +437,8 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+@@ -416,7 +444,8 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
  	int i;
  
  	/*
@@ -260734,7 +268408,7 @@
  
  		Sample memory map (w/overlaps):
  		   ____22__________________
-@@ -458,22 +480,23 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+@@ -458,22 +487,23 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
  	old_nr = *pnr_map;
  
  	/* bail out if we find any unreasonable addresses in bios map */
@@ -260762,7 +268436,7 @@
  			change_point[chgidx++]->pbios = &biosmap[i];
  		}
  	}
-@@ -483,75 +506,106 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+@@ -483,75 +513,106 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
  	still_changing = 1;
  	while (still_changing)	{
  		still_changing = 0;
@@ -260905,7 +268579,7 @@
  	*pnr_map = new_nr;
  
  	return 0;
-@@ -566,7 +620,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+@@ -566,7 +627,7 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
   * will have given us a memory map that we can use to properly
   * set up memory.  If we aren't, we'll fake a memory map.
   */
@@ -260914,7 +268588,7 @@
  {
  	/* Only one memory region (or negative)? Ignore it */
  	if (nr_map < 2)
-@@ -583,18 +637,20 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+@@ -583,18 +644,20 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
  			return -1;
  
  		add_memory_region(start, size, type);
@@ -260938,7 +268612,7 @@
  	/*
  	 * Try to copy the BIOS-supplied E820-map.
  	 *
-@@ -605,7 +661,10 @@ void __init setup_memory_region(void)
+@@ -605,7 +668,10 @@ void __init setup_memory_region(void)
  	if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0)
  		early_panic("Cannot find a valid memory map");
  	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
@@ -260950,7 +268624,7 @@
  }
  
  static int __init parse_memopt(char *p)
-@@ -613,9 +672,9 @@ static int __init parse_memopt(char *p)
+@@ -613,9 +679,9 @@ static int __init parse_memopt(char *p)
  	if (!p)
  		return -EINVAL;
  	end_user_pfn = memparse(p, &p);
@@ -260962,7 +268636,7 @@
  early_param("mem", parse_memopt);
  
  static int userdef __initdata;
-@@ -627,9 +686,9 @@ static int __init parse_memmap_opt(char *p)
+@@ -627,9 +693,9 @@ static int __init parse_memmap_opt(char *p)
  
  	if (!strcmp(p, "exactmap")) {
  #ifdef CONFIG_CRASH_DUMP
@@ -260975,7 +268649,7 @@
  		 * reset.
  		 */
  		e820_register_active_regions(0, 0, -1UL);
-@@ -646,6 +705,8 @@ static int __init parse_memmap_opt(char *p)
+@@ -646,6 +712,8 @@ static int __init parse_memmap_opt(char *p)
  	mem_size = memparse(p, &p);
  	if (p == oldp)
  		return -EINVAL;
@@ -260984,7 +268658,7 @@
  	if (*p == '@') {
  		start_at = memparse(p+1, &p);
  		add_memory_region(start_at, mem_size, E820_RAM);
-@@ -665,11 +726,29 @@ early_param("memmap", parse_memmap_opt);
+@@ -665,11 +733,29 @@ early_param("memmap", parse_memmap_opt);
  void __init finish_e820_parsing(void)
  {
  	if (userdef) {
@@ -261014,7 +268688,7 @@
  unsigned long pci_mem_start = 0xaeedbabe;
  EXPORT_SYMBOL(pci_mem_start);
  
-@@ -713,8 +792,10 @@ __init void e820_setup_gap(void)
+@@ -713,8 +799,10 @@ __init void e820_setup_gap(void)
  
  	if (!found) {
  		gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
@@ -261027,7 +268701,7 @@
  	}
  
  	/*
-@@ -727,8 +808,9 @@ __init void e820_setup_gap(void)
+@@ -727,8 +815,9 @@ __init void e820_setup_gap(void)
  	/* Fun with two's complement */
  	pci_mem_start = (gapstart + round) & -round;
  
@@ -261210,6 +268884,19 @@
 +			for (func = 0; func < 8; func++)
 +				check_dev_quirk(num, slot, func);
  }
+diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
+index b7d6c23..cff84cd 100644
+--- a/arch/x86/kernel/early_printk.c
++++ b/arch/x86/kernel/early_printk.c
+@@ -193,7 +193,7 @@ static struct console simnow_console = {
+ };
+ 
+ /* Direct interface for emergencies */
+-struct console *early_console = &early_vga_console;
++static struct console *early_console = &early_vga_console;
+ static int early_console_initialized = 0;
+ 
+ void early_printk(const char *fmt, ...)
 diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
 new file mode 100644
 index 0000000..1411324
@@ -262403,7 +270090,7 @@
  }
 diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c
 new file mode 100644
-index 0000000..4b73992
+index 0000000..674f237
 --- /dev/null
 +++ b/arch/x86/kernel/efi_64.c
 @@ -0,0 +1,134 @@
@@ -262453,7 +270140,7 @@
 +					  int executable)
 +{
 +	pte_t *kpte;
-+	int level;
++	unsigned int level;
 +
 +	while (start < end) {
 +		kpte = lookup_address((unsigned long)__va(start), &level);
@@ -263237,7 +270924,7 @@
  EXPORT_SYMBOL_GPL(geode_gpio_isset);
  
 diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
-index 6b34693..a317336 100644
+index 6b34693..24dbf56 100644
 --- a/arch/x86/kernel/head64.c
 +++ b/arch/x86/kernel/head64.c
 @@ -10,6 +10,7 @@
@@ -263294,7 +270981,7 @@
 +	if (ebda_size > 64*1024)
 +		ebda_size = 64*1024;
 +
-+	reserve_early(ebda_addr, ebda_addr + ebda_size);
++	reserve_early(ebda_addr, ebda_addr + ebda_size, "EBDA");
 +}
 +
  void __init x86_64_start_kernel(char * real_mode_data)
@@ -263323,14 +271010,14 @@
 -	cpu_set(0, cpu_online_map);
 -#endif
 +
-+	reserve_early(__pa_symbol(&_text), __pa_symbol(&_end));
++	reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
 +
 +	/* Reserve INITRD */
 +	if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
 +		unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
 +		unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
 +		unsigned long ramdisk_end   = ramdisk_image + ramdisk_size;
-+		reserve_early(ramdisk_image, ramdisk_end);
++		reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
 +	}
 +
 +	reserve_ebda();
@@ -269829,7 +277516,7 @@
   * Check whether any MFGPTs are available for the kernel to use.  In most
   * cases, firmware that uses AMD's VSA code will claim all timers during
 diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
-index 09c3152..6ff447f 100644
+index 09c3152..f2702d0 100644
 --- a/arch/x86/kernel/microcode.c
 +++ b/arch/x86/kernel/microcode.c
 @@ -244,8 +244,8 @@ static int microcode_sanity_check(void *mc)
@@ -269901,6 +277588,15 @@
  		set_cpus_allowed(current, old);
  	}
  	if (err)
+@@ -799,7 +797,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+ 	return NOTIFY_OK;
+ }
+ 
+-static struct notifier_block __cpuinitdata mc_cpu_notifier = {
++static struct notifier_block __refdata mc_cpu_notifier = {
+ 	.notifier_call = mc_cpu_callback,
+ };
+ 
 @@ -817,9 +815,9 @@ static int __init microcode_init (void)
  		return PTR_ERR(microcode_pdev);
  	}
@@ -270098,10 +277794,10 @@
  
  	cpu_set(cpu, cpu_possible_map);
 diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
-index ee6eba4..21f6e3c 100644
+index ee6eba4..bd82850 100644
 --- a/arch/x86/kernel/msr.c
 +++ b/arch/x86/kernel/msr.c
-@@ -155,15 +155,15 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
+@@ -155,20 +155,20 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
  
  	switch (action) {
  	case CPU_UP_PREPARE:
@@ -270120,6 +277816,12 @@
  	}
  	return err ? NOTIFY_BAD : NOTIFY_OK;
  }
+ 
+-static struct notifier_block __cpuinitdata msr_class_cpu_notifier = {
++static struct notifier_block __refdata msr_class_cpu_notifier = {
+ 	.notifier_call = msr_class_cpu_callback,
+ };
+ 
 diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c
 index 852db29..edd4136 100644
 --- a/arch/x86/kernel/nmi_32.c
@@ -271460,7 +279162,7 @@
 +	return ret;
 +}
 diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
-index 6bf1f71..21f34db 100644
+index 6bf1f71..1fe7f04 100644
 --- a/arch/x86/kernel/pci-calgary_64.c
 +++ b/arch/x86/kernel/pci-calgary_64.c
 @@ -30,7 +30,6 @@
@@ -271489,6 +279191,24 @@
  
  static inline unsigned long verify_bit_range(unsigned long* bitmap,
  	int expected, unsigned long start, unsigned long end)
+@@ -1007,7 +1006,7 @@ static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
+ 	readq(target); /* flush */
+ }
+ 
+-static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
++static void __init calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+ {
+ 	unsigned char busnum = dev->bus->number;
+ 	void __iomem *bbar = tbl->bbar;
+@@ -1023,7 +1022,7 @@ static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+ 	writel(cpu_to_be32(val), target);
+ }
+ 
+-static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
++static void __init calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+ {
+ 	unsigned char busnum = dev->bus->number;
+ 
 diff --git a/arch/x86/kernel/pci-dma_64.c b/arch/x86/kernel/pci-dma_64.c
 index 5552d23..a82473d 100644
 --- a/arch/x86/kernel/pci-dma_64.c
@@ -276767,10 +284487,67 @@
 -		syscall_trace(regs);
 -}
 diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
-index fab30e1..150ba29 100644
+index fab30e1..3cd7a2d 100644
 --- a/arch/x86/kernel/quirks.c
 +++ b/arch/x86/kernel/quirks.c
-@@ -162,6 +162,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
+@@ -30,8 +30,8 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
+ 	raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
+ 
+ 	if (!(word & (1 << 13))) {
+-		printk(KERN_INFO "Intel E7520/7320/7525 detected. "
+-			"Disabling irq balancing and affinity\n");
++		dev_info(&dev->dev, "Intel E7520/7320/7525 detected; "
++			"disabling irq balancing and affinity\n");
+ #ifdef CONFIG_IRQBALANCE
+ 		irqbalance_disable("");
+ #endif
+@@ -104,14 +104,16 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0xF0, &rcba);
+ 	rcba &= 0xFFFFC000;
+ 	if (rcba == 0) {
+-		printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
++		dev_printk(KERN_DEBUG, &dev->dev, "RCBA disabled; "
++			"cannot force enable HPET\n");
+ 		return;
+ 	}
+ 
+ 	/* use bits 31:14, 16 kB aligned */
+ 	rcba_base = ioremap_nocache(rcba, 0x4000);
+ 	if (rcba_base == NULL) {
+-		printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
++		dev_printk(KERN_DEBUG, &dev->dev, "ioremap failed; "
++			"cannot force enable HPET\n");
+ 		return;
+ 	}
+ 
+@@ -122,8 +124,8 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
+ 		/* HPET is enabled in HPTC. Just not reported by BIOS */
+ 		val = val & 0x3;
+ 		force_hpet_address = 0xFED00000 | (val << 12);
+-		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
++			"0x%lx\n", force_hpet_address);
+ 		iounmap(rcba_base);
+ 		return;
+ 	}
+@@ -142,11 +144,12 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
+ 	if (err) {
+ 		force_hpet_address = 0;
+ 		iounmap(rcba_base);
+-		printk(KERN_DEBUG "Failed to force enable HPET\n");
++		dev_printk(KERN_DEBUG, &dev->dev,
++			"Failed to force enable HPET\n");
+ 	} else {
+ 		force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
+-		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
++			"0x%lx\n", force_hpet_address);
+ 	}
+ }
+ 
+@@ -162,6 +165,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
  			 ich_force_enable_hpet);
  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
  			 ich_force_enable_hpet);
@@ -276779,6 +284556,73 @@
  
  
  static struct pci_dev *cached_dev;
+@@ -206,8 +211,8 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev)
+ 	if (val & 0x4) {
+ 		val &= 0x3;
+ 		force_hpet_address = 0xFED00000 | (val << 12);
+-		printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
++			force_hpet_address);
+ 		return;
+ 	}
+ 
+@@ -227,14 +232,14 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev)
+ 		/* HPET is enabled in HPTC. Just not reported by BIOS */
+ 		val &= 0x3;
+ 		force_hpet_address = 0xFED00000 | (val << 12);
+-		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
++			"0x%lx\n", force_hpet_address);
+ 		cached_dev = dev;
+ 		force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
+ 		return;
+ 	}
+ 
+-	printk(KERN_DEBUG "Failed to force enable HPET\n");
++	dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
+ }
+ 
+ /*
+@@ -292,8 +297,8 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev)
+ 	 */
+ 	if (val & 0x80) {
+ 		force_hpet_address = (val & ~0x3ff);
+-		printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
++			force_hpet_address);
+ 		return;
+ 	}
+ 
+@@ -307,14 +312,14 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0x68, &val);
+ 	if (val & 0x80) {
+ 		force_hpet_address = (val & ~0x3ff);
+-		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+-			       force_hpet_address);
++		dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
++			"0x%lx\n", force_hpet_address);
+ 		cached_dev = dev;
+ 		force_hpet_resume_type = VT8237_FORCE_HPET_RESUME;
+ 		return;
+ 	}
+ 
+-	printk(KERN_DEBUG "Failed to force enable HPET\n");
++	dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
+ }
+ 
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235,
+@@ -342,7 +347,7 @@ static void nvidia_force_enable_hpet(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0x44, &val);
+ 	force_hpet_address = val & 0xfffffffe;
+ 	force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME;
+-	printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
++	dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
+ 		force_hpet_address);
+ 	cached_dev = dev;
+ 	return;
 diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
 new file mode 100644
 index 0000000..5818dc2
@@ -278633,7 +286477,7 @@
 +
 +subsys_initcall(request_standard_resources);
 diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
-index 30d94d1..77fb87b 100644
+index 30d94d1..18df70c 100644
 --- a/arch/x86/kernel/setup_64.c
 +++ b/arch/x86/kernel/setup_64.c
 @@ -30,6 +30,7 @@
@@ -278731,9 +286575,13 @@
  #ifdef CONFIG_PROC_VMCORE
  /* elfcorehdr= specifies the location of elf core header
   * stored by the crashed kernel. This option will be passed
-@@ -166,12 +184,12 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+@@ -164,14 +182,15 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+ 	unsigned long bootmap_size, bootmap;
+ 
  	bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
- 	bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+-	bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
++	bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
++				 PAGE_SIZE);
  	if (bootmap == -1L)
 -		panic("Cannot find bootmem map of size %ld\n",bootmap_size);
 +		panic("Cannot find bootmem map of size %ld\n", bootmap_size);
@@ -278746,7 +286594,7 @@
  #endif
  
  #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-@@ -205,7 +223,8 @@ static void __init reserve_crashkernel(void)
+@@ -205,7 +224,8 @@ static void __init reserve_crashkernel(void)
  	unsigned long long crash_size, crash_base;
  	int ret;
  
@@ -278756,7 +286604,7 @@
  
  	ret = parse_crashkernel(boot_command_line, free_mem,
  			&crash_size, &crash_base);
-@@ -229,33 +248,21 @@ static inline void __init reserve_crashkernel(void)
+@@ -229,33 +249,21 @@ static inline void __init reserve_crashkernel(void)
  {}
  #endif
  
@@ -278800,7 +286648,7 @@
  	printk(KERN_INFO "Command line: %s\n", boot_command_line);
  
  	ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
-@@ -269,7 +276,15 @@ void __init setup_arch(char **cmdline_p)
+@@ -269,7 +277,15 @@ void __init setup_arch(char **cmdline_p)
  	rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
  	rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
  #endif
@@ -278817,7 +286665,7 @@
  	copy_edd();
  
  	if (!boot_params.hdr.root_flags)
-@@ -293,27 +308,47 @@ void __init setup_arch(char **cmdline_p)
+@@ -293,27 +309,47 @@ void __init setup_arch(char **cmdline_p)
  
  	parse_early_param();
  
@@ -278869,7 +286717,7 @@
  #endif
  
  #ifdef CONFIG_ACPI
-@@ -340,48 +375,26 @@ void __init setup_arch(char **cmdline_p)
+@@ -340,48 +376,26 @@ void __init setup_arch(char **cmdline_p)
  #endif
  
  #ifdef CONFIG_NUMA
@@ -278927,7 +286775,7 @@
  	find_smp_config();
  #ifdef CONFIG_BLK_DEV_INITRD
  	if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
-@@ -395,6 +408,8 @@ void __init setup_arch(char **cmdline_p)
+@@ -395,6 +409,8 @@ void __init setup_arch(char **cmdline_p)
  			initrd_start = ramdisk_image + PAGE_OFFSET;
  			initrd_end = initrd_start+ramdisk_size;
  		} else {
@@ -278936,7 +286784,7 @@
  			printk(KERN_ERR "initrd extends beyond end of memory "
  			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
  			       ramdisk_end, end_of_mem);
-@@ -404,17 +419,10 @@ void __init setup_arch(char **cmdline_p)
+@@ -404,17 +420,10 @@ void __init setup_arch(char **cmdline_p)
  #endif
  	reserve_crashkernel();
  	paging_init();
@@ -278955,7 +286803,7 @@
  #ifdef CONFIG_ACPI
  	/*
  	 * Read APIC and some other early information from ACPI tables.
-@@ -430,25 +438,24 @@ void __init setup_arch(char **cmdline_p)
+@@ -430,25 +439,24 @@ void __init setup_arch(char **cmdline_p)
  	if (smp_found_config)
  		get_smp_config();
  	init_apic_mappings();
@@ -278986,7 +286834,7 @@
  #elif defined(CONFIG_DUMMY_CONSOLE)
  	conswitchp = &dummy_con;
  #endif
-@@ -479,9 +486,10 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+@@ -479,9 +487,10 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
  
  	if (n >= 0x80000005) {
  		cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
@@ -279000,7 +286848,7 @@
  		/* On K8 L1 TLB is inclusive, so don't count it */
  		c->x86_tlbsize = 0;
  	}
-@@ -495,11 +503,8 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+@@ -495,11 +504,8 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
  		printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
  		c->x86_cache_size, ecx & 0xFF);
  	}
@@ -279013,7 +286861,7 @@
  		c->x86_virt_bits = (eax >> 8) & 0xff;
  		c->x86_phys_bits = eax & 0xff;
  	}
-@@ -508,14 +513,15 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+@@ -508,14 +514,15 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
  #ifdef CONFIG_NUMA
  static int nearby_node(int apicid)
  {
@@ -279032,7 +286880,7 @@
  		if (node != NUMA_NO_NODE && node_online(node))
  			return node;
  	}
-@@ -527,7 +533,7 @@ static int nearby_node(int apicid)
+@@ -527,7 +534,7 @@ static int nearby_node(int apicid)
   * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
   * Assumes number of cores is a power of two.
   */
@@ -279041,7 +286889,7 @@
  {
  #ifdef CONFIG_SMP
  	unsigned bits;
-@@ -536,7 +542,54 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
+@@ -536,7 +543,54 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
  	int node = 0;
  	unsigned apicid = hard_smp_processor_id();
  #endif
@@ -279097,7 +286945,7 @@
  
  	c->x86_max_cores = (ecx & 0xff) + 1;
  
-@@ -549,37 +602,8 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
+@@ -549,37 +603,8 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
  			bits++;
  	}
  
@@ -279136,7 +286984,7 @@
  #endif
  }
  
-@@ -595,8 +619,8 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
+@@ -595,8 +620,8 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
  /* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
  static __cpuinit int amd_apic_timer_broken(void)
  {
@@ -279147,7 +286995,7 @@
  	switch (eax & CPUID_XFAM) {
  	case CPUID_XFAM_K8:
  		if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
-@@ -614,6 +638,15 @@ static __cpuinit int amd_apic_timer_broken(void)
+@@ -614,6 +639,15 @@ static __cpuinit int amd_apic_timer_broken(void)
  	return 0;
  }
  
@@ -279163,7 +287011,7 @@
  static void __cpuinit init_amd(struct cpuinfo_x86 *c)
  {
  	unsigned level;
-@@ -624,7 +657,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+@@ -624,7 +658,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
  	/*
  	 * Disable TLB flush filter by setting HWCR.FFDIS on K8
  	 * bit 6 of msr C001_0015
@@ -279172,7 +287020,7 @@
  	 * Errata 63 for SH-B3 steppings
  	 * Errata 122 for all steppings (F+ have it disabled by default)
  	 */
-@@ -637,35 +670,32 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+@@ -637,35 +671,32 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
  
  	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
  	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
@@ -279219,7 +287067,7 @@
  	/* Multi core CPU? */
  	if (c->extended_cpuid_level >= 0x80000008)
  		amd_detect_cmp(c);
-@@ -677,41 +707,38 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+@@ -677,41 +708,38 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
  		num_cache_leaves = 3;
  
  	if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
@@ -279271,7 +287119,7 @@
  			smp_num_siblings = 1;
  			return;
  		}
-@@ -721,7 +748,7 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+@@ -721,7 +749,7 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
  
  		smp_num_siblings = smp_num_siblings / c->x86_max_cores;
  
@@ -279280,7 +287128,7 @@
  
  		core_bits = get_count_order(c->x86_max_cores);
  
-@@ -730,8 +757,10 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+@@ -730,8 +758,10 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
  	}
  out:
  	if ((c->x86_max_cores * smp_num_siblings) > 1) {
@@ -279293,7 +287141,7 @@
  	}
  
  #endif
-@@ -773,28 +802,39 @@ static void srat_detect_node(void)
+@@ -773,28 +803,39 @@ static void srat_detect_node(void)
  #endif
  }
  
@@ -279337,7 +287185,7 @@
  	n = c->extended_cpuid_level;
  	if (n >= 0x80000008) {
  		unsigned eax = cpuid_eax(0x80000008);
-@@ -811,14 +851,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
+@@ -811,14 +852,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
  		c->x86_cache_alignment = c->x86_clflush_size * 2;
  	if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
  	    (c->x86 == 0x6 && c->x86_model >= 0x0e))
@@ -279356,7 +287204,7 @@
  
  	srat_detect_node();
  }
-@@ -835,18 +872,12 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
+@@ -835,18 +873,12 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
  		c->x86_vendor = X86_VENDOR_UNKNOWN;
  }
  
@@ -279377,7 +287225,7 @@
  
  	c->loops_per_jiffy = loops_per_jiffy;
  	c->x86_cache_size = -1;
-@@ -857,6 +888,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
+@@ -857,6 +889,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
  	c->x86_clflush_size = 64;
  	c->x86_cache_alignment = c->x86_clflush_size;
  	c->x86_max_cores = 1;
@@ -279385,7 +287233,7 @@
  	c->extended_cpuid_level = 0;
  	memset(&c->x86_capability, 0, sizeof c->x86_capability);
  
-@@ -865,7 +897,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
+@@ -865,7 +898,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
  	      (unsigned int *)&c->x86_vendor_id[0],
  	      (unsigned int *)&c->x86_vendor_id[8],
  	      (unsigned int *)&c->x86_vendor_id[4]);
@@ -279394,7 +287242,7 @@
  	get_cpu_vendor(c);
  
  	/* Initialize the standard set of capabilities */
-@@ -883,7 +915,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
+@@ -883,7 +916,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
  			c->x86 += (tfms >> 20) & 0xff;
  		if (c->x86 >= 0x6)
  			c->x86_model += ((tfms >> 16) & 0xF) << 4;
@@ -279403,7 +287251,7 @@
  			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
  	} else {
  		/* Have CPUID level 0 only - unheard of */
-@@ -893,18 +925,6 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
+@@ -893,18 +926,6 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
  #ifdef CONFIG_SMP
  	c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
  #endif
@@ -279422,7 +287270,7 @@
  	/* AMD-defined flags: level 0x80000001 */
  	xlvl = cpuid_eax(0x80000000);
  	c->extended_cpuid_level = xlvl;
-@@ -925,6 +945,30 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+@@ -925,6 +946,30 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
  			c->x86_capability[2] = cpuid_edx(0x80860001);
  	}
  
@@ -279453,7 +287301,7 @@
  	init_scattered_cpuid_features(c);
  
  	c->apicid = phys_pkg_id(0);
-@@ -954,8 +998,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+@@ -954,8 +999,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
  		break;
  	}
  
@@ -279463,7 +287311,7 @@
  
  	/*
  	 * On SMP, boot_cpu_data holds the common feature set between
-@@ -965,32 +1008,56 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+@@ -965,32 +1009,56 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
  	 */
  	if (c != &boot_cpu_data) {
  		/* AND the already accumulated flags with these */
@@ -279526,7 +287374,7 @@
  /*
   *	Get CPU information for use by the procfs.
   */
-@@ -998,9 +1065,9 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
+@@ -998,9 +1066,9 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
  static int show_cpuinfo(struct seq_file *m, void *v)
  {
  	struct cpuinfo_x86 *c = v;
@@ -279538,7 +287386,7 @@
  	 * These flag bits must match the definitions in <asm/cpufeature.h>.
  	 * NULL means this bit is undefined or reserved; either way it doesn't
  	 * have meaning as far as Linux is concerned.  Note that it's important
-@@ -1010,10 +1077,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
+@@ -1010,10 +1078,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
  	 */
  	static const char *const x86_cap_flags[] = {
  		/* Intel-defined */
@@ -279553,7 +287401,7 @@
  
  		/* AMD-defined */
  		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-@@ -1080,34 +1147,35 @@ static int show_cpuinfo(struct seq_file *m, void *v)
+@@ -1080,34 +1148,35 @@ static int show_cpuinfo(struct seq_file *m, void *v)
  	cpu = c->cpu_index;
  #endif
  
@@ -279605,7 +287453,7 @@
  #ifdef CONFIG_SMP
  	if (smp_num_siblings * c->x86_max_cores > 1) {
  		seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
-@@ -1116,48 +1184,43 @@ static int show_cpuinfo(struct seq_file *m, void *v)
+@@ -1116,48 +1185,43 @@ static int show_cpuinfo(struct seq_file *m, void *v)
  		seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
  		seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
  	}
@@ -279676,7 +287524,7 @@
  	}
  
  	seq_printf(m, "\n\n");
-@@ -1184,8 +1247,8 @@ static void c_stop(struct seq_file *m, void *v)
+@@ -1184,8 +1248,8 @@ static void c_stop(struct seq_file *m, void *v)
  {
  }
  
@@ -281010,7 +288858,7 @@
  
  void __init smp_intr_init(void)
 diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
-index aaf4e12..cc64b80 100644
+index aaf4e12..d53bd6f 100644
 --- a/arch/x86/kernel/smpboot_64.c
 +++ b/arch/x86/kernel/smpboot_64.c
 @@ -65,7 +65,7 @@ int smp_num_siblings = 1;
@@ -281229,7 +289077,14 @@
  	cpu_set(me, cpu_callout_map);
  	per_cpu(cpu_state, me) = CPU_ONLINE;
  }
-@@ -1016,7 +1025,7 @@ void remove_cpu_from_maps(void)
+@@ -1010,13 +1019,13 @@ static void remove_siblinginfo(int cpu)
+ 	cpu_clear(cpu, cpu_sibling_setup_map);
+ }
+ 
+-void remove_cpu_from_maps(void)
++static void __ref remove_cpu_from_maps(void)
+ {
+ 	int cpu = smp_processor_id();
  
  	cpu_clear(cpu, cpu_callout_map);
  	cpu_clear(cpu, cpu_callin_map);
@@ -281561,7 +289416,7 @@
 +		task_pt_regs(child)->flags &= ~X86_EFLAGS_TF;
 +}
 diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c
-index 2e5efaa..0919951 100644
+index 2e5efaa..7ac7130 100644
 --- a/arch/x86/kernel/suspend_64.c
 +++ b/arch/x86/kernel/suspend_64.c
 @@ -17,9 +17,26 @@
@@ -281606,7 +289461,7 @@
  {
  	/*
  	 * control registers
-@@ -113,14 +135,14 @@ void restore_processor_state(void)
+@@ -113,14 +135,19 @@ void restore_processor_state(void)
  	__restore_processor_state(&saved_context);
  }
  
@@ -281616,13 +289471,27 @@
  	int cpu = smp_processor_id();
  	struct tss_struct *t = &per_cpu(init_tss, cpu);
  
- 	set_tss_desc(cpu,t);	/* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
+-	set_tss_desc(cpu,t);	/* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
++	/*
++	 * This just modifies memory; should not be necessary. But... This
++	 * is necessary, because 386 hardware has concept of busy TSS or some
++	 * similar stupidity.
++	 */
++	set_tss_desc(cpu, t);
  
 -	cpu_gdt(cpu)[GDT_ENTRY_TSS].type = 9;
 +	get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
  
  	syscall_init();                         /* This sets MSR_*STAR and related */
  	load_TR_desc();				/* This does ltr */
+@@ -138,7 +165,6 @@ void fix_processor_context(void)
+                 loaddebug(&current->thread, 6);
+                 loaddebug(&current->thread, 7);
+ 	}
+-
+ }
+ 
+ #ifdef CONFIG_HIBERNATION
 diff --git a/arch/x86/kernel/suspend_asm_64.S b/arch/x86/kernel/suspend_asm_64.S
 index 72f9521..aeb9a4d 100644
 --- a/arch/x86/kernel/suspend_asm_64.S
@@ -283111,7 +290980,7 @@
 +
 +#endif	/* _ARCH_X86_KERNEL_TLS_H */
 diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
-index 7e16d67..78cbb65 100644
+index 7e16d67..e6757aa 100644
 --- a/arch/x86/kernel/topology.c
 +++ b/arch/x86/kernel/topology.c
 @@ -31,9 +31,10 @@
@@ -283127,7 +290996,7 @@
  {
  	/*
  	 * CPU0 cannot be offlined due to several
-@@ -44,21 +45,23 @@ int __cpuinit arch_register_cpu(int num)
+@@ -44,21 +45,22 @@ int __cpuinit arch_register_cpu(int num)
  	 * Also certain PCI quirks require not to enable hotplug control
  	 * for all CPU's.
  	 */
@@ -283151,11 +291020,10 @@
 -EXPORT_SYMBOL(arch_register_cpu);
  EXPORT_SYMBOL(arch_unregister_cpu);
 +#else
-+int arch_register_cpu(int num)
++static int __init arch_register_cpu(int num)
 +{
 +	return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
 +}
-+EXPORT_SYMBOL(arch_register_cpu);
  #endif /*CONFIG_HOTPLUG_CPU*/
  
  static int __init topology_init(void)
@@ -320654,7 +328522,7 @@
 -}
 diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
 new file mode 100644
-index 0000000..e28cc52
+index 0000000..e4440d0
 --- /dev/null
 +++ b/arch/x86/mm/fault.c
 @@ -0,0 +1,986 @@
@@ -321042,7 +328910,7 @@
 +
 +#ifdef CONFIG_X86_PAE
 +	if (error_code & PF_INSTR) {
-+		int level;
++		unsigned int level;
 +		pte_t *pte = lookup_address(address, &level);
 +
 +		if (pte && pte_present(*pte) && !pte_exec(*pte))
@@ -323026,7 +330894,7 @@
  		put_page(virt_to_page(spte));
  	spin_unlock(&mm->page_table_lock);
 diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
-index 3c76d19..da524fb 100644
+index 3c76d19..f2f36f8 100644
 --- a/arch/x86/mm/init_32.c
 +++ b/arch/x86/mm/init_32.c
 @@ -27,7 +27,6 @@
@@ -323410,7 +331278,7 @@
  
  	paravirt_pagetable_setup_start(pgd_base);
  
-@@ -435,9 +412,11 @@ static void __init pagetable_init (void)
+@@ -435,34 +412,36 @@ static void __init pagetable_init (void)
  	 * Fixed mappings, only the page table structure has to be
  	 * created - mappings will be set by set_fixmap():
  	 */
@@ -323422,18 +331290,32 @@
  
  	permanent_kmaps_init(pgd_base);
  
-@@ -450,7 +429,7 @@ static void __init pagetable_init (void)
+ 	paravirt_pagetable_setup_done(pgd_base);
+ }
+ 
+-#if defined(CONFIG_HIBERNATION) || defined(CONFIG_ACPI)
++#ifdef CONFIG_ACPI_SLEEP
+ /*
+- * Swap suspend & friends need this for resume because things like the intel-agp
++ * ACPI suspend needs this for resume, because things like the intel-agp
   * driver might have split up a kernel 4MB mapping.
   */
- char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+-char __nosavedata swsusp_pg_dir[PAGE_SIZE]
 -	__attribute__ ((aligned (PAGE_SIZE)));
++char swsusp_pg_dir[PAGE_SIZE]
 +	__attribute__ ((aligned(PAGE_SIZE)));
  
  static inline void save_pg_dir(void)
  {
-@@ -462,7 +441,7 @@ static inline void save_pg_dir(void)
+ 	memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
  }
- #endif
+-#else
++#else /* !CONFIG_ACPI_SLEEP */
+ static inline void save_pg_dir(void)
+ {
+ }
+-#endif
++#endif /* !CONFIG_ACPI_SLEEP */
  
 -void zap_low_mappings (void)
 +void zap_low_mappings(void)
@@ -323853,7 +331735,7 @@
  #endif
 -
 diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
-index 0f9c8c8..cc50a13 100644
+index 0f9c8c8..eabcaed 100644
 --- a/arch/x86/mm/init_64.c
 +++ b/arch/x86/mm/init_64.c
 @@ -43,12 +43,10 @@
@@ -324186,7 +332068,7 @@
  
  static void __init find_early_table_space(unsigned long end)
  {
-@@ -326,14 +348,23 @@ static void __init find_early_table_space(unsigned long end)
+@@ -326,11 +348,13 @@ static void __init find_early_table_space(unsigned long end)
  	tables = round_up(puds * sizeof(pud_t), PAGE_SIZE) +
  		 round_up(pmds * sizeof(pmd_t), PAGE_SIZE);
  
@@ -324201,21 +332083,11 @@
 +	 * need roughly 0.5KB per GB.
 +	 */
 +	start = 0x8000;
-+	table_start = find_e820_area(start, end, tables);
++	table_start = find_e820_area(start, end, tables, PAGE_SIZE);
  	if (table_start == -1UL)
  		panic("Cannot find space for the kernel page tables");
  
-+	/*
-+	 * When you have a lot of RAM like 256GB, early_table will not fit
-+	 * into 0x8000 range, find_e820_area() will find area after kernel
-+	 * bss but the table_start is not page aligned, so need to round it
-+	 * up to avoid overlap with bss:
-+	 */
-+	table_start = round_up(table_start, PAGE_SIZE);
- 	table_start >>= PAGE_SHIFT;
- 	table_end = table_start;
- 
-@@ -342,20 +373,23 @@ static void __init find_early_table_space(unsigned long end)
+@@ -342,20 +366,23 @@ static void __init find_early_table_space(unsigned long end)
  		(table_start << PAGE_SHIFT) + tables);
  }
  
@@ -324249,7 +332121,7 @@
  	 */
  	if (!after_bootmem)
  		find_early_table_space(end);
-@@ -364,8 +398,8 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
+@@ -364,8 +391,8 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
  	end = (unsigned long)__va(end);
  
  	for (; start < end; start = next) {
@@ -324259,7 +332131,7 @@
  		pud_t *pud;
  
  		if (after_bootmem)
-@@ -374,23 +408,26 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
+@@ -374,23 +401,28 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
  			pud = alloc_low_page(&pud_phys);
  
  		next = start + PGDIR_SIZE;
@@ -324278,7 +332150,9 @@
  		mmu_cr4_features = read_cr4();
  	__flush_tlb_all();
 +
-+	reserve_early(table_start << PAGE_SHIFT, table_end << PAGE_SHIFT);
++	if (!after_bootmem)
++		reserve_early(table_start << PAGE_SHIFT,
++				 table_end << PAGE_SHIFT, "PGTABLE");
  }
  
  #ifndef CONFIG_NUMA
@@ -324289,7 +332163,7 @@
  	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
  	max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
  	max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
-@@ -402,39 +439,48 @@ void __init paging_init(void)
+@@ -402,39 +434,48 @@ void __init paging_init(void)
  }
  #endif
  
@@ -324355,7 +332229,7 @@
  
  /*
   * Memory hotplug specific functions
-@@ -461,16 +507,12 @@ int arch_add_memory(int nid, u64 start, u64 size)
+@@ -461,16 +502,12 @@ int arch_add_memory(int nid, u64 start, u64 size)
  	unsigned long nr_pages = size >> PAGE_SHIFT;
  	int ret;
  
@@ -324374,7 +332248,7 @@
  }
  EXPORT_SYMBOL_GPL(arch_add_memory);
  
-@@ -484,36 +526,8 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+@@ -484,36 +521,8 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
  
  #endif /* CONFIG_MEMORY_HOTPLUG */
  
@@ -324413,7 +332287,7 @@
  
  void __init mem_init(void)
  {
-@@ -521,8 +535,15 @@ void __init mem_init(void)
+@@ -521,8 +530,15 @@ void __init mem_init(void)
  
  	pci_iommu_alloc();
  
@@ -324431,7 +332305,7 @@
  
  	reservedpages = 0;
  
-@@ -534,7 +555,6 @@ void __init mem_init(void)
+@@ -534,7 +550,6 @@ void __init mem_init(void)
  #endif
  	reservedpages = end_pfn - totalram_pages -
  					absent_pages_in_range(0, end_pfn);
@@ -324439,7 +332313,7 @@
  	after_bootmem = 1;
  
  	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-@@ -542,15 +562,16 @@ void __init mem_init(void)
+@@ -542,15 +557,16 @@ void __init mem_init(void)
  	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
  
  	/* Register memory areas for /proc/kcore */
@@ -324460,7 +332334,7 @@
  		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
  		end_pfn << (PAGE_SHIFT-10),
  		codesize >> 10,
-@@ -566,19 +587,27 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
+@@ -566,19 +582,27 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
  	if (begin >= end)
  		return;
  
@@ -324492,7 +332366,7 @@
  }
  
  void free_initmem(void)
-@@ -589,6 +618,8 @@ void free_initmem(void)
+@@ -589,6 +613,8 @@ void free_initmem(void)
  }
  
  #ifdef CONFIG_DEBUG_RODATA
@@ -324501,7 +332375,7 @@
  
  void mark_rodata_ro(void)
  {
-@@ -603,25 +634,27 @@ void mark_rodata_ro(void)
+@@ -603,25 +629,27 @@ void mark_rodata_ro(void)
  #ifdef CONFIG_KPROBES
  	start = (unsigned long)__start_rodata;
  #endif
@@ -324538,7 +332412,7 @@
  }
  #endif
  
-@@ -632,17 +665,21 @@ void free_initrd_mem(unsigned long start, unsigned long end)
+@@ -632,17 +660,21 @@ void free_initrd_mem(unsigned long start, unsigned long end)
  }
  #endif
  
@@ -324564,7 +332438,7 @@
  		printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n",
  				phys, len);
  		return;
-@@ -650,9 +687,9 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
+@@ -650,9 +682,9 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
  
  	/* Should check here against the e820 map to avoid double free */
  #ifdef CONFIG_NUMA
@@ -324577,7 +332451,7 @@
  #endif
  	if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
  		dma_reserve += len / PAGE_SIZE;
-@@ -660,46 +697,49 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
+@@ -660,46 +692,49 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
  	}
  }
  
@@ -324644,7 +332518,7 @@
  };
  
  struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
-@@ -714,14 +754,17 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+@@ -714,14 +749,17 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
  int in_gate_area(struct task_struct *task, unsigned long addr)
  {
  	struct vm_area_struct *vma = get_gate_vma(task);
@@ -324665,7 +332539,7 @@
   */
  int in_gate_area_no_task(unsigned long addr)
  {
-@@ -741,8 +784,8 @@ const char *arch_vma_name(struct vm_area_struct *vma)
+@@ -741,8 +779,8 @@ const char *arch_vma_name(struct vm_area_struct *vma)
  /*
   * Initialise the sparsemem vmemmap using huge-pages at the PMD level.
   */
@@ -324676,7 +332550,7 @@
  {
  	unsigned long addr = (unsigned long)start_page;
  	unsigned long end = (unsigned long)(start_page + size);
-@@ -757,6 +800,7 @@ int __meminit vmemmap_populate(struct page *start_page,
+@@ -757,6 +795,7 @@ int __meminit vmemmap_populate(struct page *start_page,
  		pgd = vmemmap_pgd_populate(addr, node);
  		if (!pgd)
  			return -ENOMEM;
@@ -324684,7 +332558,7 @@
  		pud = vmemmap_pud_populate(pgd, addr, node);
  		if (!pud)
  			return -ENOMEM;
-@@ -764,20 +808,22 @@ int __meminit vmemmap_populate(struct page *start_page,
+@@ -764,20 +803,22 @@ int __meminit vmemmap_populate(struct page *start_page,
  		pmd = pmd_offset(pud, addr);
  		if (pmd_none(*pmd)) {
  			pte_t entry;
@@ -324714,10 +332588,10 @@
  #endif
 diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
 new file mode 100644
-index 0000000..a177d76
+index 0000000..c004d94
 --- /dev/null
 +++ b/arch/x86/mm/ioremap.c
-@@ -0,0 +1,501 @@
+@@ -0,0 +1,502 @@
 +/*
 + * Re-map IO memory to kernel address space so that we can access it.
 + * This is needed for high PCI addresses that aren't mapped in the
@@ -324795,7 +332669,8 @@
 +{
 +	unsigned long vaddr = (unsigned long)__va(paddr);
 +	unsigned long nrpages = size >> PAGE_SHIFT;
-+	int err, level;
++	unsigned int level;
++	int err;
 +
 +	/* No change for pages after the last mapping */
 +	if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT))
@@ -326228,7 +334103,7 @@
 -}
 -
 diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
-index 3d6926b..dc3b1f7 100644
+index 3d6926b..a920d09 100644
 --- a/arch/x86/mm/numa_64.c
 +++ b/arch/x86/mm/numa_64.c
 @@ -1,7 +1,7 @@
@@ -326311,7 +334186,7 @@
  	for (i = 0; i < numnodes; i++) {
  		addr = nodes[i].start;
  		end = nodes[i].end;
-@@ -63,13 +72,13 @@ populate_memnodemap(const struct bootnode *nodes, int numnodes, int shift)
+@@ -63,37 +72,36 @@ populate_memnodemap(const struct bootnode *nodes, int numnodes, int shift)
  		if ((end >> shift) >= memnodemapsize)
  			return 0;
  		do {
@@ -326327,30 +334202,39 @@
  	return res;
  }
  
-@@ -78,12 +87,12 @@ static int __init allocate_cachealigned_memnodemap(void)
- 	unsigned long pad, pad_addr;
+ static int __init allocate_cachealigned_memnodemap(void)
+ {
+-	unsigned long pad, pad_addr;
++	unsigned long addr;
  
  	memnodemap = memnode.embedded_map;
 -	if (memnodemapsize <= 48)
 +	if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map))
  		return 0;
  
- 	pad = L1_CACHE_BYTES - 1;
- 	pad_addr = 0x8000;
+-	pad = L1_CACHE_BYTES - 1;
+-	pad_addr = 0x8000;
 -	nodemap_size = pad + memnodemapsize;
-+	nodemap_size = pad + sizeof(s16) * memnodemapsize;
- 	nodemap_addr = find_e820_area(pad_addr, end_pfn<<PAGE_SHIFT,
- 				      nodemap_size);
+-	nodemap_addr = find_e820_area(pad_addr, end_pfn<<PAGE_SHIFT,
+-				      nodemap_size);
++	addr = 0x8000;
++	nodemap_size = round_up(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
++	nodemap_addr = find_e820_area(addr, end_pfn<<PAGE_SHIFT,
++				      nodemap_size, L1_CACHE_BYTES);
  	if (nodemap_addr == -1UL) {
-@@ -94,6 +103,7 @@ static int __init allocate_cachealigned_memnodemap(void)
+ 		printk(KERN_ERR
+ 		       "NUMA: Unable to allocate Memory to Node hash map\n");
+ 		nodemap_addr = nodemap_size = 0;
+ 		return -1;
  	}
- 	pad_addr = (nodemap_addr + pad) & ~pad;
- 	memnodemap = phys_to_virt(pad_addr);
-+	reserve_early(nodemap_addr, nodemap_addr + nodemap_size);
+-	pad_addr = (nodemap_addr + pad) & ~pad;
+-	memnodemap = phys_to_virt(pad_addr);
++	memnodemap = phys_to_virt(nodemap_addr);
++	reserve_early(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
  
  	printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
  	       nodemap_addr, nodemap_addr + nodemap_size);
-@@ -104,8 +114,8 @@ static int __init allocate_cachealigned_memnodemap(void)
+@@ -104,8 +112,8 @@ static int __init allocate_cachealigned_memnodemap(void)
   * The LSB of all start and end addresses in the node map is the value of the
   * maximum possible shift.
   */
@@ -326361,7 +334245,7 @@
  {
  	int i, nodes_used = 0;
  	unsigned long start, end;
-@@ -140,51 +150,50 @@ int __init compute_hash_shift(struct bootnode *nodes, int numnodes)
+@@ -140,56 +148,57 @@ int __init compute_hash_shift(struct bootnode *nodes, int numnodes)
  		shift);
  
  	if (populate_memnodemap(nodes, numnodes, shift) != 1) {
@@ -326388,15 +334272,19 @@
 -early_node_mem(int nodeid, unsigned long start, unsigned long end,
 -	      unsigned long size)
 +static void * __init early_node_mem(int nodeid, unsigned long start,
-+				    unsigned long end, unsigned long size)
++				    unsigned long end, unsigned long size,
++				    unsigned long align)
  {
- 	unsigned long mem = find_e820_area(start, end, size);
+-	unsigned long mem = find_e820_area(start, end, size);
++	unsigned long mem = find_e820_area(start, end, size, align);
  	void *ptr;
 +
  	if (mem != -1L)
  		return __va(mem);
- 	ptr = __alloc_bootmem_nopanic(size,
- 				SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS));
+-	ptr = __alloc_bootmem_nopanic(size,
+-				SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS));
++
++	ptr = __alloc_bootmem_nopanic(size, align, __pa(MAX_DMA_ADDRESS));
  	if (ptr == NULL) {
  		printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
 -			size, nodeid);
@@ -326428,15 +334316,27 @@
  
  	start_pfn = start >> PAGE_SHIFT;
  	end_pfn = end >> PAGE_SHIFT;
-@@ -200,75 +209,55 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
+ 
+-	node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size);
++	node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
++					   SMP_CACHE_BYTES);
+ 	if (node_data[nodeid] == NULL)
+ 		return;
+ 	nodedata_phys = __pa(node_data[nodeid]);
+@@ -200,75 +209,59 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
  	NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn;
  
  	/* Find a place for the bootmem map */
 -	bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); 
 +	bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
  	bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
++	/*
++	 * SMP_CAHCE_BYTES could be enough, but init_bootmem_node like
++	 * to use that to align to PAGE_SIZE
++	 */
  	bootmap = early_node_mem(nodeid, bootmap_start, end,
- 					bootmap_pages<<PAGE_SHIFT);
+-					bootmap_pages<<PAGE_SHIFT);
++				 bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
  	if (bootmap == NULL)  {
  		if (nodedata_phys < start || nodedata_phys >= end)
 -			free_bootmem((unsigned long)node_data[nodeid],pgdat_size);
@@ -326525,7 +334425,7 @@
  }
  
  #ifdef CONFIG_NUMA_EMU
-@@ -276,15 +265,17 @@ void __init numa_init_array(void)
+@@ -276,15 +269,17 @@ void __init numa_init_array(void)
  char *cmdline __initdata;
  
  /*
@@ -326547,7 +334447,7 @@
  	nodes[nid].start = *addr;
  	*addr += size;
  	if (*addr >= max_addr) {
-@@ -335,6 +326,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
+@@ -335,6 +330,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
  
  	for (i = node_start; i < num_nodes + node_start; i++) {
  		u64 end = *addr + size;
@@ -326555,7 +334455,7 @@
  		if (i < big)
  			end += FAKE_NODE_MIN_SIZE;
  		/*
-@@ -380,14 +372,9 @@ static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
+@@ -380,14 +376,9 @@ static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
  static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
  {
  	struct bootnode nodes[MAX_NUMNODES];
@@ -326572,7 +334472,7 @@
  
  	memset(&nodes, 0, sizeof(nodes));
  	/*
-@@ -395,8 +382,9 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+@@ -395,8 +386,9 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
  	 * system RAM into N fake nodes.
  	 */
  	if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) {
@@ -326584,7 +334484,7 @@
  		if (num_nodes < 0)
  			return num_nodes;
  		goto out;
-@@ -483,46 +471,47 @@ out:
+@@ -483,46 +475,47 @@ out:
  	for_each_node_mask(i, node_possible_map) {
  		e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
  						nodes[i].end >> PAGE_SHIFT);
@@ -326643,7 +334543,7 @@
  	memnodemap = memnode.embedded_map;
  	memnodemap[0] = 0;
  	nodes_clear(node_online_map);
-@@ -530,36 +519,48 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+@@ -530,36 +523,48 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
  	node_set(0, node_possible_map);
  	for (i = 0; i < NR_CPUS; i++)
  		numa_set_node(i, 0);
@@ -326704,7 +334604,7 @@
  	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
  	max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
  	max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
-@@ -568,32 +569,27 @@ void __init paging_init(void)
+@@ -568,32 +573,27 @@ void __init paging_init(void)
  	sparse_memory_present_with_active_regions(MAX_NUMNODES);
  	sparse_init();
  
@@ -326744,7 +334644,7 @@
  early_param("numa", numa_setup);
  
  /*
-@@ -611,38 +607,16 @@ early_param("numa", numa_setup);
+@@ -611,38 +611,16 @@ early_param("numa", numa_setup);
  void __init init_cpu_to_node(void)
  {
  	int i;
@@ -326767,7 +334667,7 @@
 -EXPORT_SYMBOL(node_to_cpumask);
 -EXPORT_SYMBOL(memnode);
 -EXPORT_SYMBOL(node_data);
--
+ 
 -#ifdef CONFIG_DISCONTIGMEM
 -/*
 - * Functions to convert PFNs from/to per node page addresses.
@@ -326775,7 +334675,7 @@
 - * They could be all tuned by pre caching more state.
 - * Should do that.
 - */
- 
+-
 -int pfn_valid(unsigned long pfn)
 -{
 -	unsigned nid;
@@ -326790,7 +334690,7 @@
 -#endif
 diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
 new file mode 100644
-index 0000000..06353d4
+index 0000000..7573e78
 --- /dev/null
 +++ b/arch/x86/mm/pageattr-test.c
 @@ -0,0 +1,224 @@
@@ -326838,7 +334738,7 @@
 +	s->max_exec = 0;
 +	for (i = 0; i < max_pfn_mapped; ) {
 +		unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
-+		int level;
++		unsigned int level;
 +		pte_t *pte;
 +
 +		pte = lookup_address(addr, &level);
@@ -326902,7 +334802,7 @@
 +	unsigned long *bm;
 +	pte_t *pte, pte0;
 +	int failed = 0;
-+	int level;
++	unsigned int level;
 +	int i, k;
 +	int err;
 +
@@ -329063,27 +336963,59 @@
  
  /*
 diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
-index 6cff66d..cb63007 100644
+index 6cff66d..74d30ff 100644
 --- a/arch/x86/pci/fixup.c
 +++ b/arch/x86/pci/fixup.c
-@@ -19,7 +19,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+@@ -17,9 +17,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+ 	int pxb, reg;
+ 	u8 busno, suba, subb;
  
- 	printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
+-	printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
++	dev_warn(&d->dev, "Searching for i450NX host bridges\n");
  	reg = 0xd0;
 -	for(pxb=0; pxb<2; pxb++) {
 +	for(pxb = 0; pxb < 2; pxb++) {
  		pci_read_config_byte(d, reg++, &busno);
  		pci_read_config_byte(d, reg++, &suba);
  		pci_read_config_byte(d, reg++, &subb);
-@@ -56,7 +56,7 @@ static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
+@@ -41,7 +41,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d)
+ 	 */
+ 	u8 busno;
+ 	pci_read_config_byte(d, 0x4a, &busno);
+-	printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
++	dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
+ 	pci_scan_bus_with_sysdata(busno);
+ 	pcibios_last_bus = -1;
+ }
+@@ -55,8 +55,8 @@ static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
+ 	 */
  	int i;
  
- 	printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d));
+-	printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d));
 -	for(i=0; i<4; i++)
++	dev_warn(&d->dev, "Fixing base address flags\n");
 +	for(i = 0; i < 4; i++)
  		d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
  }
  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide);
+@@ -68,7 +68,7 @@ static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
+ 	 * Fix class to be PCI_CLASS_STORAGE_SCSI
+ 	 */
+ 	if (!d->class) {
+-		printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d));
++		dev_warn(&d->dev, "Fixing NCR 53C810 class code\n");
+ 		d->class = PCI_CLASS_STORAGE_SCSI << 8;
+ 	}
+ }
+@@ -80,7 +80,7 @@ static void __devinit  pci_fixup_latency(struct pci_dev *d)
+ 	 *  SiS 5597 and 5598 chipsets require latency timer set to
+ 	 *  at most 32 to avoid lockups.
+ 	 */
+-	DBG("PCI: Setting max latency to 32\n");
++	dev_dbg(&d->dev, "Setting max latency to 32\n");
+ 	pcibios_max_latency = 32;
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency);
 @@ -127,7 +127,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
  		   NB latency to zero */
  		pci_write_config_byte(d, PCI_LATENCY_TIMER, 0);
@@ -329093,6 +337025,24 @@
  				different for the KT266x's: 0x95 not 0x55 */
  	} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
  			(d->revision == VIA_8363_KL133_REVISION_ID ||
+@@ -138,7 +138,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
+ 
+ 	pci_read_config_byte(d, where, &v);
+ 	if (v & ~mask) {
+-		printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
++		dev_warn(&d->dev, "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
+ 			d->device, d->revision, where, v, mask, v & mask);
+ 		v &= mask;
+ 		pci_write_config_byte(d, where, v);
+@@ -200,7 +200,7 @@ static void pci_fixup_nforce2(struct pci_dev *dev)
+ 	 * Apply fixup if needed, but don't touch disconnect state
+ 	 */
+ 	if ((val & 0x00FF0000) != 0x00010000) {
+-		printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n");
++		dev_warn(&dev->dev, "nForce2 C1 Halt Disconnect fixup\n");
+ 		pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000);
+ 	}
+ }
 @@ -230,7 +230,7 @@ static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int wh
  
  	if ((offset) && (where == offset))
@@ -329149,6 +337099,30 @@
  			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
  						&config);
  			if (!(config & PCI_BRIDGE_CTL_VGA))
+@@ -348,7 +348,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
+ 	pci_read_config_word(pdev, PCI_COMMAND, &config);
+ 	if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ 		pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+-		printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
++		dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ 	}
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+@@ -388,11 +388,11 @@ static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
+ 		/* verify the change for status output */
+ 		pci_read_config_byte(dev, 0x50, &val);
+ 		if (val & 0x40)
+-			printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
++			dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
+ 					"can't enable onboard soundcard!\n");
+ 		else
+-			printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+-					"enabled onboard soundcard.\n");
++			dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
++					"enabled onboard soundcard\n");
+ 	}
+ }
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
 diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
 index 88d8f5c..ed07ce6 100644
 --- a/arch/x86/pci/irq.c
@@ -331218,6 +339192,22 @@
  
  .pushsection .bss.page_aligned
  	.align PAGE_SIZE_asm
+diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
+index d3cb3d6..844721e 100644
+--- a/arch/xtensa/Kconfig
++++ b/arch/xtensa/Kconfig
+@@ -174,11 +174,6 @@ config PCI
+ 	  your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
+ 	  VESA. If you have PCI, say Y, otherwise N.
+ 
+-	  The PCI-HOWTO, available from
+-	  <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+-	  information about which PCI hardware does work under Linux and which
+-	  doesn't
+-
+ source "drivers/pci/Kconfig"
+ 
+ config HOTPLUG
 diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
 index ac4ed52..7d0f55a 100644
 --- a/arch/xtensa/kernel/vmlinux.lds.S
@@ -331296,22 +339286,37 @@
  obj-$(CONFIG_BLK_DEV_BSG)	+= bsg.o
  obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 diff --git a/block/as-iosched.c b/block/as-iosched.c
-index cb5e53b..9603684 100644
+index cb5e53b..8c39467 100644
 --- a/block/as-iosched.c
 +++ b/block/as-iosched.c
 @@ -170,9 +170,11 @@ static void free_as_io_context(struct as_io_context *aic)
  
  static void as_trim(struct io_context *ioc)
  {
-+	spin_lock(&ioc->lock);
++	spin_lock_irq(&ioc->lock);
  	if (ioc->aic)
  		free_as_io_context(ioc->aic);
  	ioc->aic = NULL;
-+	spin_unlock(&ioc->lock);
++	spin_unlock_irq(&ioc->lock);
  }
  
  /* Called when the task exits */
-@@ -462,7 +464,9 @@ static void as_antic_timeout(unsigned long data)
+@@ -233,10 +235,12 @@ static void as_put_io_context(struct request *rq)
+ 	aic = RQ_IOC(rq)->aic;
+ 
+ 	if (rq_is_sync(rq) && aic) {
+-		spin_lock(&aic->lock);
++		unsigned long flags;
++
++		spin_lock_irqsave(&aic->lock, flags);
+ 		set_bit(AS_TASK_IORUNNING, &aic->state);
+ 		aic->last_end_request = jiffies;
+-		spin_unlock(&aic->lock);
++		spin_unlock_irqrestore(&aic->lock, flags);
+ 	}
+ 
+ 	put_io_context(RQ_IOC(rq));
+@@ -462,7 +466,9 @@ static void as_antic_timeout(unsigned long data)
  	spin_lock_irqsave(q->queue_lock, flags);
  	if (ad->antic_status == ANTIC_WAIT_REQ
  			|| ad->antic_status == ANTIC_WAIT_NEXT) {
@@ -331322,7 +339327,7 @@
  
  		ad->antic_status = ANTIC_FINISHED;
  		kblockd_schedule_work(&ad->antic_work);
-@@ -475,6 +479,7 @@ static void as_antic_timeout(unsigned long data)
+@@ -475,6 +481,7 @@ static void as_antic_timeout(unsigned long data)
  			/* process not "saved" by a cooperating request */
  			ad->exit_no_coop = (7*ad->exit_no_coop + 256)/8;
  		}
@@ -331330,7 +339335,7 @@
  	}
  	spin_unlock_irqrestore(q->queue_lock, flags);
  }
-@@ -635,9 +640,11 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+@@ -635,9 +642,11 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
  
  	ioc = ad->io_context;
  	BUG_ON(!ioc);
@@ -331342,7 +339347,7 @@
  		return 1;
  	}
  
-@@ -646,20 +653,25 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+@@ -646,20 +655,25 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
  		 * In this situation status should really be FINISHED,
  		 * however the timer hasn't had the chance to run yet.
  		 */
@@ -331369,7 +339374,7 @@
  		return 1;
  	}
  
-@@ -680,6 +692,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+@@ -680,6 +694,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
  		}
  
  		as_update_iohist(ad, aic, rq);
@@ -331377,7 +339382,7 @@
  		return 1;
  	}
  
-@@ -688,20 +701,27 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
+@@ -688,20 +703,27 @@ static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
  		if (aic->ttime_samples == 0)
  			ad->exit_prob = (7*ad->exit_prob + 256)/8;
  
@@ -331409,27 +339414,29 @@
  	return 0;
  }
  
-@@ -1255,7 +1275,13 @@ static void as_merged_requests(struct request_queue *q, struct request *req,
- 			 * Don't copy here but swap, because when anext is
- 			 * removed below, it must contain the unused context
- 			 */
+@@ -1246,16 +1268,8 @@ static void as_merged_requests(struct request_queue *q, struct request *req,
+ 	 */
+ 	if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
+ 		if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
+-			struct io_context *rioc = RQ_IOC(req);
+-			struct io_context *nioc = RQ_IOC(next);
+-
+ 			list_move(&req->queuelist, &next->queuelist);
+ 			rq_set_fifo_time(req, rq_fifo_time(next));
+-			/*
+-			 * Don't copy here but swap, because when anext is
+-			 * removed below, it must contain the unused context
+-			 */
 -			swap_io_context(&rioc, &nioc);
-+			if (rioc != nioc) {
-+				double_spin_lock(&rioc->lock, &nioc->lock,
-+								rioc < nioc);
-+				swap_io_context(&rioc, &nioc);
-+				double_spin_unlock(&rioc->lock, &nioc->lock,
-+								rioc < nioc);
-+			}
  		}
  	}
  
 diff --git a/block/blk-barrier.c b/block/blk-barrier.c
 new file mode 100644
-index 0000000..5f74fec
+index 0000000..6901eed
 --- /dev/null
 +++ b/block/blk-barrier.c
-@@ -0,0 +1,319 @@
+@@ -0,0 +1,318 @@
 +/*
 + * Functions related to barrier IO handling
 + */
@@ -331458,7 +339465,8 @@
 +{
 +	if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
 +	    prepare_flush_fn == NULL) {
-+		printk(KERN_ERR "blk_queue_ordered: prepare_flush_fn required\n");
++		printk(KERN_ERR "%s: prepare_flush_fn required\n",
++								__FUNCTION__);
 +		return -EINVAL;
 +	}
 +
@@ -331479,7 +339487,6 @@
 +
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_ordered);
 +
 +/*
@@ -331747,20 +339754,20 @@
 +	bio_put(bio);
 +	return ret;
 +}
-+
 +EXPORT_SYMBOL(blkdev_issue_flush);
 diff --git a/block/blk-core.c b/block/blk-core.c
 new file mode 100644
-index 0000000..8ff9944
+index 0000000..4afb39c
 --- /dev/null
 +++ b/block/blk-core.c
-@@ -0,0 +1,2034 @@
+@@ -0,0 +1,2027 @@
 +/*
 + * Copyright (C) 1991, 1992 Linus Torvalds
 + * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
 + * Elevator latency, (C) 2000  Andrea Arcangeli <andrea at suse.de> SuSE
 + * Queue request tables / lock, selectable elevator, Jens Axboe <axboe at suse.de>
-+ * kernel-doc documentation started by NeilBrown <neilb at cse.unsw.edu.au> -  July2000
++ * kernel-doc documentation started by NeilBrown <neilb at cse.unsw.edu.au>
++ *	-  July2000
 + * bio rewrite, highmem i/o, etc, Jens Axboe <axboe at suse.de> - may 2001
 + */
 +
@@ -331799,7 +339806,7 @@
 +/*
 + * For queue allocation
 + */
-+struct kmem_cache *blk_requestq_cachep = NULL;
++struct kmem_cache *blk_requestq_cachep;
 +
 +/*
 + * Controlling structure to kblockd
@@ -331894,7 +339901,7 @@
 +			error = -EIO;
 +
 +		if (unlikely(nbytes > bio->bi_size)) {
-+			printk("%s: want %u bytes done, only %u left\n",
++			printk(KERN_ERR "%s: want %u bytes done, %u left\n",
 +			       __FUNCTION__, nbytes, bio->bi_size);
 +			nbytes = bio->bi_size;
 +		}
@@ -331918,23 +339925,26 @@
 +{
 +	int bit;
 +
-+	printk("%s: dev %s: type=%x, flags=%x\n", msg,
++	printk(KERN_INFO "%s: dev %s: type=%x, flags=%x\n", msg,
 +		rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
 +		rq->cmd_flags);
 +
-+	printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
-+						       rq->nr_sectors,
-+						       rq->current_nr_sectors);
-+	printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len);
++	printk(KERN_INFO "  sector %llu, nr/cnr %lu/%u\n",
++						(unsigned long long)rq->sector,
++						rq->nr_sectors,
++						rq->current_nr_sectors);
++	printk(KERN_INFO "  bio %p, biotail %p, buffer %p, data %p, len %u\n",
++						rq->bio, rq->biotail,
++						rq->buffer, rq->data,
++						rq->data_len);
 +
 +	if (blk_pc_request(rq)) {
-+		printk("cdb: ");
++		printk(KERN_INFO "  cdb: ");
 +		for (bit = 0; bit < sizeof(rq->cmd); bit++)
 +			printk("%02x ", rq->cmd[bit]);
 +		printk("\n");
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_dump_rq_flags);
 +
 +/*
@@ -331961,7 +339971,6 @@
 +		blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_plug_device);
 +
 +/*
@@ -331978,7 +339987,6 @@
 +	del_timer(&q->unplug_timer);
 +	return 1;
 +}
-+
 +EXPORT_SYMBOL(blk_remove_plug);
 +
 +/*
@@ -332085,7 +340093,6 @@
 +		kblockd_schedule_work(&q->unplug_work);
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_start_queue);
 +
 +/**
@@ -332165,7 +340172,7 @@
 +}
 +EXPORT_SYMBOL(blk_put_queue);
 +
-+void blk_cleanup_queue(struct request_queue * q)
++void blk_cleanup_queue(struct request_queue *q)
 +{
 +	mutex_lock(&q->sysfs_lock);
 +	set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
@@ -332176,7 +340183,6 @@
 +
 +	blk_put_queue(q);
 +}
-+
 +EXPORT_SYMBOL(blk_cleanup_queue);
 +
 +static int blk_init_free_list(struct request_queue *q)
@@ -332332,7 +340338,6 @@
 +
 +	return 1;
 +}
-+
 +EXPORT_SYMBOL(blk_get_queue);
 +
 +static inline void blk_free_request(struct request_queue *q, struct request *rq)
@@ -332531,7 +340536,7 @@
 +	 */
 +	if (ioc_batching(q, ioc))
 +		ioc->nr_batch_requests--;
-+	
++
 +	rq_init(q, rq);
 +
 +	blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
@@ -332645,7 +340650,6 @@
 +
 +	elv_requeue_request(q, rq);
 +}
-+
 +EXPORT_SYMBOL(blk_requeue_request);
 +
 +/**
@@ -332696,7 +340700,6 @@
 +	blk_start_queueing(q);
 +	spin_unlock_irqrestore(q->queue_lock, flags);
 +}
-+
 +EXPORT_SYMBOL(blk_insert_request);
 +
 +/*
@@ -332704,7 +340707,7 @@
 + * queue lock is held and interrupts disabled, as we muck with the
 + * request queue list.
 + */
-+static inline void add_request(struct request_queue * q, struct request * req)
++static inline void add_request(struct request_queue *q, struct request *req)
 +{
 +	drive_stat_acct(req, 1);
 +
@@ -332714,7 +340717,7 @@
 +	 */
 +	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
 +}
-+ 
++
 +/*
 + * disk_round_stats()	- Round off the performance stats on a struct
 + * disk_stats.
@@ -332744,7 +340747,6 @@
 +	}
 +	disk->stamp = now;
 +}
-+
 +EXPORT_SYMBOL_GPL(disk_round_stats);
 +
 +/*
@@ -332774,7 +340776,6 @@
 +		freed_request(q, rw, priv);
 +	}
 +}
-+
 +EXPORT_SYMBOL_GPL(__blk_put_request);
 +
 +void blk_put_request(struct request *req)
@@ -332792,7 +340793,6 @@
 +		spin_unlock_irqrestore(q->queue_lock, flags);
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_put_request);
 +
 +void init_request_from_bio(struct request *req, struct bio *bio)
@@ -332853,53 +340853,53 @@
 +
 +	el_ret = elv_merge(q, &req, bio);
 +	switch (el_ret) {
-+		case ELEVATOR_BACK_MERGE:
-+			BUG_ON(!rq_mergeable(req));
++	case ELEVATOR_BACK_MERGE:
++		BUG_ON(!rq_mergeable(req));
 +
-+			if (!ll_back_merge_fn(q, req, bio))
-+				break;
++		if (!ll_back_merge_fn(q, req, bio))
++			break;
 +
-+			blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
++		blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
 +
-+			req->biotail->bi_next = bio;
-+			req->biotail = bio;
-+			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
-+			req->ioprio = ioprio_best(req->ioprio, prio);
-+			drive_stat_acct(req, 0);
-+			if (!attempt_back_merge(q, req))
-+				elv_merged_request(q, req, el_ret);
-+			goto out;
++		req->biotail->bi_next = bio;
++		req->biotail = bio;
++		req->nr_sectors = req->hard_nr_sectors += nr_sectors;
++		req->ioprio = ioprio_best(req->ioprio, prio);
++		drive_stat_acct(req, 0);
++		if (!attempt_back_merge(q, req))
++			elv_merged_request(q, req, el_ret);
++		goto out;
 +
-+		case ELEVATOR_FRONT_MERGE:
-+			BUG_ON(!rq_mergeable(req));
++	case ELEVATOR_FRONT_MERGE:
++		BUG_ON(!rq_mergeable(req));
 +
-+			if (!ll_front_merge_fn(q, req, bio))
-+				break;
++		if (!ll_front_merge_fn(q, req, bio))
++			break;
 +
-+			blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
++		blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
 +
-+			bio->bi_next = req->bio;
-+			req->bio = bio;
++		bio->bi_next = req->bio;
++		req->bio = bio;
 +
-+			/*
-+			 * may not be valid. if the low level driver said
-+			 * it didn't need a bounce buffer then it better
-+			 * not touch req->buffer either...
-+			 */
-+			req->buffer = bio_data(bio);
-+			req->current_nr_sectors = bio_cur_sectors(bio);
-+			req->hard_cur_sectors = req->current_nr_sectors;
-+			req->sector = req->hard_sector = bio->bi_sector;
-+			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
-+			req->ioprio = ioprio_best(req->ioprio, prio);
-+			drive_stat_acct(req, 0);
-+			if (!attempt_front_merge(q, req))
-+				elv_merged_request(q, req, el_ret);
-+			goto out;
++		/*
++		 * may not be valid. if the low level driver said
++		 * it didn't need a bounce buffer then it better
++		 * not touch req->buffer either...
++		 */
++		req->buffer = bio_data(bio);
++		req->current_nr_sectors = bio_cur_sectors(bio);
++		req->hard_cur_sectors = req->current_nr_sectors;
++		req->sector = req->hard_sector = bio->bi_sector;
++		req->nr_sectors = req->hard_nr_sectors += nr_sectors;
++		req->ioprio = ioprio_best(req->ioprio, prio);
++		drive_stat_acct(req, 0);
++		if (!attempt_front_merge(q, req))
++			elv_merged_request(q, req, el_ret);
++		goto out;
 +
-+		/* ELV_NO_MERGE: elevator says don't/can't merge. */
-+		default:
-+			;
++	/* ELV_NO_MERGE: elevator says don't/can't merge. */
++	default:
++		;
 +	}
 +
 +get_rq:
@@ -333107,7 +341107,7 @@
 +		}
 +
 +		if (unlikely(nr_sectors > q->max_hw_sectors)) {
-+			printk("bio too big device %s (%u > %u)\n", 
++			printk(KERN_ERR "bio too big device %s (%u > %u)\n",
 +				bdevname(bio->bi_bdev, b),
 +				bio_sectors(bio),
 +				q->max_hw_sectors);
@@ -333196,7 +341196,6 @@
 +	} while (bio);
 +	current->bio_tail = NULL; /* deactivate */
 +}
-+
 +EXPORT_SYMBOL(generic_make_request);
 +
 +/**
@@ -333237,13 +341236,12 @@
 +			current->comm, task_pid_nr(current),
 +				(rw & WRITE) ? "WRITE" : "READ",
 +				(unsigned long long)bio->bi_sector,
-+				bdevname(bio->bi_bdev,b));
++				bdevname(bio->bi_bdev, b));
 +		}
 +	}
 +
 +	generic_make_request(bio);
 +}
-+
 +EXPORT_SYMBOL(submit_bio);
 +
 +/**
@@ -333275,9 +341273,8 @@
 +	if (!blk_pc_request(req))
 +		req->errors = 0;
 +
-+	if (error) {
-+		if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))
-+			printk("end_request: I/O error, dev %s, sector %llu\n",
++	if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) {
++		printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
 +				req->rq_disk ? req->rq_disk->disk_name : "?",
 +				(unsigned long long)req->sector);
 +	}
@@ -333311,9 +341308,9 @@
 +
 +			if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
 +				blk_dump_rq_flags(req, "__end_that");
-+				printk("%s: bio idx %d >= vcnt %d\n",
-+						__FUNCTION__,
-+						bio->bi_idx, bio->bi_vcnt);
++				printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
++						__FUNCTION__, bio->bi_idx,
++						bio->bi_vcnt);
 +				break;
 +			}
 +
@@ -333339,7 +341336,8 @@
 +		total_bytes += nbytes;
 +		nr_bytes -= nbytes;
 +
-+		if ((bio = req->bio)) {
++		bio = req->bio;
++		if (bio) {
 +			/*
 +			 * end more in this run, or just return 'not-done'
 +			 */
@@ -333383,15 +341381,16 @@
 +	local_irq_enable();
 +
 +	while (!list_empty(&local_list)) {
-+		struct request *rq = list_entry(local_list.next, struct request, donelist);
++		struct request *rq;
 +
++		rq = list_entry(local_list.next, struct request, donelist);
 +		list_del_init(&rq->donelist);
 +		rq->q->softirq_done_fn(rq);
 +	}
 +}
 +
-+static int __cpuinit blk_cpu_notify(struct notifier_block *self, unsigned long action,
-+			  void *hcpu)
++static int __cpuinit blk_cpu_notify(struct notifier_block *self,
++				    unsigned long action, void *hcpu)
 +{
 +	/*
 +	 * If a CPU goes away, splice its entries to the current CPU
@@ -333433,7 +341432,7 @@
 +	unsigned long flags;
 +
 +	BUG_ON(!req->q->softirq_done_fn);
-+		
++
 +	local_irq_save(flags);
 +
 +	cpu_list = &__get_cpu_var(blk_cpu_done);
@@ -333442,9 +341441,8 @@
 +
 +	local_irq_restore(flags);
 +}
-+
 +EXPORT_SYMBOL(blk_complete_request);
-+	
++
 +/*
 + * queue lock must be held
 + */
@@ -333603,8 +341601,9 @@
 + *     0 - we are done with this request
 + *     1 - this request is not freed yet, it still has pending buffers.
 + **/
-+static int blk_end_io(struct request *rq, int error, int nr_bytes,
-+		      int bidi_bytes, int (drv_callback)(struct request *))
++static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
++		      unsigned int bidi_bytes,
++		      int (drv_callback)(struct request *))
 +{
 +	struct request_queue *q = rq->q;
 +	unsigned long flags = 0UL;
@@ -333646,7 +341645,7 @@
 + *     0 - we are done with this request
 + *     1 - still buffers pending for this request
 + **/
-+int blk_end_request(struct request *rq, int error, int nr_bytes)
++int blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 +{
 +	return blk_end_io(rq, error, nr_bytes, 0, NULL);
 +}
@@ -333665,7 +341664,7 @@
 + *     0 - we are done with this request
 + *     1 - still buffers pending for this request
 + **/
-+int __blk_end_request(struct request *rq, int error, int nr_bytes)
++int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 +{
 +	if (blk_fs_request(rq) || blk_pc_request(rq)) {
 +		if (__end_that_request_first(rq, error, nr_bytes))
@@ -333694,8 +341693,8 @@
 + *     0 - we are done with this request
 + *     1 - still buffers pending for this request
 + **/
-+int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
-+			 int bidi_bytes)
++int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes,
++			 unsigned int bidi_bytes)
 +{
 +	return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL);
 +}
@@ -333726,7 +341725,8 @@
 + *         this request still has pending buffers or
 + *         the driver doesn't want to finish this request yet.
 + **/
-+int blk_end_request_callback(struct request *rq, int error, int nr_bytes,
++int blk_end_request_callback(struct request *rq, int error,
++			     unsigned int nr_bytes,
 +			     int (drv_callback)(struct request *))
 +{
 +	return blk_end_io(rq, error, nr_bytes, 0, drv_callback);
@@ -333757,7 +341757,6 @@
 +{
 +	return queue_work(kblockd_workqueue, work);
 +}
-+
 +EXPORT_SYMBOL(kblockd_schedule_work);
 +
 +void kblockd_flush_work(struct work_struct *work)
@@ -333791,10 +341790,10 @@
 +
 diff --git a/block/blk-exec.c b/block/blk-exec.c
 new file mode 100644
-index 0000000..ebfb44e
+index 0000000..391dd62
 --- /dev/null
 +++ b/block/blk-exec.c
-@@ -0,0 +1,105 @@
+@@ -0,0 +1,104 @@
 +/*
 + * Functions related to setting various queue properties from drivers
 + */
@@ -333898,14 +341897,13 @@
 +
 +	return err;
 +}
-+
 +EXPORT_SYMBOL(blk_execute_rq);
 diff --git a/block/blk-ioc.c b/block/blk-ioc.c
 new file mode 100644
-index 0000000..6d16755
+index 0000000..80245dc
 --- /dev/null
 +++ b/block/blk-ioc.c
-@@ -0,0 +1,194 @@
+@@ -0,0 +1,185 @@
 +/*
 + * Functions related to io context handling
 + */
@@ -334084,15 +342082,6 @@
 +}
 +EXPORT_SYMBOL(copy_io_context);
 +
-+void swap_io_context(struct io_context **ioc1, struct io_context **ioc2)
-+{
-+	struct io_context *temp;
-+	temp = *ioc1;
-+	*ioc1 = *ioc2;
-+	*ioc2 = temp;
-+}
-+EXPORT_SYMBOL(swap_io_context);
-+
 +int __init blk_ioc_init(void)
 +{
 +	iocontext_cachep = kmem_cache_create("blkdev_ioc",
@@ -334102,10 +342091,10 @@
 +subsys_initcall(blk_ioc_init);
 diff --git a/block/blk-map.c b/block/blk-map.c
 new file mode 100644
-index 0000000..916cfc9
+index 0000000..955d75c
 --- /dev/null
 +++ b/block/blk-map.c
-@@ -0,0 +1,264 @@
+@@ -0,0 +1,262 @@
 +/*
 + * Functions related to mapping data to requests
 + */
@@ -334161,7 +342150,8 @@
 +	 * direct dma. else, set up kernel bounce buffers
 +	 */
 +	uaddr = (unsigned long) ubuf;
-+	if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))
++	if (!(uaddr & queue_dma_alignment(q)) &&
++	    !(len & queue_dma_alignment(q)))
 +		bio = bio_map_user(q, NULL, uaddr, len, reading);
 +	else
 +		bio = bio_copy_user(q, uaddr, len, reading);
@@ -334252,7 +342242,6 @@
 +	blk_rq_unmap_user(bio);
 +	return ret;
 +}
-+
 +EXPORT_SYMBOL(blk_rq_map_user);
 +
 +/**
@@ -334287,7 +342276,8 @@
 +	/* we don't allow misaligned data like bio_map_user() does.  If the
 +	 * user is using sg, they're expected to know the alignment constraints
 +	 * and respect them accordingly */
-+	bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ);
++	bio = bio_map_user_iov(q, NULL, iov, iov_count,
++				rq_data_dir(rq) == READ);
 +	if (IS_ERR(bio))
 +		return PTR_ERR(bio);
 +
@@ -334302,7 +342292,6 @@
 +	rq->buffer = rq->data = NULL;
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL(blk_rq_map_user_iov);
 +
 +/**
@@ -334335,7 +342324,6 @@
 +
 +	return ret;
 +}
-+
 +EXPORT_SYMBOL(blk_rq_unmap_user);
 +
 +/**
@@ -334368,11 +342356,10 @@
 +	rq->buffer = rq->data = NULL;
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL(blk_rq_map_kern);
 diff --git a/block/blk-merge.c b/block/blk-merge.c
 new file mode 100644
-index 0000000..5023f0b
+index 0000000..845ef81
 --- /dev/null
 +++ b/block/blk-merge.c
 @@ -0,0 +1,485 @@
@@ -334410,7 +342397,7 @@
 +		 * size, something has gone terribly wrong
 +		 */
 +		if (rq->nr_sectors < rq->current_nr_sectors) {
-+			printk("blk: request botched\n");
++			printk(KERN_ERR "blk: request botched\n");
 +			rq->nr_sectors = rq->current_nr_sectors;
 +		}
 +	}
@@ -334613,7 +342600,6 @@
 +
 +	return nsegs;
 +}
-+
 +EXPORT_SYMBOL(blk_rq_map_sg);
 +
 +static inline int ll_new_mergeable(struct request_queue *q,
@@ -334683,8 +342669,8 @@
 +	if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
 +		blk_recount_segments(q, bio);
 +	len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size;
-+	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) &&
-+	    !BIOVEC_VIRT_OVERSIZE(len)) {
++	if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))
++	    && !BIOVEC_VIRT_OVERSIZE(len)) {
 +		int mergeable =  ll_new_mergeable(q, req, bio);
 +
 +		if (mergeable) {
@@ -334699,7 +342685,7 @@
 +	return ll_new_hw_segment(q, req, bio);
 +}
 +
-+int ll_front_merge_fn(struct request_queue *q, struct request *req, 
++int ll_front_merge_fn(struct request_queue *q, struct request *req,
 +		      struct bio *bio)
 +{
 +	unsigned short max_sectors;
@@ -334766,7 +342752,8 @@
 +
 +	total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
 +	if (blk_hw_contig_segment(q, req->biotail, next->bio)) {
-+		int len = req->biotail->bi_hw_back_size + next->bio->bi_hw_front_size;
++		int len = req->biotail->bi_hw_back_size +
++				next->bio->bi_hw_front_size;
 +		/*
 +		 * propagate the combined length to the end of the requests
 +		 */
@@ -334863,10 +342850,10 @@
 +}
 diff --git a/block/blk-settings.c b/block/blk-settings.c
 new file mode 100644
-index 0000000..4df09a1
+index 0000000..c8d0c57
 --- /dev/null
 +++ b/block/blk-settings.c
-@@ -0,0 +1,402 @@
+@@ -0,0 +1,395 @@
 +/*
 + * Functions related to setting various queue properties from drivers
 + */
@@ -334879,8 +342866,10 @@
 +
 +#include "blk.h"
 +
-+unsigned long blk_max_low_pfn, blk_max_pfn;
++unsigned long blk_max_low_pfn;
 +EXPORT_SYMBOL(blk_max_low_pfn);
++
++unsigned long blk_max_pfn;
 +EXPORT_SYMBOL(blk_max_pfn);
 +
 +/**
@@ -334898,7 +342887,6 @@
 +{
 +	q->prep_rq_fn = pfn;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_prep_rq);
 +
 +/**
@@ -334921,14 +342909,12 @@
 +{
 +	q->merge_bvec_fn = mbfn;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_merge_bvec);
 +
 +void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
 +{
 +	q->softirq_done_fn = fn;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_softirq_done);
 +
 +/**
@@ -334953,7 +342939,7 @@
 + *    __bio_kmap_atomic() to get a temporary kernel mapping, or by calling
 + *    blk_queue_bounce() to create a buffer in normal memory.
 + **/
-+void blk_queue_make_request(struct request_queue * q, make_request_fn * mfn)
++void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 +{
 +	/*
 +	 * set defaults
@@ -334962,7 +342948,8 @@
 +	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 +	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
 +	q->make_request_fn = mfn;
-+	q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
++	q->backing_dev_info.ra_pages =
++			(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 +	q->backing_dev_info.state = 0;
 +	q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
 +	blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
@@ -334986,7 +342973,6 @@
 +	 */
 +	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 +}
-+
 +EXPORT_SYMBOL(blk_queue_make_request);
 +
 +/**
@@ -335002,7 +342988,7 @@
 + **/
 +void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr)
 +{
-+	unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
++	unsigned long b_pfn = dma_addr >> PAGE_SHIFT;
 +	int dma = 0;
 +
 +	q->bounce_gfp = GFP_NOIO;
@@ -335010,21 +342996,20 @@
 +	/* Assume anything <= 4GB can be handled by IOMMU.
 +	   Actually some IOMMUs can handle everything, but I don't
 +	   know of a way to test this here. */
-+	if (bounce_pfn < (min_t(u64,0xffffffff,BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
++	if (b_pfn < (min_t(u64, 0xffffffff, BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
 +		dma = 1;
 +	q->bounce_pfn = max_low_pfn;
 +#else
-+	if (bounce_pfn < blk_max_low_pfn)
++	if (b_pfn < blk_max_low_pfn)
 +		dma = 1;
-+	q->bounce_pfn = bounce_pfn;
++	q->bounce_pfn = b_pfn;
 +#endif
 +	if (dma) {
 +		init_emergency_isa_pool();
 +		q->bounce_gfp = GFP_NOIO | GFP_DMA;
-+		q->bounce_pfn = bounce_pfn;
++		q->bounce_pfn = b_pfn;
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_queue_bounce_limit);
 +
 +/**
@@ -335040,7 +343025,8 @@
 +{
 +	if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
 +		max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
-+		printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors);
++		printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
++							max_sectors);
 +	}
 +
 +	if (BLK_DEF_MAX_SECTORS > max_sectors)
@@ -335050,7 +343036,6 @@
 +		q->max_hw_sectors = max_sectors;
 +	}
 +}
-+
 +EXPORT_SYMBOL(blk_queue_max_sectors);
 +
 +/**
@@ -335068,12 +343053,12 @@
 +{
 +	if (!max_segments) {
 +		max_segments = 1;
-+		printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
++		printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
++							max_segments);
 +	}
 +
 +	q->max_phys_segments = max_segments;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_max_phys_segments);
 +
 +/**
@@ -335092,12 +343077,12 @@
 +{
 +	if (!max_segments) {
 +		max_segments = 1;
-+		printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
++		printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
++							max_segments);
 +	}
 +
 +	q->max_hw_segments = max_segments;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_max_hw_segments);
 +
 +/**
@@ -335113,12 +343098,12 @@
 +{
 +	if (max_size < PAGE_CACHE_SIZE) {
 +		max_size = PAGE_CACHE_SIZE;
-+		printk("%s: set to minimum %d\n", __FUNCTION__, max_size);
++		printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
++							max_size);
 +	}
 +
 +	q->max_segment_size = max_size;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_max_segment_size);
 +
 +/**
@@ -335136,7 +343121,6 @@
 +{
 +	q->hardsect_size = size;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_hardsect_size);
 +
 +/*
@@ -335152,17 +343136,16 @@
 +void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 +{
 +	/* zero is "infinity" */
-+	t->max_sectors = min_not_zero(t->max_sectors,b->max_sectors);
-+	t->max_hw_sectors = min_not_zero(t->max_hw_sectors,b->max_hw_sectors);
++	t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
++	t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
 +
-+	t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments);
-+	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);
++	t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments);
++	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);
 +
 +/**
@@ -335201,7 +343184,6 @@
 +
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL_GPL(blk_queue_dma_drain);
 +
 +/**
@@ -335213,12 +343195,12 @@
 +{
 +	if (mask < PAGE_CACHE_SIZE - 1) {
 +		mask = PAGE_CACHE_SIZE - 1;
-+		printk("%s: set to minimum %lx\n", __FUNCTION__, mask);
++		printk(KERN_INFO "%s: set to minimum %lx\n", __FUNCTION__,
++							mask);
 +	}
 +
 +	q->seg_boundary_mask = mask;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_segment_boundary);
 +
 +/**
@@ -335235,7 +343217,6 @@
 +{
 +	q->dma_alignment = mask;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_dma_alignment);
 +
 +/**
@@ -335259,7 +343240,6 @@
 +	if (mask > q->dma_alignment)
 +		q->dma_alignment = mask;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_update_dma_alignment);
 +
 +int __init blk_settings_init(void)
@@ -335271,10 +343251,10 @@
 +subsys_initcall(blk_settings_init);
 diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
 new file mode 100644
-index 0000000..bc28776
+index 0000000..54d0db1
 --- /dev/null
 +++ b/block/blk-sysfs.c
-@@ -0,0 +1,309 @@
+@@ -0,0 +1,310 @@
 +/*
 + * Functions related to sysfs handling
 + */
@@ -335484,12 +343464,13 @@
 +		    const char *page, size_t length)
 +{
 +	struct queue_sysfs_entry *entry = to_queue(attr);
-+	struct request_queue *q = container_of(kobj, struct request_queue, kobj);
-+
++	struct request_queue *q;
 +	ssize_t res;
 +
 +	if (!entry->store)
 +		return -EIO;
++
++	q = container_of(kobj, struct request_queue, kobj);
 +	mutex_lock(&q->sysfs_lock);
 +	if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
 +		mutex_unlock(&q->sysfs_lock);
@@ -335586,10 +343567,10 @@
 +}
 diff --git a/block/blk-tag.c b/block/blk-tag.c
 new file mode 100644
-index 0000000..d1fd300
+index 0000000..a8c37d4
 --- /dev/null
 +++ b/block/blk-tag.c
-@@ -0,0 +1,396 @@
+@@ -0,0 +1,390 @@
 +/*
 + * Functions related to tagged command queuing
 + */
@@ -335613,7 +343594,6 @@
 +{
 +	return blk_map_queue_find_tag(q->queue_tags, tag);
 +}
-+
 +EXPORT_SYMBOL(blk_queue_find_tag);
 +
 +/**
@@ -335691,7 +343671,6 @@
 +{
 +	clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
 +}
-+
 +EXPORT_SYMBOL(blk_queue_free_tags);
 +
 +static int
@@ -335777,7 +343756,8 @@
 +		if (!tags)
 +			goto fail;
 +	} else if (q->queue_tags) {
-+		if ((rc = blk_queue_resize_tags(q, depth)))
++		rc = blk_queue_resize_tags(q, depth);
++		if (rc)
 +			return rc;
 +		set_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
 +		return 0;
@@ -335795,7 +343775,6 @@
 +	kfree(tags);
 +	return -ENOMEM;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_init_tags);
 +
 +/**
@@ -335852,7 +343831,6 @@
 +	kfree(tag_map);
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_resize_tags);
 +
 +/**
@@ -335905,7 +343883,6 @@
 +	clear_bit_unlock(tag, bqt->tag_map);
 +	bqt->busy--;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_end_tag);
 +
 +/**
@@ -335932,7 +343909,7 @@
 +	int tag;
 +
 +	if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
-+		printk(KERN_ERR 
++		printk(KERN_ERR
 +		       "%s: request %p for device [%s] already tagged %d",
 +		       __FUNCTION__, rq,
 +		       rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag);
@@ -335962,7 +343939,6 @@
 +	bqt->busy++;
 +	return 0;
 +}
-+
 +EXPORT_SYMBOL(blk_queue_start_tag);
 +
 +/**
@@ -335984,7 +343960,6 @@
 +	list_for_each_safe(tmp, n, &q->tag_busy_list)
 +		blk_requeue_request(q, list_entry_rq(tmp));
 +}
-+
 +EXPORT_SYMBOL(blk_queue_invalidate_tags);
 diff --git a/block/blk.h b/block/blk.h
 new file mode 100644
@@ -336205,10 +344180,27 @@
  	/*
  	 * block device ioctls
 diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
-index 13553e0..f28d1fb 100644
+index 13553e0..ca198e6 100644
 --- a/block/cfq-iosched.c
 +++ b/block/cfq-iosched.c
-@@ -26,9 +26,9 @@ static const int cfq_slice_async_rq = 2;
+@@ -15,20 +15,22 @@
+ /*
+  * tunables
+  */
+-static const int cfq_quantum = 4;		/* max queue in one round of service */
++/* max queue in one round of service */
++static const int cfq_quantum = 4;
+ static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
+-static const int cfq_back_max = 16 * 1024;	/* maximum backwards seek, in KiB */
+-static const int cfq_back_penalty = 2;		/* penalty of a backwards seek */
+-
++/* maximum backwards seek, in KiB */
++static const int cfq_back_max = 16 * 1024;
++/* penalty of a backwards seek */
++static const int cfq_back_penalty = 2;
+ 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 / 125;
  
  /*
@@ -336220,7 +344212,17 @@
  
  /*
   * below this threshold, we consider thinktime immediate
-@@ -98,8 +98,6 @@ struct cfq_data {
+@@ -37,7 +39,8 @@ static int cfq_slice_idle = HZ / 125;
+ 
+ #define CFQ_SLICE_SCALE		(5)
+ 
+-#define RQ_CIC(rq)		((struct cfq_io_context*)(rq)->elevator_private)
++#define RQ_CIC(rq)		\
++	((struct cfq_io_context *) (rq)->elevator_private)
+ #define RQ_CFQQ(rq)		((rq)->elevator_private2)
+ 
+ static struct kmem_cache *cfq_pool;
+@@ -98,8 +101,6 @@ struct cfq_data {
  	struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
  	struct cfq_queue *async_idle_cfqq;
  
@@ -336229,7 +344231,26 @@
  	sector_t last_position;
  	unsigned long last_end_request;
  
-@@ -199,8 +197,8 @@ CFQ_CFQQ_FNS(sync);
+@@ -173,15 +174,15 @@ enum cfqq_state_flags {
+ #define CFQ_CFQQ_FNS(name)						\
+ static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq)		\
+ {									\
+-	cfqq->flags |= (1 << CFQ_CFQQ_FLAG_##name);			\
++	(cfqq)->flags |= (1 << CFQ_CFQQ_FLAG_##name);			\
+ }									\
+ static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq)	\
+ {									\
+-	cfqq->flags &= ~(1 << CFQ_CFQQ_FLAG_##name);			\
++	(cfqq)->flags &= ~(1 << CFQ_CFQQ_FLAG_##name);			\
+ }									\
+ static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq)		\
+ {									\
+-	return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;	\
++	return ((cfqq)->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;	\
+ }
+ 
+ CFQ_CFQQ_FNS(on_rr);
+@@ -199,8 +200,8 @@ CFQ_CFQQ_FNS(sync);
  
  static void cfq_dispatch_insert(struct request_queue *, struct request *);
  static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
@@ -336240,7 +344261,7 @@
  						struct io_context *);
  
  static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
-@@ -384,12 +382,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
+@@ -384,12 +385,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
  /*
   * The below is leftmost cache rbtree addon
   */
@@ -336258,7 +344279,7 @@
  }
  
  static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
-@@ -446,12 +447,20 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+@@ -446,12 +450,20 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
  static void cfq_service_tree_add(struct cfq_data *cfqd,
  				    struct cfq_queue *cfqq, int add_front)
  {
@@ -336282,7 +344303,7 @@
  		rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
  		rb_key += cfqq->slice_resid;
  		cfqq->slice_resid = 0;
-@@ -469,8 +478,9 @@ static void cfq_service_tree_add(struct cfq_data *cfqd,
+@@ -469,8 +481,9 @@ static void cfq_service_tree_add(struct cfq_data *cfqd,
  	}
  
  	left = 1;
@@ -336293,7 +344314,7 @@
  		struct rb_node **n;
  
  		parent = *p;
-@@ -524,8 +534,7 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+@@ -524,8 +537,7 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
   * add to busy list of queues for service, trying to be fair in ordering
   * the pending list according to last request service
   */
@@ -336303,7 +344324,7 @@
  {
  	BUG_ON(cfq_cfqq_on_rr(cfqq));
  	cfq_mark_cfqq_on_rr(cfqq);
-@@ -538,8 +547,7 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+@@ -538,8 +550,7 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
   * Called when the cfqq no longer has requests pending, remove it from
   * the service tree.
   */
@@ -336313,7 +344334,7 @@
  {
  	BUG_ON(!cfq_cfqq_on_rr(cfqq));
  	cfq_clear_cfqq_on_rr(cfqq);
-@@ -554,7 +562,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+@@ -554,7 +565,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
  /*
   * rb tree support functions
   */
@@ -336322,7 +344343,7 @@
  {
  	struct cfq_queue *cfqq = RQ_CFQQ(rq);
  	struct cfq_data *cfqd = cfqq->cfqd;
-@@ -594,8 +602,7 @@ static void cfq_add_rq_rb(struct request *rq)
+@@ -594,8 +605,7 @@ static void cfq_add_rq_rb(struct request *rq)
  	BUG_ON(!cfqq->next_rq);
  }
  
@@ -336332,7 +344353,7 @@
  {
  	elv_rb_del(&cfqq->sort_list, rq);
  	cfqq->queued[rq_is_sync(rq)]--;
-@@ -609,7 +616,7 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
+@@ -609,7 +619,7 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
  	struct cfq_io_context *cic;
  	struct cfq_queue *cfqq;
  
@@ -336341,7 +344362,7 @@
  	if (!cic)
  		return NULL;
  
-@@ -721,7 +728,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
+@@ -721,7 +731,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
  	 * Lookup the cfqq that this bio will be queued with. Allow
  	 * merge only if rq is queued there.
  	 */
@@ -336350,7 +344371,7 @@
  	if (!cic)
  		return 0;
  
-@@ -732,15 +739,10 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
+@@ -732,15 +742,10 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
  	return 0;
  }
  
@@ -336368,7 +344389,7 @@
  		cfqq->slice_end = 0;
  		cfq_clear_cfqq_must_alloc_slice(cfqq);
  		cfq_clear_cfqq_fifo_expire(cfqq);
-@@ -789,47 +791,16 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
+@@ -789,47 +794,16 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
  		__cfq_slice_expired(cfqd, cfqq, timed_out);
  }
  
@@ -336417,7 +344438,7 @@
  }
  
  /*
-@@ -895,7 +866,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
+@@ -895,7 +869,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
  	 * task has exited, don't wait
  	 */
  	cic = cfqd->active_cic;
@@ -336426,7 +344447,7 @@
  		return;
  
  	/*
-@@ -939,7 +910,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
+@@ -939,7 +913,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
  /*
   * return expired entry, or NULL to just start from scratch in rbtree
   */
@@ -336435,7 +344456,17 @@
  {
  	struct cfq_data *cfqd = cfqq->cfqd;
  	struct request *rq;
-@@ -1068,7 +1039,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+@@ -1034,7 +1008,8 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ 		/*
+ 		 * follow expired path, else get first next available
+ 		 */
+-		if ((rq = cfq_check_fifo(cfqq)) == NULL)
++		rq = cfq_check_fifo(cfqq);
++		if (rq == NULL)
+ 			rq = cfqq->next_rq;
+ 
+ 		/*
+@@ -1068,7 +1043,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
  	return dispatched;
  }
  
@@ -336444,7 +344475,7 @@
  {
  	int dispatched = 0;
  
-@@ -1087,14 +1058,11 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
+@@ -1087,14 +1062,11 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
   */
  static int cfq_forced_dispatch(struct cfq_data *cfqd)
  {
@@ -336461,7 +344492,7 @@
  
  	cfq_slice_expired(cfqd, 0);
  
-@@ -1170,20 +1138,69 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
+@@ -1170,20 +1142,69 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
  	kmem_cache_free(cfq_pool, cfqq);
  }
  
@@ -336542,7 +344573,7 @@
  
  	elv_ioc_count_mod(ioc_count, -freed);
  
-@@ -1205,7 +1222,12 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
+@@ -1205,7 +1226,12 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
  					 struct cfq_io_context *cic)
  {
  	list_del_init(&cic->queue_list);
@@ -336555,7 +344586,7 @@
  	cic->key = NULL;
  
  	if (cic->cfqq[ASYNC]) {
-@@ -1219,16 +1241,18 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
+@@ -1219,16 +1245,18 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
  	}
  }
  
@@ -336577,7 +344608,7 @@
  	}
  }
  
-@@ -1238,21 +1262,8 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
+@@ -1238,21 +1266,8 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
   */
  static void cfq_exit_io_context(struct io_context *ioc)
  {
@@ -336601,7 +344632,7 @@
  }
  
  static struct cfq_io_context *
-@@ -1273,7 +1284,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+@@ -1273,7 +1288,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
  	return cic;
  }
  
@@ -336610,30 +344641,61 @@
  {
  	struct task_struct *tsk = current;
  	int ioprio_class;
-@@ -1281,7 +1292,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
+@@ -1281,30 +1296,30 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
  	if (!cfq_cfqq_prio_changed(cfqq))
  		return;
  
 -	ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
 +	ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio);
  	switch (ioprio_class) {
- 		default:
- 			printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
-@@ -1293,11 +1304,11 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
- 			cfqq->ioprio_class = IOPRIO_CLASS_BE;
- 			break;
- 		case IOPRIO_CLASS_RT:
+-		default:
+-			printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+-		case IOPRIO_CLASS_NONE:
+-			/*
+-			 * no prio set, place us in the middle of the BE classes
+-			 */
+-			cfqq->ioprio = task_nice_ioprio(tsk);
+-			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+-			break;
+-		case IOPRIO_CLASS_RT:
 -			cfqq->ioprio = task_ioprio(tsk);
-+			cfqq->ioprio = task_ioprio(ioc);
- 			cfqq->ioprio_class = IOPRIO_CLASS_RT;
- 			break;
- 		case IOPRIO_CLASS_BE:
+-			cfqq->ioprio_class = IOPRIO_CLASS_RT;
+-			break;
+-		case IOPRIO_CLASS_BE:
 -			cfqq->ioprio = task_ioprio(tsk);
-+			cfqq->ioprio = task_ioprio(ioc);
- 			cfqq->ioprio_class = IOPRIO_CLASS_BE;
- 			break;
- 		case IOPRIO_CLASS_IDLE:
-@@ -1316,7 +1327,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
+-			cfqq->ioprio_class = IOPRIO_CLASS_BE;
+-			break;
+-		case IOPRIO_CLASS_IDLE:
+-			cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
+-			cfqq->ioprio = 7;
+-			cfq_clear_cfqq_idle_window(cfqq);
+-			break;
++	default:
++		printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
++	case IOPRIO_CLASS_NONE:
++		/*
++		 * no prio set, place us in the middle of the BE classes
++		 */
++		cfqq->ioprio = task_nice_ioprio(tsk);
++		cfqq->ioprio_class = IOPRIO_CLASS_BE;
++		break;
++	case IOPRIO_CLASS_RT:
++		cfqq->ioprio = task_ioprio(ioc);
++		cfqq->ioprio_class = IOPRIO_CLASS_RT;
++		break;
++	case IOPRIO_CLASS_BE:
++		cfqq->ioprio = task_ioprio(ioc);
++		cfqq->ioprio_class = IOPRIO_CLASS_BE;
++		break;
++	case IOPRIO_CLASS_IDLE:
++		cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
++		cfqq->ioprio = 7;
++		cfq_clear_cfqq_idle_window(cfqq);
++		break;
+ 	}
+ 
+ 	/*
+@@ -1316,7 +1331,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
  	cfq_clear_cfqq_prio_changed(cfqq);
  }
  
@@ -336642,7 +344704,7 @@
  {
  	struct cfq_data *cfqd = cic->key;
  	struct cfq_queue *cfqq;
-@@ -1330,8 +1341,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
+@@ -1330,8 +1345,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
  	cfqq = cic->cfqq[ASYNC];
  	if (cfqq) {
  		struct cfq_queue *new_cfqq;
@@ -336652,7 +344714,7 @@
  		if (new_cfqq) {
  			cic->cfqq[ASYNC] = new_cfqq;
  			cfq_put_queue(cfqq);
-@@ -1347,29 +1357,19 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
+@@ -1347,29 +1361,19 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
  
  static void cfq_ioc_set_ioprio(struct io_context *ioc)
  {
@@ -336685,7 +344747,7 @@
  	/* cic always exists here */
  	cfqq = cic_to_cfqq(cic, is_sync);
  
-@@ -1404,15 +1404,16 @@ retry:
+@@ -1404,15 +1408,16 @@ retry:
  		atomic_set(&cfqq->ref, 0);
  		cfqq->cfqd = cfqd;
  
@@ -336708,7 +344770,16 @@
  	}
  
  	if (new_cfqq)
-@@ -1439,11 +1440,11 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+@@ -1426,7 +1431,7 @@ out:
+ static struct cfq_queue **
+ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+ {
+-	switch(ioprio_class) {
++	switch (ioprio_class) {
+ 	case IOPRIO_CLASS_RT:
+ 		return &cfqd->async_cfqq[0][ioprio];
+ 	case IOPRIO_CLASS_BE:
+@@ -1439,11 +1444,11 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
  }
  
  static struct cfq_queue *
@@ -336723,7 +344794,7 @@
  	struct cfq_queue **async_cfqq = NULL;
  	struct cfq_queue *cfqq = NULL;
  
-@@ -1453,7 +1454,7 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
+@@ -1453,7 +1458,7 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
  	}
  
  	if (!cfqq) {
@@ -336732,7 +344803,7 @@
  		if (!cfqq)
  			return NULL;
  	}
-@@ -1470,28 +1471,42 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
+@@ -1470,28 +1475,42 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
  	return cfqq;
  }
  
@@ -336783,7 +344854,7 @@
  
  	if (unlikely(!ioc))
  		return NULL;
-@@ -1499,74 +1514,64 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
+@@ -1499,74 +1518,64 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
  	/*
  	 * we maintain a last-hit cache, to avoid browsing over the tree
  	 */
@@ -336897,7 +344968,7 @@
  }
  
  /*
-@@ -1586,7 +1591,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+@@ -1586,7 +1595,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
  	if (!ioc)
  		return NULL;
  
@@ -336906,7 +344977,7 @@
  	if (cic)
  		goto out;
  
-@@ -1594,13 +1599,17 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
+@@ -1594,13 +1603,17 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
  	if (cic == NULL)
  		goto err;
  
@@ -336925,7 +344996,7 @@
  err:
  	put_io_context(ioc);
  	return NULL;
-@@ -1655,12 +1664,15 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+@@ -1655,12 +1668,15 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
  {
  	int enable_idle;
  
@@ -336943,7 +345014,7 @@
  	    (cfqd->hw_tag && CIC_SEEKY(cic)))
  		enable_idle = 0;
  	else if (sample_valid(cic->ttime_samples)) {
-@@ -1793,7 +1805,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
+@@ -1793,7 +1809,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
  	struct cfq_data *cfqd = q->elevator->elevator_data;
  	struct cfq_queue *cfqq = RQ_CFQQ(rq);
  
@@ -336952,7 +345023,7 @@
  
  	cfq_add_rq_rb(rq);
  
-@@ -1834,7 +1846,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
+@@ -1834,7 +1850,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
  			cfq_set_prio_slice(cfqd, cfqq);
  			cfq_clear_cfqq_slice_new(cfqq);
  		}
@@ -336961,7 +345032,7 @@
  			cfq_slice_expired(cfqd, 1);
  		else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
  			cfq_arm_slice_timer(cfqd);
-@@ -1894,13 +1906,13 @@ static int cfq_may_queue(struct request_queue *q, int rw)
+@@ -1894,13 +1910,13 @@ static int cfq_may_queue(struct request_queue *q, int rw)
  	 * so just lookup a possibly existing queue, or return 'may queue'
  	 * if that fails
  	 */
@@ -336977,7 +345048,7 @@
  		cfq_prio_boost(cfqq);
  
  		return __cfq_may_queue(cfqq);
-@@ -1938,7 +1950,6 @@ static int
+@@ -1938,7 +1954,6 @@ static int
  cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
  {
  	struct cfq_data *cfqd = q->elevator->elevator_data;
@@ -336985,7 +345056,7 @@
  	struct cfq_io_context *cic;
  	const int rw = rq_data_dir(rq);
  	const int is_sync = rq_is_sync(rq);
-@@ -1956,7 +1967,7 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
+@@ -1956,7 +1971,7 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
  
  	cfqq = cic_to_cfqq(cic, is_sync);
  	if (!cfqq) {
@@ -336994,7 +345065,17 @@
  
  		if (!cfqq)
  			goto queue_fail;
-@@ -2039,29 +2050,9 @@ out_cont:
+@@ -2007,7 +2022,8 @@ static void cfq_idle_slice_timer(unsigned long data)
+ 
+ 	spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+ 
+-	if ((cfqq = cfqd->active_queue) != NULL) {
++	cfqq = cfqd->active_queue;
++	if (cfqq) {
+ 		timed_out = 0;
+ 
+ 		/*
+@@ -2039,29 +2055,9 @@ out_cont:
  	spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
  }
  
@@ -337024,7 +345105,7 @@
  	kblockd_flush_work(&cfqd->unplug_work);
  }
  
-@@ -2126,10 +2117,6 @@ static void *cfq_init_queue(struct request_queue *q)
+@@ -2126,10 +2122,6 @@ static void *cfq_init_queue(struct request_queue *q)
  	cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
  	cfqd->idle_slice_timer.data = (unsigned long) cfqd;
  
@@ -337035,7 +345116,7 @@
  	INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
  
  	cfqd->last_end_request = jiffies;
-@@ -2160,7 +2147,7 @@ static int __init cfq_slab_setup(void)
+@@ -2160,7 +2152,7 @@ static int __init cfq_slab_setup(void)
  	if (!cfq_pool)
  		goto fail;
  
@@ -337044,6 +345125,29 @@
  	if (!cfq_ioc_pool)
  		goto fail;
  
+@@ -2225,14 +2217,18 @@ static ssize_t __FUNC(elevator_t *e, const char *page, size_t count)	\
+ 	return ret;							\
+ }
+ STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
+-STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
+-STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
++STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1,
++		UINT_MAX, 1);
++STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1,
++		UINT_MAX, 1);
+ STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
+-STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0);
++STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1,
++		UINT_MAX, 0);
+ STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
+ 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_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
++		UINT_MAX, 0);
+ #undef STORE_FUNCTION
+ 
+ #define CFQ_ATTR(name) \
 diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
 index cae0a85..b733732 100644
 --- a/block/compat_ioctl.c
@@ -337075,10 +345179,20 @@
  	if (ret)
  		return ret;
 diff --git a/block/elevator.c b/block/elevator.c
-index e452deb..8cd5775 100644
+index e452deb..bafbae0 100644
 --- a/block/elevator.c
 +++ b/block/elevator.c
-@@ -185,9 +185,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
+@@ -45,7 +45,8 @@ static LIST_HEAD(elv_list);
+  */
+ static const int elv_hash_shift = 6;
+ #define ELV_HASH_BLOCK(sec)	((sec) >> 3)
+-#define ELV_HASH_FN(sec)	(hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
++#define ELV_HASH_FN(sec)	\
++		(hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
+ #define ELV_HASH_ENTRIES	(1 << elv_hash_shift)
+ #define rq_hash_key(rq)		((rq)->sector + (rq)->nr_sectors)
+ #define ELV_ON_HASH(rq)		(!hlist_unhashed(&(rq)->hash))
+@@ -185,9 +186,7 @@ static elevator_t *elevator_alloc(struct request_queue *q,
  
  	eq->ops = &e->ops;
  	eq->elevator_type = e;
@@ -337089,7 +345203,148 @@
  	mutex_init(&eq->sysfs_lock);
  
  	eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
-@@ -743,7 +741,21 @@ struct request *elv_next_request(struct request_queue *q)
+@@ -226,15 +225,27 @@ int elevator_init(struct request_queue *q, char *name)
+ 	q->end_sector = 0;
+ 	q->boundary_rq = NULL;
+ 
+-	if (name && !(e = elevator_get(name)))
+-		return -EINVAL;
++	if (name) {
++		e = elevator_get(name);
++		if (!e)
++			return -EINVAL;
++	}
+ 
+-	if (!e && *chosen_elevator && !(e = elevator_get(chosen_elevator)))
+-		printk("I/O scheduler %s not found\n", chosen_elevator);
++	if (!e && *chosen_elevator) {
++		e = elevator_get(chosen_elevator);
++		if (!e)
++			printk(KERN_ERR "I/O scheduler %s not found\n",
++							chosen_elevator);
++	}
+ 
+-	if (!e && !(e = elevator_get(CONFIG_DEFAULT_IOSCHED))) {
+-		printk("Default I/O scheduler not found, using no-op\n");
+-		e = elevator_get("noop");
++	if (!e) {
++		e = elevator_get(CONFIG_DEFAULT_IOSCHED);
++		if (!e) {
++			printk(KERN_ERR
++				"Default I/O scheduler not found. " \
++				"Using noop.\n");
++			e = elevator_get("noop");
++		}
+ 	}
+ 
+ 	eq = elevator_alloc(q, e);
+@@ -250,7 +261,6 @@ int elevator_init(struct request_queue *q, char *name)
+ 	elevator_attach(q, eq, data);
+ 	return ret;
+ }
+-
+ EXPORT_SYMBOL(elevator_init);
+ 
+ void elevator_exit(elevator_t *e)
+@@ -263,7 +273,6 @@ void elevator_exit(elevator_t *e)
+ 
+ 	kobject_put(&e->kobj);
+ }
+-
+ EXPORT_SYMBOL(elevator_exit);
+ 
+ static void elv_activate_rq(struct request_queue *q, struct request *rq)
+@@ -355,7 +364,6 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq)
+ 	rb_insert_color(&rq->rb_node, root);
+ 	return NULL;
+ }
+-
+ EXPORT_SYMBOL(elv_rb_add);
+ 
+ void elv_rb_del(struct rb_root *root, struct request *rq)
+@@ -364,7 +372,6 @@ void elv_rb_del(struct rb_root *root, struct request *rq)
+ 	rb_erase(&rq->rb_node, root);
+ 	RB_CLEAR_NODE(&rq->rb_node);
+ }
+-
+ EXPORT_SYMBOL(elv_rb_del);
+ 
+ struct request *elv_rb_find(struct rb_root *root, sector_t sector)
+@@ -385,7 +392,6 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector)
+ 
+ 	return NULL;
+ }
+-
+ EXPORT_SYMBOL(elv_rb_find);
+ 
+ /*
+@@ -397,6 +403,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
+ {
+ 	sector_t boundary;
+ 	struct list_head *entry;
++	int stop_flags;
+ 
+ 	if (q->last_merge == rq)
+ 		q->last_merge = NULL;
+@@ -406,13 +413,13 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
+ 	q->nr_sorted--;
+ 
+ 	boundary = q->end_sector;
+-
++	stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED;
+ 	list_for_each_prev(entry, &q->queue_head) {
+ 		struct request *pos = list_entry_rq(entry);
+ 
+ 		if (rq_data_dir(rq) != rq_data_dir(pos))
+ 			break;
+-		if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
++		if (pos->cmd_flags & stop_flags)
+ 			break;
+ 		if (rq->sector >= boundary) {
+ 			if (pos->sector < boundary)
+@@ -427,7 +434,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
+ 
+ 	list_add(&rq->queuelist, entry);
+ }
+-
+ EXPORT_SYMBOL(elv_dispatch_sort);
+ 
+ /*
+@@ -448,7 +454,6 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
+ 	q->boundary_rq = rq;
+ 	list_add_tail(&rq->queuelist, &q->queue_head);
+ }
+-
+ EXPORT_SYMBOL(elv_dispatch_add_tail);
+ 
+ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
+@@ -667,7 +672,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
+ 			q->end_sector = rq_end_sector(rq);
+ 			q->boundary_rq = rq;
+ 		}
+-	} else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
++	} else if (!(rq->cmd_flags & REQ_ELVPRIV) &&
++		    where == ELEVATOR_INSERT_SORT)
+ 		where = ELEVATOR_INSERT_BACK;
+ 
+ 	if (plug)
+@@ -675,7 +681,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
+ 
+ 	elv_insert(q, rq, where);
+ }
+-
+ EXPORT_SYMBOL(__elv_add_request);
+ 
+ void elv_add_request(struct request_queue *q, struct request *rq, int where,
+@@ -687,7 +692,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where,
+ 	__elv_add_request(q, rq, where, plug);
+ 	spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+-
+ EXPORT_SYMBOL(elv_add_request);
+ 
+ static inline struct request *__elv_next_request(struct request_queue *q)
+@@ -743,7 +747,21 @@ struct request *elv_next_request(struct request_queue *q)
  			q->boundary_rq = NULL;
  		}
  
@@ -337112,7 +345367,7 @@
  			break;
  
  		ret = q->prep_rq_fn(q, rq);
-@@ -756,6 +768,16 @@ struct request *elv_next_request(struct request_queue *q)
+@@ -756,6 +774,16 @@ struct request *elv_next_request(struct request_queue *q)
  			 * avoid resource deadlock.  REQ_STARTED will
  			 * prevent other fs requests from passing this one.
  			 */
@@ -337129,7 +345384,31 @@
  			rq = NULL;
  			break;
  		} else if (ret == BLKPREP_KILL) {
-@@ -931,9 +953,7 @@ int elv_register_queue(struct request_queue *q)
+@@ -770,7 +798,6 @@ struct request *elv_next_request(struct request_queue *q)
+ 
+ 	return rq;
+ }
+-
+ EXPORT_SYMBOL(elv_next_request);
+ 
+ void elv_dequeue_request(struct request_queue *q, struct request *rq)
+@@ -788,7 +815,6 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq)
+ 	if (blk_account_rq(rq))
+ 		q->in_flight++;
+ }
+-
+ EXPORT_SYMBOL(elv_dequeue_request);
+ 
+ int elv_queue_empty(struct request_queue *q)
+@@ -803,7 +829,6 @@ int elv_queue_empty(struct request_queue *q)
+ 
+ 	return 1;
+ }
+-
+ EXPORT_SYMBOL(elv_queue_empty);
+ 
+ struct request *elv_latter_request(struct request_queue *q, struct request *rq)
+@@ -931,9 +956,7 @@ int elv_register_queue(struct request_queue *q)
  	elevator_t *e = q->elevator;
  	int error;
  
@@ -337140,6 +345419,40 @@
  	if (!error) {
  		struct elv_fs_entry *attr = e->elevator_type->elevator_attrs;
  		if (attr) {
+@@ -974,7 +997,8 @@ void elv_register(struct elevator_type *e)
+ 			 !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
+ 				def = " (default)";
+ 
+-	printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, def);
++	printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name,
++								def);
+ }
+ EXPORT_SYMBOL_GPL(elv_register);
+ 
+@@ -1106,7 +1130,8 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
+ 	}
+ 
+ 	if (!elevator_switch(q, e))
+-		printk(KERN_ERR "elevator: switch to %s failed\n",elevator_name);
++		printk(KERN_ERR "elevator: switch to %s failed\n",
++							elevator_name);
+ 	return count;
+ }
+ 
+@@ -1140,7 +1165,6 @@ struct request *elv_rb_former_request(struct request_queue *q,
+ 
+ 	return NULL;
+ }
+-
+ EXPORT_SYMBOL(elv_rb_former_request);
+ 
+ struct request *elv_rb_latter_request(struct request_queue *q,
+@@ -1153,5 +1177,4 @@ struct request *elv_rb_latter_request(struct request_queue *q,
+ 
+ 	return NULL;
+ }
+-
+ EXPORT_SYMBOL(elv_rb_latter_request);
 diff --git a/block/genhd.c b/block/genhd.c
 index f2ac914..de2ebb2 100644
 --- a/block/genhd.c
@@ -355576,6 +363889,157 @@
  
  	result = acpi_bus_init();
  
+diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
+index 81b2484..fd1c4ba 100644
+--- a/drivers/acpi/hardware/hwsleep.c
++++ b/drivers/acpi/hardware/hwsleep.c
+@@ -192,18 +192,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
+ 	arg.type = ACPI_TYPE_INTEGER;
+ 	arg.integer.value = sleep_state;
+ 
+-	/* Run the _PTS and _GTS methods */
++	/* Run the _PTS method */
+ 
+ 	status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
+ 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ 		return_ACPI_STATUS(status);
+ 	}
+ 
+-	status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
+-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+-		return_ACPI_STATUS(status);
+-	}
+-
+ 	/* Setup the argument to _SST */
+ 
+ 	switch (sleep_state) {
+@@ -234,10 +229,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
+ 				"While executing method _SST"));
+ 	}
+ 
+-	/* Disable/Clear all GPEs */
+-
+-	status = acpi_hw_disable_all_gpes();
+-
+ 	return_ACPI_STATUS(status);
+ }
+ 
+@@ -262,6 +253,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
+ 	struct acpi_bit_register_info *sleep_type_reg_info;
+ 	struct acpi_bit_register_info *sleep_enable_reg_info;
+ 	u32 in_value;
++	struct acpi_object_list arg_list;
++	union acpi_object arg;
+ 	acpi_status status;
+ 
+ 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
+@@ -307,6 +300,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
+ 		return_ACPI_STATUS(status);
+ 	}
+ 
++	/* Execute the _GTS method */
++
++	arg_list.count = 1;
++	arg_list.pointer = &arg;
++	arg.type = ACPI_TYPE_INTEGER;
++	arg.integer.value = sleep_state;
++
++	status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
++	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
++		return_ACPI_STATUS(status);
++	}
++
+ 	/* Get current value of PM1A control */
+ 
+ 	status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+@@ -473,17 +478,18 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
+ 
+ /*******************************************************************************
+  *
+- * FUNCTION:    acpi_leave_sleep_state
++ * FUNCTION:    acpi_leave_sleep_state_prep
+  *
+- * PARAMETERS:  sleep_state         - Which sleep state we just exited
++ * PARAMETERS:  sleep_state         - Which sleep state we are exiting
+  *
+  * RETURN:      Status
+  *
+- * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+- *              Called with interrupts ENABLED.
++ * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
++ *              sleep.
++ *              Called with interrupts DISABLED.
+  *
+  ******************************************************************************/
+-acpi_status acpi_leave_sleep_state(u8 sleep_state)
++acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
+ {
+ 	struct acpi_object_list arg_list;
+ 	union acpi_object arg;
+@@ -493,7 +499,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
+ 	u32 PM1Acontrol;
+ 	u32 PM1Bcontrol;
+ 
+-	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
++	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
+ 
+ 	/*
+ 	 * Set SLP_TYPE and SLP_EN to state S0.
+@@ -540,6 +546,41 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
+ 		}
+ 	}
+ 
++	/* Execute the _BFS method */
++
++	arg_list.count = 1;
++	arg_list.pointer = &arg;
++	arg.type = ACPI_TYPE_INTEGER;
++	arg.integer.value = sleep_state;
++
++	status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
++	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
++		ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
++	}
++
++	return_ACPI_STATUS(status);
++}
++
++/*******************************************************************************
++ *
++ * FUNCTION:    acpi_leave_sleep_state
++ *
++ * PARAMETERS:  sleep_state         - Which sleep state we just exited
++ *
++ * RETURN:      Status
++ *
++ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
++ *              Called with interrupts ENABLED.
++ *
++ ******************************************************************************/
++acpi_status acpi_leave_sleep_state(u8 sleep_state)
++{
++	struct acpi_object_list arg_list;
++	union acpi_object arg;
++	acpi_status status;
++
++	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
++
+ 	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
+ 
+ 	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
+@@ -558,12 +599,6 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
+ 		ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
+ 	}
+ 
+-	arg.integer.value = sleep_state;
+-	status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
+-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+-		ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
+-	}
+-
+ 	/*
+ 	 * GPEs must be enabled before _WAK is called as GPEs
+ 	 * might get fired there
 diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
 index c9f526e..5400ea1 100644
 --- a/drivers/acpi/pci_link.c
@@ -355676,6 +364140,295 @@
  #endif
  	sleep_ticks = ticks_elapsed(t1, t2);
  	/* Tell the scheduler how much we idled: */
+diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
+index 2c0b663..485de13 100644
+--- a/drivers/acpi/sleep/main.c
++++ b/drivers/acpi/sleep/main.c
+@@ -26,9 +26,24 @@ u8 sleep_states[ACPI_S_STATE_COUNT];
+ 
+ #ifdef CONFIG_PM_SLEEP
+ static u32 acpi_target_sleep_state = ACPI_STATE_S0;
++static bool acpi_sleep_finish_wake_up;
++
++/*
++ * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
++ * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
++ * kernel command line option that causes the following variable to be set.
++ */
++static bool new_pts_ordering;
++
++static int __init acpi_new_pts_ordering(char *str)
++{
++	new_pts_ordering = true;
++	return 1;
++}
++__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
+ #endif
+ 
+-int acpi_sleep_prepare(u32 acpi_state)
++static int acpi_sleep_prepare(u32 acpi_state)
+ {
+ #ifdef CONFIG_ACPI_SLEEP
+ 	/* do we have a wakeup address for S2 and S3? */
+@@ -44,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state)
+ 	ACPI_FLUSH_CPU_CACHE();
+ 	acpi_enable_wakeup_device_prep(acpi_state);
+ #endif
++	printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
++		acpi_state);
+ 	acpi_enter_sleep_state_prep(acpi_state);
+ 	return 0;
+ }
+@@ -63,17 +80,25 @@ static u32 acpi_suspend_states[] = {
+ static int init_8259A_after_S1;
+ 
+ /**
+- *	acpi_pm_set_target - Set the target system sleep state to the state
++ *	acpi_pm_begin - Set the target system sleep state to the state
+  *		associated with given @pm_state, if supported.
+  */
+ 
+-static int acpi_pm_set_target(suspend_state_t pm_state)
++static int acpi_pm_begin(suspend_state_t pm_state)
+ {
+ 	u32 acpi_state = acpi_suspend_states[pm_state];
+ 	int error = 0;
+ 
+ 	if (sleep_states[acpi_state]) {
+ 		acpi_target_sleep_state = acpi_state;
++		if (new_pts_ordering)
++			return 0;
++
++		error = acpi_sleep_prepare(acpi_state);
++		if (error)
++			acpi_target_sleep_state = ACPI_STATE_S0;
++		else
++			acpi_sleep_finish_wake_up = true;
+ 	} else {
+ 		printk(KERN_ERR "ACPI does not support this state: %d\n",
+ 			pm_state);
+@@ -91,12 +116,17 @@ static int acpi_pm_set_target(suspend_state_t pm_state)
+ 
+ static int acpi_pm_prepare(void)
+ {
+-	int error = acpi_sleep_prepare(acpi_target_sleep_state);
++	if (new_pts_ordering) {
++		int error = acpi_sleep_prepare(acpi_target_sleep_state);
+ 
+-	if (error)
+-		acpi_target_sleep_state = ACPI_STATE_S0;
++		if (error) {
++			acpi_target_sleep_state = ACPI_STATE_S0;
++			return error;
++		}
++		acpi_sleep_finish_wake_up = true;
++	}
+ 
+-	return error;
++	return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
+ }
+ 
+ /**
+@@ -120,10 +150,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
+ 	if (acpi_state == ACPI_STATE_S3) {
+ 		int error = acpi_save_state_mem();
+ 
+-		if (error) {
+-			acpi_target_sleep_state = ACPI_STATE_S0;
++		if (error)
+ 			return error;
+-		}
+ 	}
+ 
+ 	local_irq_save(flags);
+@@ -139,6 +167,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
+ 		break;
+ 	}
+ 
++	/* Reprogram control registers and execute _BFS */
++	acpi_leave_sleep_state_prep(acpi_state);
++
+ 	/* ACPI 3.0 specs (P62) says that it's the responsabilty
+ 	 * of the OSPM to clear the status bit [ implying that the
+ 	 * POWER_BUTTON event should not reach userspace ]
+@@ -146,6 +177,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
+ 	if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
+ 		acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
+ 
++	/*
++	 * Disable and clear GPE status before interrupt is enabled. Some GPEs
++	 * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
++	 * acpi_leave_sleep_state will reenable specific GPEs later
++	 */
++	acpi_hw_disable_all_gpes();
++
+ 	local_irq_restore(flags);
+ 	printk(KERN_DEBUG "Back to C!\n");
+ 
+@@ -157,7 +195,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
+ }
+ 
+ /**
+- *	acpi_pm_finish - Finish up suspend sequence.
++ *	acpi_pm_finish - Instruct the platform to leave a sleep state.
+  *
+  *	This is called after we wake back up (or if entering the sleep state
+  *	failed). 
+@@ -174,6 +212,7 @@ static void acpi_pm_finish(void)
+ 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+ 
+ 	acpi_target_sleep_state = ACPI_STATE_S0;
++	acpi_sleep_finish_wake_up = false;
+ 
+ #ifdef CONFIG_X86
+ 	if (init_8259A_after_S1) {
+@@ -183,6 +222,20 @@ static void acpi_pm_finish(void)
+ #endif
+ }
+ 
++/**
++ *	acpi_pm_end - Finish up suspend sequence.
++ */
++
++static void acpi_pm_end(void)
++{
++	/*
++	 * This is necessary in case acpi_pm_finish() is not called directly
++	 * during a failing transition to a sleep state.
++	 */
++	if (acpi_sleep_finish_wake_up)
++		acpi_pm_finish();
++}
++
+ static int acpi_pm_state_valid(suspend_state_t pm_state)
+ {
+ 	u32 acpi_state;
+@@ -201,10 +254,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
+ 
+ static struct platform_suspend_ops acpi_pm_ops = {
+ 	.valid = acpi_pm_state_valid,
+-	.set_target = acpi_pm_set_target,
++	.begin = acpi_pm_begin,
+ 	.prepare = acpi_pm_prepare,
+ 	.enter = acpi_pm_enter,
+ 	.finish = acpi_pm_finish,
++	.end = acpi_pm_end,
+ };
+ 
+ /*
+@@ -229,15 +283,36 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+ #endif /* CONFIG_SUSPEND */
+ 
+ #ifdef CONFIG_HIBERNATION
+-static int acpi_hibernation_start(void)
++static int acpi_hibernation_begin(void)
+ {
++	int error;
++
+ 	acpi_target_sleep_state = ACPI_STATE_S4;
+-	return 0;
++	if (new_pts_ordering)
++		return 0;
++
++	error = acpi_sleep_prepare(ACPI_STATE_S4);
++	if (error)
++		acpi_target_sleep_state = ACPI_STATE_S0;
++	else
++		acpi_sleep_finish_wake_up = true;
++
++	return error;
+ }
+ 
+ static int acpi_hibernation_prepare(void)
+ {
+-	return acpi_sleep_prepare(ACPI_STATE_S4);
++	if (new_pts_ordering) {
++		int error = acpi_sleep_prepare(ACPI_STATE_S4);
++
++		if (error) {
++			acpi_target_sleep_state = ACPI_STATE_S0;
++			return error;
++		}
++		acpi_sleep_finish_wake_up = true;
++	}
++
++	return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
+ }
+ 
+ static int acpi_hibernation_enter(void)
+@@ -251,6 +326,8 @@ static int acpi_hibernation_enter(void)
+ 	acpi_enable_wakeup_device(ACPI_STATE_S4);
+ 	/* This shouldn't return.  If it returns, we have a problem */
+ 	status = acpi_enter_sleep_state(ACPI_STATE_S4);
++	/* Reprogram control registers and execute _BFS */
++	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+ 	local_irq_restore(flags);
+ 
+ 	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+@@ -263,15 +340,12 @@ static void acpi_hibernation_leave(void)
+ 	 * enable it here.
+ 	 */
+ 	acpi_enable();
++	/* Reprogram control registers and execute _BFS */
++	acpi_leave_sleep_state_prep(ACPI_STATE_S4);
+ }
+ 
+ static void acpi_hibernation_finish(void)
+ {
+-	/*
+-	 * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+-	 * enable it here.
+-	 */
+-	acpi_enable();
+ 	acpi_disable_wakeup_device(ACPI_STATE_S4);
+ 	acpi_leave_sleep_state(ACPI_STATE_S4);
+ 
+@@ -279,6 +353,17 @@ static void acpi_hibernation_finish(void)
+ 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+ 
+ 	acpi_target_sleep_state = ACPI_STATE_S0;
++	acpi_sleep_finish_wake_up = false;
++}
++
++static void acpi_hibernation_end(void)
++{
++	/*
++	 * This is necessary in case acpi_hibernation_finish() is not called
++	 * directly during a failing transition to the sleep state.
++	 */
++	if (acpi_sleep_finish_wake_up)
++		acpi_hibernation_finish();
+ }
+ 
+ static int acpi_hibernation_pre_restore(void)
+@@ -296,7 +381,8 @@ static void acpi_hibernation_restore_cleanup(void)
+ }
+ 
+ static struct platform_hibernation_ops acpi_hibernation_ops = {
+-	.start = acpi_hibernation_start,
++	.begin = acpi_hibernation_begin,
++	.end = acpi_hibernation_end,
+ 	.pre_snapshot = acpi_hibernation_prepare,
+ 	.finish = acpi_hibernation_finish,
+ 	.prepare = acpi_hibernation_prepare,
+@@ -403,6 +489,7 @@ static void acpi_power_off_prepare(void)
+ {
+ 	/* Prepare to power off the system */
+ 	acpi_sleep_prepare(ACPI_STATE_S5);
++	acpi_hw_disable_all_gpes();
+ }
+ 
+ static void acpi_power_off(void)
+diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
+index a2ea125..cfaf8f5 100644
+--- a/drivers/acpi/sleep/sleep.h
++++ b/drivers/acpi/sleep/sleep.h
+@@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state);
+ extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
+ extern void acpi_enable_wakeup_device(u8 sleep_state);
+ extern void acpi_disable_wakeup_device(u8 sleep_state);
+-
+-extern int acpi_sleep_prepare(u32 acpi_state);
 diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
 index edee280..5ffe0ea 100644
 --- a/drivers/acpi/system.c
@@ -355722,9 +364475,18 @@
  	return 0;
  }
 diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
-index ba63619..ae19c9b 100644
+index ba63619..ba8f7f4 100644
 --- a/drivers/ata/Kconfig
 +++ b/drivers/ata/Kconfig
+@@ -69,7 +69,7 @@ config ATA_PIIX
+ 
+ config SATA_MV
+ 	tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
+-	depends on PCI && EXPERIMENTAL
++	depends on EXPERIMENTAL
+ 	help
+ 	  This option enables support for the Marvell Serial ATA family.
+ 	  Currently supports 88SX[56]0[48][01] chips.
 @@ -184,7 +184,7 @@ config PATA_ACPI
  
  config SATA_FSL
@@ -355796,7 +364558,7 @@
  # Should be last but two libata driver
  obj-$(CONFIG_PATA_ACPI)		+= pata_acpi.o
 diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
-index 54f38c2..6f089b8 100644
+index 54f38c2..27c8d56 100644
 --- a/drivers/ata/ahci.c
 +++ b/drivers/ata/ahci.c
 @@ -198,18 +198,18 @@ enum {
@@ -355827,7 +364589,16 @@
  };
  
  struct ahci_host_priv {
-@@ -597,6 +597,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
+@@ -475,6 +475,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
+ 	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+ 	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+ 	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
++	{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
++	{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
+ 
+ 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
+ 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+@@ -597,6 +599,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
  	return __ahci_port_base(ap->host, ap->port_no);
  }
  
@@ -355848,7 +364619,7 @@
  /**
   *	ahci_save_initial_config - Save and fixup initial config values
   *	@pdev: target PCI device
-@@ -619,6 +633,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
+@@ -619,6 +635,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
  	u32 cap, port_map;
  	int i;
  
@@ -355858,7 +364629,7 @@
  	/* Values prefixed with saved_ are written back to host after
  	 * reset.  Values without are used for driver operation.
  	 */
-@@ -1036,19 +1053,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
+@@ -1036,19 +1055,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
  static int ahci_reset_controller(struct ata_host *host)
  {
  	struct pci_dev *pdev = to_pci_dev(host->dev);
@@ -355881,7 +364652,7 @@
  	if ((tmp & HOST_RESET) == 0) {
  		writel(tmp | HOST_RESET, mmio + HOST_CTL);
  		readl(mmio + HOST_CTL); /* flush */
-@@ -1067,8 +1082,7 @@ static int ahci_reset_controller(struct ata_host *host)
+@@ -1067,8 +1084,7 @@ static int ahci_reset_controller(struct ata_host *host)
  	}
  
  	/* turn on AHCI mode */
@@ -355891,7 +364662,7 @@
  
  	/* some registers might be cleared on reset.  restore initial values */
  	ahci_restore_initial_config(host);
-@@ -1078,8 +1092,10 @@ static int ahci_reset_controller(struct ata_host *host)
+@@ -1078,8 +1094,10 @@ static int ahci_reset_controller(struct ata_host *host)
  
  		/* configure PCS */
  		pci_read_config_word(pdev, 0x92, &tmp16);
@@ -355904,7 +364675,7 @@
  	}
  
  	return 0;
-@@ -1480,35 +1496,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+@@ -1480,35 +1498,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
  static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
  {
  	struct scatterlist *sg;
@@ -356032,7 +364803,7 @@
  	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
  	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
 diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
-index b406b39..a65c8ae 100644
+index b406b39..47892e6 100644
 --- a/drivers/ata/ata_piix.c
 +++ b/drivers/ata/ata_piix.c
 @@ -101,39 +101,21 @@ enum {
@@ -356123,7 +364894,22 @@
  #ifdef CONFIG_PM
  static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
  static int piix_pci_device_resume(struct pci_dev *pdev);
-@@ -321,7 +325,6 @@ static const struct ata_port_operations piix_pata_ops = {
+@@ -263,6 +267,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
+ 	{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ 	/* SATA Controller IDE (Tolapai) */
+ 	{ 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci },
++	/* SATA Controller IDE (ICH10) */
++	{ 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++	/* SATA Controller IDE (ICH10) */
++	{ 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
++	/* SATA Controller IDE (ICH10) */
++	{ 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++	/* SATA Controller IDE (ICH10) */
++	{ 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ 
+ 	{ }	/* terminate list */
+ };
+@@ -321,7 +333,6 @@ static const struct ata_port_operations piix_pata_ops = {
  	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
  	.cable_detect		= ata_cable_40wire,
  
@@ -356131,7 +364917,7 @@
  	.irq_clear		= ata_bmdma_irq_clear,
  	.irq_on			= ata_irq_on,
  
-@@ -353,7 +356,6 @@ static const struct ata_port_operations ich_pata_ops = {
+@@ -353,7 +364,6 @@ static const struct ata_port_operations ich_pata_ops = {
  	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
  	.cable_detect		= ich_pata_cable_detect,
  
@@ -356139,7 +364925,7 @@
  	.irq_clear		= ata_bmdma_irq_clear,
  	.irq_on			= ata_irq_on,
  
-@@ -380,7 +382,6 @@ static const struct ata_port_operations piix_sata_ops = {
+@@ -380,7 +390,6 @@ static const struct ata_port_operations piix_sata_ops = {
  	.error_handler		= ata_bmdma_error_handler,
  	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
  
@@ -356147,7 +364933,7 @@
  	.irq_clear		= ata_bmdma_irq_clear,
  	.irq_on			= ata_irq_on,
  
-@@ -419,6 +420,35 @@ static const struct ata_port_operations piix_vmw_ops = {
+@@ -419,6 +428,35 @@ static const struct ata_port_operations piix_vmw_ops = {
  	.port_start		= ata_port_start,
  };
  
@@ -356183,7 +364969,7 @@
  static const struct piix_map_db ich5_map_db = {
  	.mask = 0x7,
  	.port_enable = 0x3,
-@@ -526,7 +556,6 @@ static const struct piix_map_db *piix_map_db_table[] = {
+@@ -526,7 +564,6 @@ static const struct piix_map_db *piix_map_db_table[] = {
  static struct ata_port_info piix_port_info[] = {
  	[piix_pata_mwdma] = 	/* PIIX3 MWDMA only */
  	{
@@ -356191,7 +364977,7 @@
  		.flags		= PIIX_PATA_FLAGS,
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
-@@ -535,7 +564,6 @@ static struct ata_port_info piix_port_info[] = {
+@@ -535,7 +572,6 @@ static struct ata_port_info piix_port_info[] = {
  
  	[piix_pata_33] =	/* PIIX4 at 33MHz */
  	{
@@ -356199,7 +364985,7 @@
  		.flags		= PIIX_PATA_FLAGS,
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
-@@ -545,7 +573,6 @@ static struct ata_port_info piix_port_info[] = {
+@@ -545,7 +581,6 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich_pata_33] = 	/* ICH0 - ICH at 33Mhz*/
  	{
@@ -356207,7 +364993,7 @@
  		.flags		= PIIX_PATA_FLAGS,
  		.pio_mask 	= 0x1f,	/* pio 0-4 */
  		.mwdma_mask	= 0x06, /* Check: maybe 0x07  */
-@@ -555,7 +582,6 @@ static struct ata_port_info piix_port_info[] = {
+@@ -555,7 +590,6 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich_pata_66] = 	/* ICH controllers up to 66MHz */
  	{
@@ -356215,7 +365001,7 @@
  		.flags		= PIIX_PATA_FLAGS,
  		.pio_mask 	= 0x1f,	/* pio 0-4 */
  		.mwdma_mask	= 0x06, /* MWDMA0 is broken on chip */
-@@ -565,7 +591,6 @@ static struct ata_port_info piix_port_info[] = {
+@@ -565,7 +599,6 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich_pata_100] =
  	{
@@ -356223,7 +365009,7 @@
  		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x06, /* mwdma1-2 */
-@@ -575,7 +600,6 @@ static struct ata_port_info piix_port_info[] = {
+@@ -575,7 +608,6 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich5_sata] =
  	{
@@ -356231,7 +365017,7 @@
  		.flags		= PIIX_SATA_FLAGS,
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
-@@ -585,8 +609,7 @@ static struct ata_port_info piix_port_info[] = {
+@@ -585,8 +617,7 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich6_sata] =
  	{
@@ -356241,7 +365027,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -595,9 +618,7 @@ static struct ata_port_info piix_port_info[] = {
+@@ -595,9 +626,7 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich6_sata_ahci] =
  	{
@@ -356252,7 +365038,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -606,9 +627,7 @@ static struct ata_port_info piix_port_info[] = {
+@@ -606,9 +635,7 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich6m_sata_ahci] =
  	{
@@ -356263,7 +365049,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -617,9 +636,8 @@ static struct ata_port_info piix_port_info[] = {
+@@ -617,9 +644,8 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich8_sata_ahci] =
  	{
@@ -356275,7 +365061,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -628,9 +646,8 @@ static struct ata_port_info piix_port_info[] = {
+@@ -628,9 +654,8 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich8_2port_sata] =
  	{
@@ -356287,7 +365073,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -639,9 +656,7 @@ static struct ata_port_info piix_port_info[] = {
+@@ -639,9 +664,7 @@ static struct ata_port_info piix_port_info[] = {
  
  	[tolapai_sata_ahci] =
  	{
@@ -356298,7 +365084,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -650,9 +665,8 @@ static struct ata_port_info piix_port_info[] = {
+@@ -650,9 +673,8 @@ static struct ata_port_info piix_port_info[] = {
  
  	[ich8m_apple_sata_ahci] =
  	{
@@ -356310,7 +365096,7 @@
  		.pio_mask	= 0x1f,	/* pio0-4 */
  		.mwdma_mask	= 0x07, /* mwdma0-2 */
  		.udma_mask	= ATA_UDMA6,
-@@ -1001,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+@@ -1001,6 +1023,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  	do_pata_set_dmamode(ap, adev, 1);
  }
  
@@ -356367,7 +365153,7 @@
 +	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
 +}
 +
-+u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
++static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
 +{
 +	u32 val = 0;
 +	int i, mi;
@@ -356491,7 +365277,7 @@
  #ifdef CONFIG_PM
  static int piix_broken_suspend(void)
  {
-@@ -1034,6 +1222,13 @@ static int piix_broken_suspend(void)
+@@ -1034,6 +1230,13 @@ static int piix_broken_suspend(void)
  			},
  		},
  		{
@@ -356505,7 +365291,7 @@
  			.ident = "TECRA M7",
  			.matches = {
  				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-@@ -1048,6 +1243,13 @@ static int piix_broken_suspend(void)
+@@ -1048,6 +1251,13 @@ static int piix_broken_suspend(void)
  			},
  		},
  		{
@@ -356519,7 +365305,7 @@
  			.ident = "Satellite R25",
  			.matches = {
  				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-@@ -1253,10 +1455,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
+@@ -1253,10 +1463,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
  	return no_piix_dma;
  }
  
@@ -356532,7 +365318,7 @@
  	u16 pcs, new_pcs;
  
  	pci_read_config_word(pdev, ICH5_PCS, &pcs);
-@@ -1270,11 +1472,10 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev,
+@@ -1270,11 +1480,10 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev,
  	}
  }
  
@@ -356547,7 +365333,7 @@
  	const int *map;
  	int i, invalid_map = 0;
  	u8 map_value;
-@@ -1298,7 +1499,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+@@ -1298,7 +1507,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
  		case IDE:
  			WARN_ON((i & 1) || map[i + 1] != IDE);
  			pinfo[i / 2] = piix_port_info[ich_pata_100];
@@ -356555,7 +365341,7 @@
  			i++;
  			printk(" IDE IDE");
  			break;
-@@ -1316,7 +1516,33 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+@@ -1316,7 +1524,33 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
  		dev_printk(KERN_ERR, &pdev->dev,
  			   "invalid MAP value %u\n", map_value);
  
@@ -356590,7 +365376,7 @@
  }
  
  static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
-@@ -1375,8 +1601,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1375,8 +1609,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  	struct device *dev = &pdev->dev;
  	struct ata_port_info port_info[2];
  	const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
@@ -356602,7 +365388,7 @@
  
  	if (!printed_version++)
  		dev_printk(KERN_DEBUG, &pdev->dev,
-@@ -1386,17 +1614,31 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1386,17 +1622,31 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  	if (!in_module_init)
  		return -ENODEV;
  
@@ -356639,7 +365425,7 @@
  	if (port_flags & PIIX_FLAG_AHCI) {
  		u8 tmp;
  		pci_read_config_byte(pdev, PIIX_SCC, &tmp);
-@@ -1407,12 +1649,9 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1407,12 +1657,9 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  		}
  	}
  
@@ -356654,7 +365440,7 @@
  	}
  
  	/* apply IOCFG bit18 quirk */
-@@ -1431,12 +1670,14 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1431,12 +1678,14 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  		/* This writes into the master table but it does not
  		   really matter for this errata as we will apply it to
  		   all the PIIX devices on the board */
@@ -359579,18 +368365,82 @@
  }
  
 diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
-index 7842cc4..a32e3c4 100644
+index 7842cc4..7f87f10 100644
 --- a/drivers/ata/pata_bf54x.c
 +++ b/drivers/ata/pata_bf54x.c
-@@ -832,6 +832,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+@@ -299,7 +299,7 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+ 	*/
+ 	n6 = num_clocks_min(t6min, fsclk);
+ 	if (mode >= 0 && mode <= 4 && n6 >= 1) {
+-		pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
++		dev_dbg(adev->link->ap->dev, "set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ 		/* calculate the timing values for register transfers. */
+ 		while (mode > 0 && pio_fsclk[mode] > fsclk)
+ 			mode--;
+@@ -376,7 +376,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+ 
+ 	mode = adev->dma_mode - XFER_UDMA_0;
+ 	if (mode >= 0 && mode <= 5) {
+-		pr_debug("set udmamode: mode=%d\n", mode);
++		dev_dbg(adev->link->ap->dev, "set udmamode: mode=%d\n", mode);
+ 		/* the most restrictive timing value is t6 and tc,
+ 		 * the DIOW - data hold. If one SCLK pulse is longer
+ 		 * than this minimum value then register
+@@ -433,7 +433,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+ 
+ 	mode = adev->dma_mode - XFER_MW_DMA_0;
+ 	if (mode >= 0 && mode <= 2) {
+-		pr_debug("set mdmamode: mode=%d\n", mode);
++		dev_dbg(adev->link->ap->dev, "set mdmamode: mode=%d\n", mode);
+ 		/* the most restrictive timing value is tf, the DMACK to
+ 		 * read data released. If one SCLK pulse is longer than
+ 		 * this maximum value then the MDMA mode
+@@ -697,7 +697,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+ 			write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+ 			write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+ 			write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+-			pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
++			dev_dbg(ap->dev, "hob: feat 0x%X nsect 0x%X, lba 0x%X "
+ 				 "0x%X 0x%X\n",
+ 				tf->hob_feature,
+ 				tf->hob_nsect,
+@@ -711,7 +711,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+ 		write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+ 		write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+ 		write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+-		pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
++		dev_dbg(ap->dev, "feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ 			tf->feature,
+ 			tf->nsect,
+ 			tf->lbal,
+@@ -721,7 +721,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+ 
+ 	if (tf->flags & ATA_TFLAG_DEVICE) {
+ 		write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+-		pr_debug("device 0x%X\n", tf->device);
++		dev_dbg(ap->dev, "device 0x%X\n", tf->device);
+ 	}
+ 
+ 	ata_wait_idle(ap);
+@@ -782,7 +782,7 @@ static void bfin_exec_command(struct ata_port *ap,
+ 			      const struct ata_taskfile *tf)
+ {
+ 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+-	pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
++	dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+ 
+ 	write_atapi_register(base, ATA_REG_CMD, tf->command);
+ 	ata_pause(ap);
+@@ -832,14 +832,15 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
  {
  	unsigned short config = WDSIZE_16;
  	struct scatterlist *sg;
 +	unsigned int si;
  
- 	pr_debug("in atapi dma setup\n");
+-	pr_debug("in atapi dma setup\n");
++	dev_dbg(qc->ap->dev, "in atapi dma setup\n");
  	/* Program the ATA_CTRL register with dir */
-@@ -839,7 +840,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+ 	if (qc->tf.flags & ATA_TFLAG_WRITE) {
  		/* fill the ATAPI DMA controller */
  		set_dma_config(CH_ATAPI_TX, config);
  		set_dma_x_modify(CH_ATAPI_TX, 2);
@@ -359608,15 +368458,18 @@
  			set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
  			set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
  		}
-@@ -867,6 +868,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+@@ -867,8 +868,9 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
  	struct ata_port *ap = qc->ap;
  	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
  	struct scatterlist *sg;
 +	unsigned int si;
  
- 	pr_debug("in atapi dma start\n");
+-	pr_debug("in atapi dma start\n");
++	dev_dbg(qc->ap->dev, "in atapi dma start\n");
  	if (!(ap->udma_mask || ap->mwdma_mask))
-@@ -881,7 +883,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+ 		return;
+ 
+@@ -881,12 +883,12 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
  		 * data cache is enabled. Otherwise, this loop
  		 * is an empty loop and optimized out.
  		 */
@@ -359625,6 +368478,21 @@
  			flush_dcache_range(sg_dma_address(sg),
  				sg_dma_address(sg) + sg_dma_len(sg));
  		}
+ 		enable_dma(CH_ATAPI_TX);
+-		pr_debug("enable udma write\n");
++		dev_dbg(qc->ap->dev, "enable udma write\n");
+ 
+ 		/* Send ATA DMA write command */
+ 		bfin_exec_command(ap, &qc->tf);
+@@ -896,7 +898,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+ 			| XFER_DIR));
+ 	} else {
+ 		enable_dma(CH_ATAPI_RX);
+-		pr_debug("enable udma read\n");
++		dev_dbg(qc->ap->dev, "enable udma read\n");
+ 
+ 		/* Send ATA DMA read command */
+ 		bfin_exec_command(ap, &qc->tf);
 @@ -910,7 +912,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
  	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
  
@@ -359634,14 +368502,17 @@
  		ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
  	}
  
-@@ -932,6 +934,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+@@ -932,8 +934,9 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct scatterlist *sg;
 +	unsigned int si;
  
- 	pr_debug("in atapi dma stop\n");
+-	pr_debug("in atapi dma stop\n");
++	dev_dbg(qc->ap->dev, "in atapi dma stop\n");
  	if (!(ap->udma_mask || ap->mwdma_mask))
+ 		return;
+ 
 @@ -950,7 +953,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
  			 * data cache is enabled. Otherwise, this loop
  			 * is an empty loop and optimized out.
@@ -359651,6 +368522,29 @@
  				invalidate_dcache_range(
  					sg_dma_address(sg),
  					sg_dma_address(sg)
+@@ -1144,15 +1147,15 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
+ 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ 	unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+ 
+-	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
++	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON))
+ 		host_stat |= ATA_DMA_ACTIVE;
+-	}
+-	if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
++	if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT|
++		ATAPI_DEV_INT))
+ 		host_stat |= ATA_DMA_INTR;
+-	}
+-	if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+-		host_stat |= ATA_DMA_ERR;
+-	}
++	if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT))
++		host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;
++
++	dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
+ 
+ 	return host_stat;
+ }
 @@ -1167,34 +1170,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
   *	Note: Original code is ata_data_xfer().
   */
@@ -359701,8 +368595,65 @@
  }
  
  /**
+@@ -1208,8 +1213,7 @@ static void bfin_irq_clear(struct ata_port *ap)
+ {
+ 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ 
+-	pr_debug("in atapi irq clear\n");
+-
++	dev_dbg(ap->dev, "in atapi irq clear\n");
+ 	ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+ 		| MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ 		| MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+@@ -1227,7 +1231,7 @@ static unsigned char bfin_irq_on(struct ata_port *ap)
+ 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ 	u8 tmp;
+ 
+-	pr_debug("in atapi irq on\n");
++	dev_dbg(ap->dev, "in atapi irq on\n");
+ 	ap->ctl &= ~ATA_NIEN;
+ 	ap->last_ctl = ap->ctl;
+ 
+@@ -1250,7 +1254,7 @@ static void bfin_bmdma_freeze(struct ata_port *ap)
+ {
+ 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ 
+-	pr_debug("in atapi dma freeze\n");
++	dev_dbg(ap->dev, "in atapi dma freeze\n");
+ 	ap->ctl |= ATA_NIEN;
+ 	ap->last_ctl = ap->ctl;
+ 
+@@ -1323,7 +1327,7 @@ static void bfin_error_handler(struct ata_port *ap)
+ 
+ static void bfin_port_stop(struct ata_port *ap)
+ {
+-	pr_debug("in atapi port stop\n");
++	dev_dbg(ap->dev, "in atapi port stop\n");
+ 	if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+ 		free_dma(CH_ATAPI_RX);
+ 		free_dma(CH_ATAPI_TX);
+@@ -1332,7 +1336,7 @@ static void bfin_port_stop(struct ata_port *ap)
+ 
+ static int bfin_port_start(struct ata_port *ap)
+ {
+-	pr_debug("in atapi port start\n");
++	dev_dbg(ap->dev, "in atapi port start\n");
+ 	if (!(ap->udma_mask || ap->mwdma_mask))
+ 		return 0;
+ 
+@@ -1368,10 +1372,6 @@ static struct scsi_host_template bfin_sht = {
+ 	.slave_configure	= ata_scsi_slave_config,
+ 	.slave_destroy		= ata_scsi_slave_destroy,
+ 	.bios_param		= ata_std_bios_param,
+-#ifdef CONFIG_PM
+-	.resume			= ata_scsi_device_resume,
+-	.suspend		= ata_scsi_device_suspend,
+-#endif
+ };
+ 
+ static const struct ata_port_operations bfin_pata_ops = {
 diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
-index 33f7f08..d4590f5 100644
+index 33f7f08..7ed279b 100644
 --- a/drivers/ata/pata_cs5520.c
 +++ b/drivers/ata/pata_cs5520.c
 @@ -198,7 +198,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
@@ -359714,6 +368665,15 @@
  	struct ata_host *host;
  	struct ata_ioports *ioaddr;
  	int i, rc;
+@@ -229,7 +229,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
+ 		return -ENOMEM;
+ 
+ 	/* Perform set up for DMA */
+-	if (pci_enable_device_bars(pdev, 1<<2)) {
++	if (pci_enable_device_io(pdev)) {
+ 		printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
+ 		return -ENODEV;
+ 	}
 diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
 index c79f066..68eb349 100644
 --- a/drivers/ata/pata_hpt37x.c
@@ -362049,6 +371009,71 @@
  	int devbits = (2 * ap->port_no + adev->devno) * 4;
  	u16 csb5_pio;
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
+index 1388cef..81ef207 100644
+--- a/drivers/ata/pata_sl82c105.c
++++ b/drivers/ata/pata_sl82c105.c
+@@ -26,7 +26,7 @@
+ #include <linux/libata.h>
+ 
+ #define DRV_NAME "pata_sl82c105"
+-#define DRV_VERSION "0.3.2"
++#define DRV_VERSION "0.3.3"
+ 
+ enum {
+ 	/*
+@@ -206,6 +206,34 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
+ 	sl82c105_set_piomode(ap, qc->dev);
+ }
+ 
++/**
++ *	sl82c105_qc_defer	-	implement serialization
++ *	@qc: command
++ *
++ *	We must issue one command per host not per channel because
++ *	of the reset bug.
++ *
++ *	Q: is the scsi host lock sufficient ?
++ */
++
++static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
++{
++	struct ata_host *host = qc->ap->host;
++	struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
++	int rc;
++
++	/* First apply the usual rules */	
++	rc = ata_std_qc_defer(qc);
++	if (rc != 0)
++		return rc;
++
++	/* Now apply serialization rules. Only allow a command if the
++	   other channel state machine is idle */
++	if (alt && alt->qc_active)
++		return	ATA_DEFER_PORT;
++	return 0;
++}
++
+ static struct scsi_host_template sl82c105_sht = {
+ 	.module			= THIS_MODULE,
+ 	.name			= DRV_NAME,
+@@ -245,6 +273,7 @@ static struct ata_port_operations sl82c105_port_ops = {
+ 	.bmdma_stop	= sl82c105_bmdma_stop,
+ 	.bmdma_status 	= ata_bmdma_status,
+ 
++	.qc_defer	= sl82c105_qc_defer,
+ 	.qc_prep 	= ata_qc_prep,
+ 	.qc_issue	= ata_qc_issue_prot,
+ 
+@@ -312,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
+ 	};
+ 	/* for now use only the first port */
+ 	const struct ata_port_info *ppi[] = { &info_early,
+-					       &ata_dummy_port_info };
++					       NULL };
+ 	u32 val;
+ 	int rev;
+ 
 diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
 index 453d72b..39627ab 100644
 --- a/drivers/ata/pata_via.c
@@ -362189,26 +371214,1040 @@
  	 * manages to report the wrong ireason and ignoring ireason
  	 * results in machine lock up.  Tell libata to always prefer
 diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
-index 37b850a..7e72463 100644
+index 37b850a..3c1b5c9 100644
 --- a/drivers/ata/sata_mv.c
 +++ b/drivers/ata/sata_mv.c
-@@ -1136,9 +1136,10 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
+@@ -29,7 +29,13 @@
+   I distinctly remember a couple workarounds (one related to PCI-X)
+   are still needed.
+ 
+-  4) Add NCQ support (easy to intermediate, once new-EH support appears)
++  2) Improve/fix IRQ and error handling sequences.
++
++  3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
++
++  4) Think about TCQ support here, and for libata in general
++  with controllers that suppport it via host-queuing hardware
++  (a software-only implementation could be a nightmare).
+ 
+   5) Investigate problems with PCI Message Signalled Interrupts (MSI).
+ 
+@@ -53,8 +59,6 @@
+   Target mode, for those without docs, is the ability to directly
+   connect two SATA controllers.
+ 
+-  13) Verify that 7042 is fully supported.  I only have a 6042.
+-
+ */
+ 
+ 
+@@ -73,7 +77,7 @@
+ #include <linux/libata.h>
+ 
+ #define DRV_NAME	"sata_mv"
+-#define DRV_VERSION	"1.01"
++#define DRV_VERSION	"1.20"
+ 
+ enum {
+ 	/* BAR's are enumerated in terms of pci_resource_start() terms */
+@@ -107,14 +111,12 @@ enum {
+ 
+ 	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
+ 	 * CRPB needs alignment on a 256B boundary. Size == 256B
+-	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
+ 	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
+ 	 */
+ 	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
+ 	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
+-	MV_MAX_SG_CT		= 176,
++	MV_MAX_SG_CT		= 256,
+ 	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
+-	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
+ 
+ 	MV_PORTS_PER_HC		= 4,
+ 	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+@@ -125,6 +127,9 @@ enum {
+ 	/* Host Flags */
+ 	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
+ 	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
++	/* SoC integrated controllers, no PCI interface */
++	MV_FLAG_SOC = (1 << 28),
++
+ 	MV_COMMON_FLAGS		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ 				  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ 				  ATA_FLAG_PIO_POLLING,
+@@ -170,7 +175,7 @@ enum {
+ 
+ 	PCIE_IRQ_CAUSE_OFS	= 0x1900,
+ 	PCIE_IRQ_MASK_OFS	= 0x1910,
+-	PCIE_UNMASK_ALL_IRQS	= 0x70a,	/* assorted bits */
++	PCIE_UNMASK_ALL_IRQS	= 0x40a,	/* assorted bits */
+ 
+ 	HC_MAIN_IRQ_CAUSE_OFS	= 0x1d60,
+ 	HC_MAIN_IRQ_MASK_OFS	= 0x1d64,
+@@ -210,6 +215,7 @@ enum {
+ 	/* SATA registers */
+ 	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
+ 	SATA_ACTIVE_OFS		= 0x350,
++	SATA_FIS_IRQ_CAUSE_OFS	= 0x364,
+ 	PHY_MODE3		= 0x310,
+ 	PHY_MODE4		= 0x314,
+ 	PHY_MODE2		= 0x330,
+@@ -222,11 +228,11 @@ enum {
+ 
+ 	/* Port registers */
+ 	EDMA_CFG_OFS		= 0,
+-	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
+-	EDMA_CFG_NCQ		= (1 << 5),
+-	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
+-	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
+-	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
++	EDMA_CFG_Q_DEPTH	= 0x1f,		/* max device queue depth */
++	EDMA_CFG_NCQ		= (1 << 5),	/* for R/W FPDMA queued */
++	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),	/* continue on error */
++	EDMA_CFG_RD_BRST_EXT	= (1 << 11),	/* read burst 512B */
++	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),	/* write buffer 512B */
+ 
+ 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
+ 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
+@@ -244,14 +250,33 @@ enum {
+ 	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
+ 	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
+ 	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
++
+ 	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
+-	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
++	EDMA_ERR_LNK_CTRL_RX_0	= (1 << 13),	/* transient: CRC err */
++	EDMA_ERR_LNK_CTRL_RX_1	= (1 << 14),	/* transient: FIFO err */
++	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),	/* fatal: caught SYNC */
++	EDMA_ERR_LNK_CTRL_RX_3	= (1 << 16),	/* transient: FIS rx err */
++
+ 	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
++
+ 	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
++	EDMA_ERR_LNK_CTRL_TX_0	= (1 << 21),	/* transient: CRC err */
++	EDMA_ERR_LNK_CTRL_TX_1	= (1 << 22),	/* transient: FIFO err */
++	EDMA_ERR_LNK_CTRL_TX_2	= (1 << 23),	/* transient: caught SYNC */
++	EDMA_ERR_LNK_CTRL_TX_3	= (1 << 24),	/* transient: caught DMAT */
++	EDMA_ERR_LNK_CTRL_TX_4	= (1 << 25),	/* transient: FIS collision */
++
+ 	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
++
+ 	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
+ 	EDMA_ERR_OVERRUN_5	= (1 << 5),
+ 	EDMA_ERR_UNDERRUN_5	= (1 << 6),
++
++	EDMA_ERR_IRQ_TRANSIENT  = EDMA_ERR_LNK_CTRL_RX_0 |
++				  EDMA_ERR_LNK_CTRL_RX_1 |
++				  EDMA_ERR_LNK_CTRL_RX_3 |
++				  EDMA_ERR_LNK_CTRL_TX,
++
+ 	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
+ 				  EDMA_ERR_PRD_PAR |
+ 				  EDMA_ERR_DEV_DCON |
+@@ -311,12 +336,14 @@ enum {
+ 
+ 	/* Port private flags (pp_flags) */
+ 	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
++	MV_PP_FLAG_NCQ_EN	= (1 << 1),	/* is EDMA set up for NCQ? */
+ 	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
+ };
+ 
+ #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
+ #define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
+ #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
++#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
+ 
+ enum {
+ 	/* DMA boundary 0xffff is required by the s/g splitting
+@@ -379,8 +406,8 @@ struct mv_port_priv {
+ 	dma_addr_t		crqb_dma;
+ 	struct mv_crpb		*crpb;
+ 	dma_addr_t		crpb_dma;
+-	struct mv_sg		*sg_tbl;
+-	dma_addr_t		sg_tbl_dma;
++	struct mv_sg		*sg_tbl[MV_MAX_Q_DEPTH];
++	dma_addr_t		sg_tbl_dma[MV_MAX_Q_DEPTH];
+ 
+ 	unsigned int		req_idx;
+ 	unsigned int		resp_idx;
+@@ -400,6 +427,14 @@ struct mv_host_priv {
+ 	u32			irq_cause_ofs;
+ 	u32			irq_mask_ofs;
+ 	u32			unmask_all_irqs;
++	/*
++	 * These consistent DMA memory pools give us guaranteed
++	 * alignment for hardware-accessed data structures,
++	 * and less memory waste in accomplishing the alignment.
++	 */
++	struct dma_pool		*crqb_pool;
++	struct dma_pool		*crpb_pool;
++	struct dma_pool		*sg_tbl_pool;
+ };
+ 
+ struct mv_hw_ops {
+@@ -411,7 +446,7 @@ struct mv_hw_ops {
+ 	int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			unsigned int n_hc);
+ 	void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
+-	void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
++	void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
+ };
+ 
+ static void mv_irq_clear(struct ata_port *ap);
+@@ -425,10 +460,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc);
+ static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
+ static void mv_error_handler(struct ata_port *ap);
+-static void mv_post_int_cmd(struct ata_queued_cmd *qc);
+ static void mv_eh_freeze(struct ata_port *ap);
+ static void mv_eh_thaw(struct ata_port *ap);
+-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
++static void mv6_dev_config(struct ata_device *dev);
+ 
+ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			   unsigned int port);
+@@ -438,7 +472,7 @@ static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
+ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			unsigned int n_hc);
+ static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
++static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio);
+ 
+ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			   unsigned int port);
+@@ -448,10 +482,17 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
+ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			unsigned int n_hc);
+ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
++static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
+ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 			     unsigned int port_no);
++static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
++			void __iomem *port_mmio, int want_ncq);
++static int __mv_stop_dma(struct ata_port *ap);
+ 
++/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
++ * because we have to allow room for worst case splitting of
++ * PRDs for 64K boundaries in mv_fill_sg().
++ */
+ static struct scsi_host_template mv5_sht = {
+ 	.module			= THIS_MODULE,
+ 	.name			= DRV_NAME,
+@@ -475,7 +516,8 @@ static struct scsi_host_template mv6_sht = {
+ 	.name			= DRV_NAME,
+ 	.ioctl			= ata_scsi_ioctl,
+ 	.queuecommand		= ata_scsi_queuecmd,
+-	.can_queue		= ATA_DEF_QUEUE,
++	.change_queue_depth	= ata_scsi_change_queue_depth,
++	.can_queue		= MV_MAX_Q_DEPTH - 1,
+ 	.this_id		= ATA_SHT_THIS_ID,
+ 	.sg_tablesize		= MV_MAX_SG_CT / 2,
+ 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+@@ -505,7 +547,6 @@ static const struct ata_port_operations mv5_ops = {
+ 	.irq_on			= ata_irq_on,
+ 
+ 	.error_handler		= mv_error_handler,
+-	.post_internal_cmd	= mv_post_int_cmd,
+ 	.freeze			= mv_eh_freeze,
+ 	.thaw			= mv_eh_thaw,
+ 
+@@ -517,6 +558,7 @@ static const struct ata_port_operations mv5_ops = {
+ };
+ 
+ static const struct ata_port_operations mv6_ops = {
++	.dev_config             = mv6_dev_config,
+ 	.tf_load		= ata_tf_load,
+ 	.tf_read		= ata_tf_read,
+ 	.check_status		= ata_check_status,
+@@ -533,9 +575,9 @@ static const struct ata_port_operations mv6_ops = {
+ 	.irq_on			= ata_irq_on,
+ 
+ 	.error_handler		= mv_error_handler,
+-	.post_internal_cmd	= mv_post_int_cmd,
+ 	.freeze			= mv_eh_freeze,
+ 	.thaw			= mv_eh_thaw,
++	.qc_defer		= ata_std_qc_defer,
+ 
+ 	.scr_read		= mv_scr_read,
+ 	.scr_write		= mv_scr_write,
+@@ -561,9 +603,9 @@ static const struct ata_port_operations mv_iie_ops = {
+ 	.irq_on			= ata_irq_on,
+ 
+ 	.error_handler		= mv_error_handler,
+-	.post_internal_cmd	= mv_post_int_cmd,
+ 	.freeze			= mv_eh_freeze,
+ 	.thaw			= mv_eh_thaw,
++	.qc_defer		= ata_std_qc_defer,
+ 
+ 	.scr_read		= mv_scr_read,
+ 	.scr_write		= mv_scr_write,
+@@ -592,26 +634,29 @@ static const struct ata_port_info mv_port_info[] = {
+ 		.port_ops	= &mv5_ops,
+ 	},
+ 	{  /* chip_604x */
+-		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
++		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
++				  ATA_FLAG_NCQ,
+ 		.pio_mask	= 0x1f,	/* pio0-4 */
+ 		.udma_mask	= ATA_UDMA6,
+ 		.port_ops	= &mv6_ops,
+ 	},
+ 	{  /* chip_608x */
+ 		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+-				  MV_FLAG_DUAL_HC,
++				  ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
+ 		.pio_mask	= 0x1f,	/* pio0-4 */
+ 		.udma_mask	= ATA_UDMA6,
+ 		.port_ops	= &mv6_ops,
+ 	},
+ 	{  /* chip_6042 */
+-		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
++		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
++				  ATA_FLAG_NCQ,
+ 		.pio_mask	= 0x1f,	/* pio0-4 */
+ 		.udma_mask	= ATA_UDMA6,
+ 		.port_ops	= &mv_iie_ops,
+ 	},
+ 	{  /* chip_7042 */
+-		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS,
++		.flags		= MV_COMMON_FLAGS | MV_6XXX_FLAGS |
++				  ATA_FLAG_NCQ,
+ 		.pio_mask	= 0x1f,	/* pio0-4 */
+ 		.udma_mask	= ATA_UDMA6,
+ 		.port_ops	= &mv_iie_ops,
+@@ -648,13 +693,6 @@ static const struct pci_device_id mv_pci_tbl[] = {
+ 	{ }			/* terminate list */
+ };
+ 
+-static struct pci_driver mv_pci_driver = {
+-	.name			= DRV_NAME,
+-	.id_table		= mv_pci_tbl,
+-	.probe			= mv_init_one,
+-	.remove			= ata_pci_remove_one,
+-};
+-
+ static const struct mv_hw_ops mv5xxx_ops = {
+ 	.phy_errata		= mv5_phy_errata,
+ 	.enable_leds		= mv5_enable_leds,
+@@ -674,45 +712,6 @@ static const struct mv_hw_ops mv6xxx_ops = {
+ };
+ 
+ /*
+- * module options
+- */
+-static int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
+-
+-
+-/* move to PCI layer or libata core? */
+-static int pci_go_64(struct pci_dev *pdev)
+-{
+-	int rc;
+-
+-	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+-		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+-		if (rc) {
+-			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+-			if (rc) {
+-				dev_printk(KERN_ERR, &pdev->dev,
+-					   "64-bit DMA enable failed\n");
+-				return rc;
+-			}
+-		}
+-	} else {
+-		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+-		if (rc) {
+-			dev_printk(KERN_ERR, &pdev->dev,
+-				   "32-bit DMA enable failed\n");
+-			return rc;
+-		}
+-		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+-		if (rc) {
+-			dev_printk(KERN_ERR, &pdev->dev,
+-				   "32-bit consistent DMA enable failed\n");
+-			return rc;
+-		}
+-	}
+-
+-	return rc;
+-}
+-
+-/*
+  * Functions
+  */
+ 
+@@ -815,19 +814,46 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
+  *      LOCKING:
+  *      Inherited from caller.
+  */
+-static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
+-			 struct mv_port_priv *pp)
++static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
++			 struct mv_port_priv *pp, u8 protocol)
+ {
++	int want_ncq = (protocol == ATA_PROT_NCQ);
++
++	if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
++		int using_ncq = ((pp->pp_flags & MV_PP_FLAG_NCQ_EN) != 0);
++		if (want_ncq != using_ncq)
++			__mv_stop_dma(ap);
++	}
+ 	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
++		struct mv_host_priv *hpriv = ap->host->private_data;
++		int hard_port = mv_hardport_from_port(ap->port_no);
++		void __iomem *hc_mmio = mv_hc_base_from_port(
++				ap->host->iomap[MV_PRIMARY_BAR], hard_port);
++		u32 hc_irq_cause, ipending;
++
+ 		/* clear EDMA event indicators, if any */
+-		writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
++		writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++
++		/* clear EDMA interrupt indicator, if any */
++		hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
++		ipending = (DEV_IRQ << hard_port) |
++				(CRPB_DMA_DONE << hard_port);
++		if (hc_irq_cause & ipending) {
++			writelfl(hc_irq_cause & ~ipending,
++				 hc_mmio + HC_IRQ_CAUSE_OFS);
++		}
++
++		mv_edma_cfg(pp, hpriv, port_mmio, want_ncq);
++
++		/* clear FIS IRQ Cause */
++		writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ 
+-		mv_set_edma_ptrs(base, hpriv, pp);
++		mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ 
+-		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
++		writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
+ 		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
+ 	}
+-	WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
++	WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+ }
+ 
+ /**
+@@ -1003,38 +1029,76 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+ 		return -EINVAL;
+ }
+ 
+-static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
+-			void __iomem *port_mmio)
++static void mv6_dev_config(struct ata_device *adev)
+ {
+-	u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
++	/*
++	 * We don't have hob_nsect when doing NCQ commands on Gen-II.
++	 * See mv_qc_prep() for more info.
++	 */
++	if (adev->flags & ATA_DFLAG_NCQ)
++		if (adev->max_sectors > ATA_MAX_SECTORS)
++			adev->max_sectors = ATA_MAX_SECTORS;
++}
++
++static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
++			void __iomem *port_mmio, int want_ncq)
++{
++	u32 cfg;
+ 
+ 	/* set up non-NCQ EDMA configuration */
+-	cfg &= ~(1 << 9);	/* disable eQue */
++	cfg = EDMA_CFG_Q_DEPTH;		/* always 0x1f for *all* chips */
+ 
+-	if (IS_GEN_I(hpriv)) {
+-		cfg &= ~0x1f;		/* clear queue depth */
++	if (IS_GEN_I(hpriv))
+ 		cfg |= (1 << 8);	/* enab config burst size mask */
+-	}
+ 
+-	else if (IS_GEN_II(hpriv)) {
+-		cfg &= ~0x1f;		/* clear queue depth */
++	else if (IS_GEN_II(hpriv))
+ 		cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+-		cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
+-	}
+ 
+ 	else if (IS_GEN_IIE(hpriv)) {
+ 		cfg |= (1 << 23);	/* do not mask PM field in rx'd FIS */
+ 		cfg |= (1 << 22);	/* enab 4-entry host queue cache */
+-		cfg &= ~(1 << 19);	/* dis 128-entry queue (for now?) */
+ 		cfg |= (1 << 18);	/* enab early completion */
+ 		cfg |= (1 << 17);	/* enab cut-through (dis stor&forwrd) */
+-		cfg &= ~(1 << 16);	/* dis FIS-based switching (for now) */
+-		cfg &= ~(EDMA_CFG_NCQ);	/* clear NCQ */
+ 	}
+ 
++	if (want_ncq) {
++		cfg |= EDMA_CFG_NCQ;
++		pp->pp_flags |=  MV_PP_FLAG_NCQ_EN;
++	} else
++		pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
++
+ 	writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+ }
+ 
++static void mv_port_free_dma_mem(struct ata_port *ap)
++{
++	struct mv_host_priv *hpriv = ap->host->private_data;
++	struct mv_port_priv *pp = ap->private_data;
++	int tag;
++
++	if (pp->crqb) {
++		dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma);
++		pp->crqb = NULL;
++	}
++	if (pp->crpb) {
++		dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma);
++		pp->crpb = NULL;
++	}
++	/*
++	 * For GEN_I, there's no NCQ, so we have only a single sg_tbl.
++	 * For later hardware, we have one unique sg_tbl per NCQ tag.
++	 */
++	for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
++		if (pp->sg_tbl[tag]) {
++			if (tag == 0 || !IS_GEN_I(hpriv))
++				dma_pool_free(hpriv->sg_tbl_pool,
++					      pp->sg_tbl[tag],
++					      pp->sg_tbl_dma[tag]);
++			pp->sg_tbl[tag] = NULL;
++		}
++	}
++}
++
+ /**
+  *      mv_port_start - Port specific init/start routine.
+  *      @ap: ATA channel to manipulate
+@@ -1051,51 +1115,47 @@ static int mv_port_start(struct ata_port *ap)
+ 	struct mv_host_priv *hpriv = ap->host->private_data;
+ 	struct mv_port_priv *pp;
+ 	void __iomem *port_mmio = mv_ap_base(ap);
+-	void *mem;
+-	dma_addr_t mem_dma;
+ 	unsigned long flags;
+-	int rc;
++	int tag, rc;
+ 
+ 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ 	if (!pp)
+ 		return -ENOMEM;
+-
+-	mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
+-				  GFP_KERNEL);
+-	if (!mem)
+-		return -ENOMEM;
+-	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
++	ap->private_data = pp;
+ 
+ 	rc = ata_pad_alloc(ap, dev);
+ 	if (rc)
+ 		return rc;
+ 
+-	/* First item in chunk of DMA memory:
+-	 * 32-slot command request table (CRQB), 32 bytes each in size
+-	 */
+-	pp->crqb = mem;
+-	pp->crqb_dma = mem_dma;
+-	mem += MV_CRQB_Q_SZ;
+-	mem_dma += MV_CRQB_Q_SZ;
++	pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
++	if (!pp->crqb)
++		return -ENOMEM;
++	memset(pp->crqb, 0, MV_CRQB_Q_SZ);
+ 
+-	/* Second item:
+-	 * 32-slot command response table (CRPB), 8 bytes each in size
+-	 */
+-	pp->crpb = mem;
+-	pp->crpb_dma = mem_dma;
+-	mem += MV_CRPB_Q_SZ;
+-	mem_dma += MV_CRPB_Q_SZ;
++	pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma);
++	if (!pp->crpb)
++		goto out_port_free_dma_mem;
++	memset(pp->crpb, 0, MV_CRPB_Q_SZ);
+ 
+-	/* Third item:
+-	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
++	/*
++	 * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
++	 * For later hardware, we need one unique sg_tbl per NCQ tag.
+ 	 */
+-	pp->sg_tbl = mem;
+-	pp->sg_tbl_dma = mem_dma;
++	for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
++		if (tag == 0 || !IS_GEN_I(hpriv)) {
++			pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool,
++					      GFP_KERNEL, &pp->sg_tbl_dma[tag]);
++			if (!pp->sg_tbl[tag])
++				goto out_port_free_dma_mem;
++		} else {
++			pp->sg_tbl[tag]     = pp->sg_tbl[0];
++			pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
++		}
++	}
+ 
+ 	spin_lock_irqsave(&ap->host->lock, flags);
+ 
+-	mv_edma_cfg(ap, hpriv, port_mmio);
+-
++	mv_edma_cfg(pp, hpriv, port_mmio, 0);
+ 	mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ 
+ 	spin_unlock_irqrestore(&ap->host->lock, flags);
+@@ -1104,8 +1164,11 @@ static int mv_port_start(struct ata_port *ap)
+ 	 * we'll be unable to send non-data, PIO, etc due to restricted access
+ 	 * to shadow regs.
+ 	 */
+-	ap->private_data = pp;
+ 	return 0;
++
++out_port_free_dma_mem:
++	mv_port_free_dma_mem(ap);
++	return -ENOMEM;
+ }
+ 
+ /**
+@@ -1120,6 +1183,7 @@ static int mv_port_start(struct ata_port *ap)
+ static void mv_port_stop(struct ata_port *ap)
+ {
+ 	mv_stop_dma(ap);
++	mv_port_free_dma_mem(ap);
+ }
+ 
+ /**
+@@ -1136,9 +1200,10 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
  	struct mv_port_priv *pp = qc->ap->private_data;
  	struct scatterlist *sg;
  	struct mv_sg *mv_sg, *last_sg = NULL;
 +	unsigned int si;
  
- 	mv_sg = pp->sg_tbl;
+-	mv_sg = pp->sg_tbl;
 -	ata_for_each_sg(sg, qc) {
++	mv_sg = pp->sg_tbl[qc->tag];
 +	for_each_sg(qc->sg, sg, qc->n_elem, si) {
  		dma_addr_t addr = sg_dma_address(sg);
  		u32 sg_len = sg_dma_len(sg);
  
+@@ -1193,7 +1258,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
+ 	u16 flags = 0;
+ 	unsigned in_index;
+ 
+-	if (qc->tf.protocol != ATA_PROT_DMA)
++	if ((qc->tf.protocol != ATA_PROT_DMA) &&
++	    (qc->tf.protocol != ATA_PROT_NCQ))
+ 		return;
+ 
+ 	/* Fill in command request block
+@@ -1202,15 +1268,14 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
+ 		flags |= CRQB_FLAG_READ;
+ 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+ 	flags |= qc->tag << CRQB_TAG_SHIFT;
+-	flags |= qc->tag << CRQB_IOID_SHIFT;	/* 50xx appears to ignore this*/
+ 
+ 	/* get current queue index from software */
+ 	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ 
+ 	pp->crqb[in_index].sg_addr =
+-		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
++		cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
+ 	pp->crqb[in_index].sg_addr_hi =
+-		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
++		cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
+ 	pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
+ 
+ 	cw = &pp->crqb[in_index].ata_cmd[0];
+@@ -1230,13 +1295,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
+ 	case ATA_CMD_WRITE_FUA_EXT:
+ 		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
+ 		break;
+-#ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
+ 	case ATA_CMD_FPDMA_READ:
+ 	case ATA_CMD_FPDMA_WRITE:
+ 		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
+ 		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
+ 		break;
+-#endif				/* FIXME: remove this line when NCQ added */
+ 	default:
+ 		/* The only other commands EDMA supports in non-queued and
+ 		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
+@@ -1285,7 +1348,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+ 	unsigned in_index;
+ 	u32 flags = 0;
+ 
+-	if (qc->tf.protocol != ATA_PROT_DMA)
++	if ((qc->tf.protocol != ATA_PROT_DMA) &&
++	    (qc->tf.protocol != ATA_PROT_NCQ))
+ 		return;
+ 
+ 	/* Fill in Gen IIE command request block
+@@ -1295,15 +1359,14 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+ 
+ 	WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+ 	flags |= qc->tag << CRQB_TAG_SHIFT;
+-	flags |= qc->tag << CRQB_IOID_SHIFT;	/* "I/O Id" is -really-
+-						   what we use as our tag */
++	flags |= qc->tag << CRQB_HOSTQ_SHIFT;
+ 
+ 	/* get current queue index from software */
+ 	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ 
+ 	crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
+-	crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+-	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
++	crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
++	crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
+ 	crqb->flags = cpu_to_le32(flags);
+ 
+ 	tf = &qc->tf;
+@@ -1350,10 +1413,10 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
+ 	struct ata_port *ap = qc->ap;
+ 	void __iomem *port_mmio = mv_ap_base(ap);
+ 	struct mv_port_priv *pp = ap->private_data;
+-	struct mv_host_priv *hpriv = ap->host->private_data;
+ 	u32 in_index;
+ 
+-	if (qc->tf.protocol != ATA_PROT_DMA) {
++	if ((qc->tf.protocol != ATA_PROT_DMA) &&
++	    (qc->tf.protocol != ATA_PROT_NCQ)) {
+ 		/* We're about to send a non-EDMA capable command to the
+ 		 * port.  Turn off EDMA so there won't be problems accessing
+ 		 * shadow block, etc registers.
+@@ -1362,13 +1425,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
+ 		return ata_qc_issue_prot(qc);
+ 	}
+ 
+-	mv_start_dma(port_mmio, hpriv, pp);
+-
+-	in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+-
+-	/* until we do queuing, the queue should be empty at this point */
+-	WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+-		>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
++	mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
+ 
+ 	pp->req_idx++;
+ 
+@@ -1436,6 +1493,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+ 		ata_ehi_hotplugged(ehi);
+ 		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
+ 			"dev disconnect" : "dev connect");
++		action |= ATA_EH_HARDRESET;
+ 	}
+ 
+ 	if (IS_GEN_I(hpriv)) {
+@@ -1464,7 +1522,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+ 	}
+ 
+ 	/* Clear EDMA now that SERR cleanup done */
+-	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
++	writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ 
+ 	if (!err_mask) {
+ 		err_mask = AC_ERR_OTHER;
+@@ -1537,23 +1595,17 @@ static void mv_intr_edma(struct ata_port *ap)
+ 		 * support for queueing.  this works transparently for
+ 		 * queued and non-queued modes.
+ 		 */
+-		else if (IS_GEN_II(hpriv))
+-			tag = (le16_to_cpu(pp->crpb[out_index].id)
+-				>> CRPB_IOID_SHIFT_6) & 0x3f;
+-
+-		else /* IS_GEN_IIE */
+-			tag = (le16_to_cpu(pp->crpb[out_index].id)
+-				>> CRPB_IOID_SHIFT_7) & 0x3f;
++		else
++			tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
+ 
+ 		qc = ata_qc_from_tag(ap, tag);
+ 
+-		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
+-		 * bits (WARNING: might not necessarily be associated
+-		 * with this command), which -should- be clear
+-		 * if all is well
++		/* For non-NCQ mode, the lower 8 bits of status
++		 * are from EDMA_ERR_IRQ_CAUSE_OFS,
++		 * which should be zero if all went well.
+ 		 */
+ 		status = le16_to_cpu(pp->crpb[out_index].flags);
+-		if (unlikely(status & 0xff)) {
++		if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
+ 			mv_err_intr(ap, qc);
+ 			return;
+ 		}
+@@ -1714,20 +1766,21 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
+ 	struct ata_host *host = dev_instance;
+ 	unsigned int hc, handled = 0, n_hcs;
+ 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+-	u32 irq_stat;
++	u32 irq_stat, irq_mask;
+ 
++	spin_lock(&host->lock);
+ 	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
++	irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+ 
+ 	/* check the cases where we either have nothing pending or have read
+ 	 * a bogus register value which can indicate HW removal or PCI fault
+ 	 */
+-	if (!irq_stat || (0xffffffffU == irq_stat))
+-		return IRQ_NONE;
++	if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
++		goto out_unlock;
+ 
+ 	n_hcs = mv_get_hc_count(host->ports[0]->flags);
+-	spin_lock(&host->lock);
+ 
+-	if (unlikely(irq_stat & PCI_ERR)) {
++	if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
+ 		mv_pci_error(host, mmio);
+ 		handled = 1;
+ 		goto out_unlock;	/* skip all other HC irq handling */
+@@ -1798,8 +1851,9 @@ static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+ 		return -EINVAL;
+ }
+ 
+-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
++static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
+ {
++	struct pci_dev *pdev = to_pci_dev(host->dev);
+ 	int early_5080;
+ 
+ 	early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
+@@ -1810,7 +1864,7 @@ static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
+ 		writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
+ 	}
+ 
+-	mv_reset_pci_bus(pdev, mmio);
++	mv_reset_pci_bus(host, mmio);
+ }
+ 
+ static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
+@@ -1934,9 +1988,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ 
+ #undef ZERO
+ #define ZERO(reg) writel(0, mmio + (reg))
+-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
++static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
+ {
+-	struct ata_host     *host = dev_get_drvdata(&pdev->dev);
+ 	struct mv_host_priv *hpriv = host->private_data;
+ 	u32 tmp;
+ 
+@@ -2328,11 +2381,6 @@ static void mv_error_handler(struct ata_port *ap)
+ 		  mv_hardreset, mv_postreset);
+ }
+ 
+-static void mv_post_int_cmd(struct ata_queued_cmd *qc)
+-{
+-	mv_stop_dma(qc->ap);
+-}
+-
+ static void mv_eh_freeze(struct ata_port *ap)
+ {
+ 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+@@ -2426,8 +2474,8 @@ static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
+ 	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
+ 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ 
+-	/* unmask all EDMA error interrupts */
+-	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
++	/* unmask all non-transient EDMA error interrupts */
++	writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+ 
+ 	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
+ 		readl(port_mmio + EDMA_CFG_OFS),
+@@ -2585,7 +2633,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
+ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+ {
+ 	int rc = 0, n_hc, port, hc;
+-	struct pci_dev *pdev = to_pci_dev(host->dev);
+ 	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+ 	struct mv_host_priv *hpriv = host->private_data;
+ 
+@@ -2606,7 +2653,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+ 		goto done;
+ 
+ 	hpriv->ops->reset_flash(hpriv, mmio);
+-	hpriv->ops->reset_bus(pdev, mmio);
++	hpriv->ops->reset_bus(host, mmio);
+ 	hpriv->ops->enable_leds(hpriv, mmio);
+ 
+ 	for (port = 0; port < host->n_ports; port++) {
+@@ -2629,8 +2676,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+ 
+ 		mv_port_init(&ap->ioaddr, port_mmio);
+ 
++#ifdef CONFIG_PCI
+ 		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ 		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
++#endif
+ 	}
+ 
+ 	for (hc = 0; hc < n_hc; hc++) {
+@@ -2667,6 +2716,55 @@ done:
+ 	return rc;
+ }
+ 
++#ifdef CONFIG_PCI
++static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
++
++static struct pci_driver mv_pci_driver = {
++	.name			= DRV_NAME,
++	.id_table		= mv_pci_tbl,
++	.probe			= mv_init_one,
++	.remove			= ata_pci_remove_one,
++};
++
++/*
++ * module options
++ */
++static int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
++
++
++/* move to PCI layer or libata core? */
++static int pci_go_64(struct pci_dev *pdev)
++{
++	int rc;
++
++	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
++		if (rc) {
++			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++			if (rc) {
++				dev_printk(KERN_ERR, &pdev->dev,
++					   "64-bit DMA enable failed\n");
++				return rc;
++			}
++		}
++	} else {
++		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++		if (rc) {
++			dev_printk(KERN_ERR, &pdev->dev,
++				   "32-bit DMA enable failed\n");
++			return rc;
++		}
++		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++		if (rc) {
++			dev_printk(KERN_ERR, &pdev->dev,
++				   "32-bit consistent DMA enable failed\n");
++			return rc;
++		}
++	}
++
++	return rc;
++}
++
+ /**
+  *      mv_print_info - Dump key info to kernel log for perusal.
+  *      @host: ATA host to print info about
+@@ -2709,6 +2807,26 @@ static void mv_print_info(struct ata_host *host)
+ 	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
+ }
+ 
++static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
++{
++	hpriv->crqb_pool   = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ,
++							     MV_CRQB_Q_SZ, 0);
++	if (!hpriv->crqb_pool)
++		return -ENOMEM;
++
++	hpriv->crpb_pool   = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ,
++							     MV_CRPB_Q_SZ, 0);
++	if (!hpriv->crpb_pool)
++		return -ENOMEM;
++
++	hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ,
++							     MV_SG_TBL_SZ, 0);
++	if (!hpriv->sg_tbl_pool)
++		return -ENOMEM;
++
++	return 0;
++}
++
+ /**
+  *      mv_init_one - handle a positive probe of a Marvell host
+  *      @pdev: PCI device found
+@@ -2754,6 +2872,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	if (rc)
+ 		return rc;
+ 
++	rc = mv_create_dma_pools(hpriv, &pdev->dev);
++	if (rc)
++		return rc;
++
+ 	/* initialize adapter */
+ 	rc = mv_init_host(host, board_idx);
+ 	if (rc)
+@@ -2771,15 +2893,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
+ 				 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
+ }
++#endif
+ 
+ static int __init mv_init(void)
+ {
+-	return pci_register_driver(&mv_pci_driver);
++	int rc = -ENODEV;
++#ifdef CONFIG_PCI
++	rc = pci_register_driver(&mv_pci_driver);
++#endif
++	return rc;
+ }
+ 
+ static void __exit mv_exit(void)
+ {
++#ifdef CONFIG_PCI
+ 	pci_unregister_driver(&mv_pci_driver);
++#endif
+ }
+ 
+ MODULE_AUTHOR("Brett Russ");
+@@ -2788,8 +2917,10 @@ MODULE_LICENSE("GPL");
+ MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
+ MODULE_VERSION(DRV_VERSION);
+ 
++#ifdef CONFIG_PCI
+ module_param(msi, int, 0444);
+ MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
++#endif
+ 
+ module_init(mv_init);
+ module_exit(mv_exit);
 diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
-index ed5dc7c..a0f98fd 100644
+index ed5dc7c..bfe92a4 100644
 --- a/drivers/ata/sata_nv.c
 +++ b/drivers/ata/sata_nv.c
-@@ -1336,21 +1336,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
+@@ -1011,14 +1011,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
+ 			}
+ 
+ 			if (status & (NV_ADMA_STAT_DONE |
+-				      NV_ADMA_STAT_CPBERR)) {
+-				u32 check_commands;
++				      NV_ADMA_STAT_CPBERR |
++				      NV_ADMA_STAT_CMD_COMPLETE)) {
++				u32 check_commands = notifier_clears[i];
+ 				int pos, error = 0;
+ 
+-				if (ata_tag_valid(ap->link.active_tag))
+-					check_commands = 1 << ap->link.active_tag;
+-				else
+-					check_commands = ap->link.sactive;
++				if (status & NV_ADMA_STAT_CPBERR) {
++					/* Check all active commands */
++					if (ata_tag_valid(ap->link.active_tag))
++						check_commands = 1 <<
++							ap->link.active_tag;
++					else
++						check_commands = ap->
++							link.sactive;
++				}
+ 
+ 				/** Check CPBs for completed commands */
+ 				while ((pos = ffs(check_commands)) && !error) {
+@@ -1336,21 +1342,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
  static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
  {
  	struct nv_adma_port_priv *pp = qc->ap->private_data;
@@ -362236,7 +372275,7 @@
  		cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
  	else
  		cpb->next_aprd = cpu_to_le64(0);
-@@ -1995,17 +1992,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+@@ -1995,17 +1998,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct scatterlist *sg;
@@ -362256,7 +372295,7 @@
  		u32 addr, offset;
  		u32 sg_len, len;
  
-@@ -2027,8 +2021,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+@@ -2027,8 +2027,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
  		}
  	}
  
@@ -366976,14 +377015,15 @@
  	int ret = 0;
  
 diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
-index 44504e6..de28dfd 100644
+index 44504e6..911208b 100644
 --- a/drivers/base/power/Makefile
 +++ b/drivers/base/power/Makefile
 @@ -1,11 +1,6 @@
 -obj-y			:= shutdown.o
  obj-$(CONFIG_PM)	+= sysfs.o
  obj-$(CONFIG_PM_SLEEP)	+= main.o
- obj-$(CONFIG_PM_TRACE)	+= trace.o
+-obj-$(CONFIG_PM_TRACE)	+= trace.o
++obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
  
 -ifeq ($(CONFIG_DEBUG_DRIVER),y)
 -EXTRA_CFLAGS += -DDEBUG
@@ -368478,7 +378518,7 @@
  	ps3disk_do_request(dev, priv->queue);
  	spin_unlock(&priv->lock);
 diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
-index fac4c6c..66e3015 100644
+index fac4c6c..a8de037 100644
 --- a/drivers/block/sunvdc.c
 +++ b/drivers/block/sunvdc.c
 @@ -212,12 +212,9 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
@@ -368514,6 +378554,15 @@
  	}
  }
  
+@@ -735,7 +732,7 @@ static struct vio_driver_ops vdc_vio_ops = {
+ 	.handshake_complete	= vdc_handshake_complete,
+ };
+ 
+-static void print_version(void)
++static void __devinit print_version(void)
+ {
+ 	static int version_printed;
+ 
 diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
 index 52dc5e1..cd5674b 100644
 --- a/drivers/block/sx8.c
@@ -368719,7 +378768,7 @@
  
  static inline void carm_handle_responses(struct carm_host *host)
 diff --git a/drivers/block/ub.c b/drivers/block/ub.c
-index 08e909d..c6179d6 100644
+index 08e909d..a70c1c2 100644
 --- a/drivers/block/ub.c
 +++ b/drivers/block/ub.c
 @@ -808,16 +808,16 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -368744,6 +378793,78 @@
  }
  
  static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
+@@ -922,11 +922,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+ 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
+ 	    bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
+ 
+-	/* Fill what we shouldn't be filling, because usb-storage did so. */
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+-
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+ 		/* XXX Clear stalls */
+ 		ub_complete(&sc->work_done);
+@@ -1313,9 +1308,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+ 	sc->last_pipe = pipe;
+ 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
+ 	    sg->length, ub_urb_complete, sc);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+ 		/* XXX Clear stalls */
+@@ -1356,9 +1348,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+ 	sc->last_pipe = sc->recv_bulk_pipe;
+ 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
+ 	    &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+ 		/* XXX Clear stalls */
+@@ -1473,9 +1462,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+ 
+ 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+ 	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+ 		ub_complete(&sc->work_done);
+@@ -1953,9 +1939,6 @@ static int ub_sync_reset(struct ub_dev *sc)
+ 
+ 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+ 	    (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+ 		printk(KERN_WARNING
+@@ -2007,9 +1990,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
+ 
+ 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
+ 	    (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
+ 		goto err_submit;
+@@ -2077,9 +2057,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
+ 
+ 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+ 	    (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
+-	sc->work_urb.actual_length = 0;
+-	sc->work_urb.error_count = 0;
+-	sc->work_urb.status = 0;
+ 
+ 	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+ 		printk(KERN_WARNING
 diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
 index ab5d404..9e61fca 100644
 --- a/drivers/block/viodasd.c
@@ -368888,6 +379009,23 @@
  
  obj-$(CONFIG_VIOCD)		+= viocd.o      cdrom.o
 +obj-$(CONFIG_GDROM)		+= gdrom.o      cdrom.o
+diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
+index af05610..47e5b40 100644
+--- a/drivers/cdrom/cdrom.c
++++ b/drivers/cdrom/cdrom.c
+@@ -2787,12 +2787,6 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
+ 	return -ENOSYS;
+ }
+ 
+-static inline
+-int msf_to_lba(char m, char s, char f)
+-{
+-	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+-}
+-
+ /*
+  * Required when we need to use READ_10 to issue other than 2048 block
+  * reads
 diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
 new file mode 100644
 index 0000000..4e2bbcc
@@ -372958,6 +383096,19 @@
 +
 +MODULE_LICENSE("Dual BSD/GPL");
 +MODULE_DESCRIPTION(DRIVER_DESC);
+diff --git a/drivers/char/random.c b/drivers/char/random.c
+index 5fee056..c511a83 100644
+--- a/drivers/char/random.c
++++ b/drivers/char/random.c
+@@ -667,8 +667,6 @@ void add_disk_randomness(struct gendisk *disk)
+ 	add_timer_randomness(disk->random,
+ 			     0x100 + MKDEV(disk->major, disk->first_minor));
+ }
+-
+-EXPORT_SYMBOL(add_disk_randomness);
+ #endif
+ 
+ #define EXTRACT_SIZE 10
 diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
 index 0c66b80..78b151c 100644
 --- a/drivers/char/rtc.c
@@ -373623,6 +383774,64 @@
  		BCD_TO_BIN(alm_tm->tm_sec);
  		BCD_TO_BIN(alm_tm->tm_min);
  		BCD_TO_BIN(alm_tm->tm_hour);
+diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
+index d222012..bacded0 100644
+--- a/drivers/char/tty_audit.c
++++ b/drivers/char/tty_audit.c
+@@ -73,6 +73,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
+  *	@tsk with @loginuid.  @buf->mutex must be locked.
+  */
+ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
++			       unsigned int sessionid,
+ 			       struct tty_audit_buf *buf)
+ {
+ 	struct audit_buffer *ab;
+@@ -85,9 +86,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+ 	if (ab) {
+ 		char name[sizeof(tsk->comm)];
+ 
+-		audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d "
+-				 "minor=%d comm=", tsk->pid, tsk->uid,
+-				 loginuid, buf->major, buf->minor);
++		audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u "
++				 "major=%d minor=%d comm=", tsk->pid, tsk->uid,
++				 loginuid, sessionid, buf->major, buf->minor);
+ 		get_task_comm(name, tsk);
+ 		audit_log_untrustedstring(ab, name);
+ 		audit_log_format(ab, " data=");
+@@ -105,8 +106,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+  */
+ static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
+ {
+-	tty_audit_buf_push(current, audit_get_loginuid(current->audit_context),
+-			   buf);
++	uid_t auid = audit_get_loginuid(current);
++	unsigned int sessionid = audit_get_sessionid(current);
++	tty_audit_buf_push(current, auid, sessionid, buf);
+ }
+ 
+ /**
+@@ -152,6 +154,11 @@ void tty_audit_fork(struct signal_struct *sig)
+ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+ {
+ 	struct tty_audit_buf *buf;
++	/* FIXME I think this is correct.  Check against netlink once that is
++	 * I really need to read this code more closely.  But that's for
++	 * another patch.
++	 */
++	unsigned int sessionid = audit_get_sessionid(tsk);
+ 
+ 	spin_lock_irq(&tsk->sighand->siglock);
+ 	buf = tsk->signal->tty_audit_buf;
+@@ -162,7 +169,7 @@ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+ 		return;
+ 
+ 	mutex_lock(&buf->mutex);
+-	tty_audit_buf_push(tsk, loginuid, buf);
++	tty_audit_buf_push(tsk, loginuid, sessionid, buf);
+ 	mutex_unlock(&buf->mutex);
+ 
+ 	tty_audit_buf_put(buf);
 diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
 index 12ceed5..5732ca3 100644
 --- a/drivers/connector/cn_queue.c
@@ -383772,6 +393981,19 @@
  };
  
  static int __init i2c_vt596_init(void)
+diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
+index e6c4a2b..f5e7a70 100644
+--- a/drivers/i2c/busses/scx200_acb.c
++++ b/drivers/i2c/busses/scx200_acb.c
+@@ -492,7 +492,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
+ 	iface->pdev = pdev;
+ 	iface->bar = bar;
+ 
+-	rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar);
++	rc = pci_enable_device_io(iface->pdev);
+ 	if (rc)
+ 		goto errout_free;
+ 
 diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
 index 2e1c24f..bd7082c 100644
 --- a/drivers/i2c/chips/Kconfig
@@ -386057,10 +396279,26 @@
  
  static int i2cdev_ioctl(struct inode *inode, struct file *file,
 diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
-index fb06555..64df55e 100644
+index fb06555..e42a465 100644
 --- a/drivers/ide/Kconfig
 +++ b/drivers/ide/Kconfig
-@@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM
+@@ -206,6 +206,15 @@ config BLK_DEV_IDECD
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ide-cd.
+ 
++config BLK_DEV_IDECD_VERBOSE_ERRORS
++	bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED
++	depends on BLK_DEV_IDECD
++	default y
++	help
++	  Turn this on to have the driver print out the meanings of the
++	  ATAPI error codes.  This will use up additional 8kB of kernel-space
++	  memory, though.
++
+ config BLK_DEV_IDETAPE
+ 	tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)"
+ 	depends on EXPERIMENTAL
+@@ -325,7 +334,7 @@ config BLK_DEV_PLATFORM
  	  If unsure, say N.
  
  config BLK_DEV_CMD640
@@ -386069,7 +396307,7 @@
  	depends on X86
  	---help---
  	  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
-@@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED
+@@ -359,9 +368,8 @@ config BLK_DEV_CMD640_ENHANCED
  	  Otherwise say N.
  
  config BLK_DEV_IDEPNP
@@ -386080,7 +396318,7 @@
  	help
  	  If you have a PnP (Plug and Play) compatible EIDE card and
  	  would like the kernel to automatically detect and activate
-@@ -374,19 +373,20 @@ comment "PCI IDE chipsets support"
+@@ -374,19 +382,20 @@ comment "PCI IDE chipsets support"
  config BLK_DEV_IDEPCI
  	bool
  
@@ -386111,7 +396349,18 @@
  
  # TODO: split it on per host driver config options (or module parameters)
  config BLK_DEV_OFFBOARD
-@@ -707,7 +707,6 @@ config BLK_DEV_SVWKS
+@@ -617,8 +626,8 @@ config BLK_DEV_SC1200
+ 	tristate "National SCx200 chipset support"
+ 	select BLK_DEV_IDEDMA_PCI
+ 	help
+-	  This driver adds support for the built in IDE on the National
+-	  SCx200 series of embedded x86 "Geode" systems
++	  This driver adds support for the on-board IDE controller on the
++	  National SCx200 series of embedded x86 "Geode" systems.
+ 
+ config BLK_DEV_PIIX
+ 	tristate "Intel PIIXn chipsets support"
+@@ -707,7 +716,6 @@ config BLK_DEV_SVWKS
  config BLK_DEV_SGIIOC4
  	tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
  	depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
@@ -386119,16 +396368,43 @@
  	select BLK_DEV_IDEDMA_PCI
  	help
  	  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
-@@ -801,7 +800,7 @@ config BLK_DEV_CELLEB
+@@ -794,22 +802,22 @@ config BLK_DEV_CELLEB
+ 	depends on PPC_CELLEB
+ 	select BLK_DEV_IDEDMA_PCI
+ 	help
+-	  This driver provides support for the built-in IDE controller on
++	  This driver provides support for the on-board IDE controller on
+ 	  Toshiba Cell Reference Board.
+ 	  If unsure, say Y.
+ 
  endif
  
  config BLK_DEV_IDE_PMAC
 -	bool "Builtin PowerMac IDE support"
-+	tristate "Builtin PowerMac IDE support"
++	tristate "PowerMac on-board IDE support"
  	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
  	help
- 	  This driver provides support for the built-in IDE controller on
-@@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
+-	  This driver provides support for the built-in IDE controller on
++	  This driver provides support for the on-board IDE controller on
+ 	  most of the recent Apple Power Macintoshes and PowerBooks.
+ 	  If unsure, say Y.
+ 
+ config BLK_DEV_IDE_PMAC_ATA100FIRST
+-	bool "Probe internal ATA/100 (Kauai) first"
++	bool "Probe on-board ATA/100 (Kauai) first"
+ 	depends on BLK_DEV_IDE_PMAC
+ 	help
+ 	  This option will cause the ATA/100 controller found in UniNorth2
+@@ -824,7 +832,7 @@ config BLK_DEV_IDEDMA_PMAC
+ 	depends on BLK_DEV_IDE_PMAC
+ 	select BLK_DEV_IDEDMA_PCI
+ 	help
+-	  This option allows the driver for the built-in IDE controller on
++	  This option allows the driver for the on-board IDE controller on
+ 	  Power Macintoshes and PowerBooks to use DMA (direct memory access)
+ 	  to transfer data to and from memory.  Saying Y is safe and improves
+ 	  performance.
+@@ -855,8 +863,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
         depends on BLK_DEV_IDE_AU1XXX
  
  config IDE_ARM
@@ -386140,7 +396416,7 @@
  
  config BLK_DEV_IDE_ICSIDE
  	tristate "ICS IDE interface support"
-@@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST
+@@ -888,10 +897,9 @@ config BLK_DEV_IDE_BAST
  	  Simtec BAST or the Thorcom VR1000
  
  config ETRAX_IDE
@@ -386152,7 +396428,7 @@
  	help
  	  Enables the ETRAX IDE driver.
  
-@@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET
+@@ -923,21 +931,19 @@ config ETRAX_IDE_G27_RESET
  endchoice
  
  config IDE_H8300
@@ -386172,7 +396448,27 @@
  	help
  	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
  	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
-@@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER
+-	  This includes builtin IDE interfaces on some Amiga models (A600,
++	  This includes on-board IDE interfaces on some Amiga models (A600,
+ 	  A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
+ 	  bus (M-Tech E-Matrix 530 expansion card).
+ 	  Say Y if you have an Amiga with a Gayle IDE interface and want to use
+@@ -951,10 +957,10 @@ config BLK_DEV_IDEDOUBLER
+ 	depends on BLK_DEV_GAYLE && EXPERIMENTAL
+ 	---help---
+ 	  This driver provides support for the so-called `IDE doublers' (made
+-	  by various manufacturers, e.g. Eyetech) that can be connected to the
+-	  builtin IDE interface of some Amiga models. Using such an IDE
+-	  doubler, you can connect up to four instead of two IDE devices on
+-	  the Amiga's builtin IDE interface.
++	  by various manufacturers, e.g. Eyetech) that can be connected to
++	  the on-board IDE interface of some Amiga models. Using such an IDE
++	  doubler, you can connect up to four instead of two IDE devices to
++	  the Amiga's on-board IDE interface.
+ 
+ 	  Note that the normal Amiga Gayle IDE driver may not work correctly
+ 	  if you have an IDE doubler and don't enable this driver!
+@@ -963,55 +969,50 @@ config BLK_DEV_IDEDOUBLER
  	  runtime using the "ide=doubler" kernel boot parameter.
  
  config BLK_DEV_BUDDHA
@@ -386181,9 +396477,15 @@
  	depends on ZORRO && EXPERIMENTAL
 -	select IDE_GENERIC
  	help
- 	  This is the IDE driver for the IDE interfaces on the Buddha, 
- 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
-@@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA
+-	  This is the IDE driver for the IDE interfaces on the Buddha, 
+-	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
+-	  on the Buddha, three on the Catweasel and two on the X-Surf.
++	  This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
++	  and X-Surf expansion boards.  It supports up to two interfaces on the
++	  Buddha, three on the Catweasel and two on the X-Surf.
+ 
+ 	  Say Y if you have a Buddha or Catweasel expansion board and want to
+ 	  use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
  	  to one of its IDE interfaces.
  
  config BLK_DEV_FALCON_IDE
@@ -386192,9 +396494,11 @@
  	depends on ATARI
 -	select IDE_GENERIC
  	help
- 	  This is the IDE driver for the builtin IDE interface on the Atari
+-	  This is the IDE driver for the builtin IDE interface on the Atari
++	  This is the IDE driver for the on-board IDE interface on the Atari
  	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
-@@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE
+-	  disks, CD-ROM drives, etc.) that are connected to the builtin IDE
++	  disks, CD-ROM drives, etc.) that are connected to the on-board IDE
  	  interface.
  
  config BLK_DEV_MAC_IDE
@@ -386203,10 +396507,16 @@
  	depends on MAC
 -	select IDE_GENERIC
  	help
- 	  This is the IDE driver for the builtin IDE interface on some m68k
+-	  This is the IDE driver for the builtin IDE interface on some m68k
++	  This is the IDE driver for the on-board IDE interface on some m68k
  	  Macintosh models. It supports both the `Quadra style' (used in
-@@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE
- 	  builtin IDE interface.
+ 	  Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
+ 	  (used in the Powerbook 150 and 190 models) IDE interface.
+ 
+ 	  Say Y if you have such an Macintosh model and want to use IDE
+ 	  devices (hard disks, CD-ROM drives, etc.) that are connected to the
+-	  builtin IDE interface.
++	  on-board IDE interface.
  
  config BLK_DEV_Q40IDE
 -	bool "Q40/Q60 IDE interface support"
@@ -386226,11 +396536,33 @@
  	help
  	  This option provides support for IDE on Motorola MPC8xx Systems.
  	  Please see 'Type of MPC8xx IDE interface' for details.
+@@ -1070,8 +1071,8 @@ config BLK_DEV_ALI14XX
+ 	  boot parameter.  It enables support for the secondary IDE interface
+ 	  of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+ 	  I/O speeds to be set as well.  See the files
+-	  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for
+-	  more info.
++	  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c>
++	  for more info.
+ 
+ config BLK_DEV_DTC2278
+ 	tristate "DTC-2278 support"
+@@ -1096,8 +1097,8 @@ config BLK_DEV_QD65XX
+ 	help
+ 	  This driver is enabled at runtime using the "qd65xx.probe" kernel
+ 	  boot parameter.  It permits faster I/O speeds to be set.  See the
+-	  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
+-	  more info.
++	  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c>
++	  for more info.
+ 
+ config BLK_DEV_UMC8672
+ 	tristate "UMC-8672 support"
 diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
-index b181fc6..0d2da89 100644
+index b181fc6..a4a4323 100644
 --- a/drivers/ide/Makefile
 +++ b/drivers/ide/Makefile
-@@ -7,41 +7,37 @@
+@@ -7,48 +7,60 @@
  # Note : at this point, these files are compiled on all systems.
  # In the future, some of these should be built conditionally.
  #
@@ -386288,8 +396620,11 @@
 +obj-$(CONFIG_IDE_H8300)			+= h8300/
  obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
  
++ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
++
  obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
-@@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+-obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
++obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd_mod.o
  obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
  obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
  
@@ -386327,10 +396662,17 @@
 +
  EXTRA_CFLAGS	:= -Idrivers/ide
 diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
-index 48db616..45bf9c8 100644
+index 48db616..037300f 100644
 --- a/drivers/ide/arm/bast-ide.c
 +++ b/drivers/ide/arm/bast-ide.c
-@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
+@@ -1,5 +1,4 @@
+-/* linux/drivers/ide/arm/bast-ide.c
+- *
++/*
+  * Copyright (c) 2003-2004 Simtec Electronics
+  *  Ben Dooks <ben at simtec.co.uk>
+  *
+@@ -45,7 +44,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
  	hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
  	hw.irq = irq;
  
@@ -386340,10 +396682,50 @@
  	return 0;
  }
 diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
-index 93f71fc..8a5c720 100644
+index 93f71fc..8d2cc47 100644
 --- a/drivers/ide/arm/icside.c
 +++ b/drivers/ide/arm/icside.c
-@@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/arm/icside.c
+- *
+  * Copyright (c) 1996-2004 Russell King.
+  *
+  * Please note that this platform does not support 32-bit IDE IO.
+@@ -71,8 +69,6 @@ struct icside_state {
+ 	void __iomem *irq_port;
+ 	void __iomem *ioc_base;
+ 	unsigned int type;
+-	/* parent device... until the IDE core gets one of its own */
+-	struct device *dev;
+ 	ide_hwif_t *hwif[2];
+ };
+ 
+@@ -206,23 +202,6 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
+  * interfaces use the same IRQ, which should guarantee this.
+  */
+ 
+-static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
+-{
+-	ide_hwif_t *hwif = drive->hwif;
+-	struct icside_state *state = hwif->hwif_data;
+-	struct scatterlist *sg = hwif->sg_table;
+-
+-	ide_map_sg(drive, rq);
+-
+-	if (rq_data_dir(rq) == READ)
+-		hwif->sg_dma_direction = DMA_FROM_DEVICE;
+-	else
+-		hwif->sg_dma_direction = DMA_TO_DEVICE;
+-
+-	hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents,
+-				    hwif->sg_dma_direction);
+-}
+-
+ /*
+  * Configure the IOMD to give the appropriate timings for the transfer
+  * mode being requested.  We take the advice of the ATA standards, and
+@@ -272,8 +251,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
  	case XFER_SW_DMA_0:
  		cycle_time = 480;
  		break;
@@ -386352,7 +396734,7 @@
  	}
  
  	/*
-@@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+@@ -289,56 +266,39 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
  		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
  }
  
@@ -386380,7 +396762,75 @@
  static int icside_dma_end(ide_drive_t *drive)
  {
  	ide_hwif_t *hwif = HWIF(drive);
-@@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
+-	struct icside_state *state = hwif->hwif_data;
++	struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ 
+ 	drive->waiting_for_dma = 0;
+ 
+-	disable_dma(ECARD_DEV(state->dev)->dma);
++	disable_dma(ec->dma);
+ 
+ 	/* Teardown mappings after DMA has completed. */
+-	dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
+-		     hwif->sg_dma_direction);
++	ide_destroy_dmatable(drive);
+ 
+-	return get_dma_residue(ECARD_DEV(state->dev)->dma) != 0;
++	return get_dma_residue(ec->dma) != 0;
+ }
+ 
+ static void icside_dma_start(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	struct icside_state *state = hwif->hwif_data;
++	struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ 
+ 	/* We can not enable DMA on both channels simultaneously. */
+-	BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
+-	enable_dma(ECARD_DEV(state->dev)->dma);
++	BUG_ON(dma_channel_active(ec->dma));
++	enable_dma(ec->dma);
+ }
+ 
+ static int icside_dma_setup(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	struct icside_state *state = hwif->hwif_data;
++	struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ 	struct request *rq = hwif->hwgroup->rq;
+ 	unsigned int dma_mode;
+ 
+@@ -350,9 +310,9 @@ static int icside_dma_setup(ide_drive_t *drive)
+ 	/*
+ 	 * We can not enable DMA on both channels.
+ 	 */
+-	BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
++	BUG_ON(dma_channel_active(ec->dma));
+ 
+-	icside_build_sglist(drive, rq);
++	hwif->sg_nents = ide_build_sglist(drive, rq);
+ 
+ 	/*
+ 	 * Ensure that we have the right interrupt routed.
+@@ -367,14 +327,14 @@ static int icside_dma_setup(ide_drive_t *drive)
+ 	/*
+ 	 * Select the correct timing for this drive.
+ 	 */
+-	set_dma_speed(ECARD_DEV(state->dev)->dma, drive->drive_data);
++	set_dma_speed(ec->dma, drive->drive_data);
+ 
+ 	/*
+ 	 * Tell the DMA engine about the SG table and
+ 	 * data direction.
+ 	 */
+-	set_dma_sg(ECARD_DEV(state->dev)->dma, hwif->sg_table, hwif->sg_nents);
+-	set_dma_mode(ECARD_DEV(state->dev)->dma, dma_mode);
++	set_dma_sg(ec->dma, hwif->sg_table, hwif->sg_nents);
++	set_dma_mode(ec->dma, dma_mode);
+ 
+ 	drive->waiting_for_dma = 1;
+ 
+@@ -424,10 +384,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
  	hwif->dmatable_dma	= 0;
  	hwif->set_dma_mode	= icside_set_dma_mode;
  
@@ -386392,6 +396842,22 @@
  	hwif->dma_setup		= icside_dma_setup;
  	hwif->dma_exec_cmd	= icside_dma_exec_cmd;
  	hwif->dma_start		= icside_dma_start;
+@@ -465,6 +422,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e
+ 		hwif->noprobe = 0;
+ 		hwif->chipset = ide_acorn;
+ 		hwif->gendev.parent = &ec->dev;
++		hwif->dev = &ec->dev;
+ 	}
+ 
+ 	return hwif;
+@@ -612,7 +570,6 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+ 	}
+ 
+ 	state->type	= ICS_TYPE_NOTYPE;
+-	state->dev	= &ec->dev;
+ 
+ 	idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
+ 	if (idmem) {
 diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
 index 8957cba..60f2497 100644
 --- a/drivers/ide/arm/ide_arm.c
@@ -386425,10 +396891,17 @@
 +
 +module_init(ide_arm_init);
 diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
-index 0775a3a..e6b56d1 100644
+index 0775a3a..c8b6581 100644
 --- a/drivers/ide/arm/rapide.c
 +++ b/drivers/ide/arm/rapide.c
-@@ -13,26 +13,18 @@
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/arm/rapide.c
+- *
+  * Copyright (c) 1996-2002 Russell King.
+  */
+ 
+@@ -13,26 +11,18 @@
  
  #include <asm/ecard.h>
  
@@ -386460,7 +396933,7 @@
  }
  
  static int __devinit
-@@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+@@ -42,6 +32,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
  	void __iomem *base;
  	int ret;
  	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
@@ -386468,7 +396941,7 @@
  
  	ret = ecard_request_resources(ec);
  	if (ret)
-@@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+@@ -53,11 +44,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
  		goto release;
  	}
  
@@ -386490,6 +396963,17 @@
  
  		idx[0] = hwif->index;
  
+@@ -79,8 +76,8 @@ static void __devexit rapide_remove(struct expansion_card *ec)
+ 
+ 	ecard_set_drvdata(ec, NULL);
+ 
+-	/* there must be a better way */
+-	ide_unregister(hwif - ide_hwifs);
++	ide_unregister(hwif->index);
++
+ 	ecard_release_resources(ec);
+ }
+ 
 diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
 index 6176e8d..20b9596 100644
 --- a/drivers/ide/cris/Makefile
@@ -386500,10 +396984,17 @@
 -obj-y					+= ide-cris.o
 +obj-$(CONFIG_IDE_ETRAX)			+= ide-cris.o
 diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
-index 476e0d6..8c3294c 100644
+index 476e0d6..0640a38 100644
 --- a/drivers/ide/cris/ide-cris.c
 +++ b/drivers/ide/cris/ide-cris.c
-@@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
+@@ -1,5 +1,4 @@
+-/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $
+- *
++/*
+  * Etrax specific IDE functions, like init and PIO-mode setting etc.
+  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
+  * Copyright (c) 2000-2005 Axis Communications AB
+@@ -673,9 +672,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
  static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
  static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
  static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
@@ -386514,7 +397005,7 @@
  {
  }
  
-@@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -747,8 +745,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
  			strobe = ATA_DMA2_STROBE;
  			hold = ATA_DMA2_HOLD;
  			break;
@@ -386523,7 +397014,7 @@
  	}
  
  	if (speed >= XFER_UDMA_0)
-@@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -757,13 +753,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
  		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
  }
  
@@ -386540,7 +397031,7 @@
  
  	printk("ide: ETRAX FS built-in ATA DMA controller\n");
  
-@@ -780,9 +775,11 @@ init_e100_ide (void)
+@@ -780,9 +774,11 @@ init_e100_ide (void)
  		                ide_offsets,
  		                0, 0, cris_ide_ack_intr,
  		                ide_default_irq(0));
@@ -386553,7 +397044,7 @@
  		hwif->mmio = 1;
  		hwif->chipset = ide_etrax100;
  		hwif->set_pio_mode = &cris_set_pio_mode;
-@@ -791,6 +788,7 @@ init_e100_ide (void)
+@@ -791,6 +787,7 @@ init_e100_ide (void)
  		hwif->ata_output_data = &cris_ide_output_data;
  		hwif->atapi_input_bytes = &cris_atapi_input_bytes;
  		hwif->atapi_output_bytes = &cris_atapi_output_bytes;
@@ -386561,7 +397052,7 @@
  		hwif->ide_dma_end = &cris_dma_end;
  		hwif->dma_setup = &cris_dma_setup;
  		hwif->dma_exec_cmd = &cris_dma_exec_cmd;
-@@ -801,9 +799,6 @@ init_e100_ide (void)
+@@ -801,9 +798,6 @@ init_e100_ide (void)
  		hwif->OUTBSYNC = &cris_ide_outbsync;
  		hwif->INB = &cris_ide_inb;
  		hwif->INW = &cris_ide_inw;
@@ -386571,7 +397062,7 @@
  		hwif->cbl = ATA_CBL_PATA40;
  		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
  		hwif->pio_mask = ATA_PIO4,
-@@ -811,6 +806,8 @@ init_e100_ide (void)
+@@ -811,6 +805,8 @@ init_e100_ide (void)
  		hwif->drives[1].autotune = 1;
  		hwif->ultra_mask = cris_ultra_mask;
  		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
@@ -386580,7 +397071,7 @@
  	}
  
  	/* Reset pulse */
-@@ -823,14 +820,12 @@ init_e100_ide (void)
+@@ -823,14 +819,12 @@ init_e100_ide (void)
  	cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
  	cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
  	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
@@ -386597,7 +397088,7 @@
  static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
  
  /*
-@@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive)
+@@ -1062,3 +1056,5 @@ static void cris_dma_start(ide_drive_t *drive)
  		LED_DISK_READ(1);
  	}
  }
@@ -386612,10 +397103,16 @@
 +
 +obj-$(CONFIG_IDE_H8300)			+= ide-h8300.o
 diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
-index 4a49b5c..4f6d019 100644
+index 4a49b5c..0243295 100644
 --- a/drivers/ide/h8300/ide-h8300.c
 +++ b/drivers/ide/h8300/ide-h8300.c
-@@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
+@@ -1,5 +1,4 @@
+ /*
+- * drivers/ide/h8300/ide-h8300.c
+  * H8/300 generic IDE interface
+  */
+ 
+@@ -84,11 +83,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
  	hwif->INSL  = NULL;
  }
  
@@ -386630,7 +397127,7 @@
  
  	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
  		goto out_busy;
-@@ -100,16 +101,28 @@ void __init h8300_ide_init(void)
+@@ -100,16 +100,28 @@ void __init h8300_ide_init(void)
  	hw_setup(&hw);
  
  	/* register if */
@@ -386665,10 +397162,16 @@
 +
 +module_init(h8300_ide_init);
 diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
-index 899d565..e888fc3 100644
+index 899d565..68bc618 100644
 --- a/drivers/ide/ide-acpi.c
 +++ b/drivers/ide/ide-acpi.c
-@@ -383,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
+@@ -1,5 +1,4 @@
+ /*
+- * ide-acpi.c
+  * Provides ACPI support for IDE drives.
+  *
+  * Copyright (C) 2005 Intel Corp.
+@@ -383,27 +382,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
  	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
  
  	memset(&args, 0, sizeof(ide_task_t));
@@ -386701,10 +397204,494 @@
  
  	return err;
 diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
-index c7d77f0..74c6087 100644
+index c7d77f0..23074e8 100644
 --- a/drivers/ide/ide-cd.c
 +++ b/drivers/ide/ide-cd.c
-@@ -655,9 +655,9 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
+@@ -1,14 +1,14 @@
+ /*
+- * linux/drivers/ide/ide-cd.c
++ * ATAPI CD-ROM driver.
+  *
+- * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder at fnald0.fnal.gov>
+- * Copyright (C) 1996-1998  Erik Andersen <andersee at debian.org>
+- * Copyright (C) 1998-2000  Jens Axboe <axboe at suse.de>
++ * Copyright (C) 1994-1996   Scott Snyder <snyder at fnald0.fnal.gov>
++ * Copyright (C) 1996-1998   Erik Andersen <andersee at debian.org>
++ * Copyright (C) 1998-2000   Jens Axboe <axboe at suse.de>
++ * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
+  *
+  * May be copied or modified under the terms of the GNU General Public
+  * License.  See linux/COPYING for more information.
+  *
+- * ATAPI CD-ROM driver.  To be used with ide.c.
+  * See Documentation/cdrom/ide-cd for usage information.
+  *
+  * Suggestions are welcome. Patches that work are more welcome though. ;-)
+@@ -19,287 +19,11 @@
+  * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
+  * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
+  *
+- * Drives that deviate from these standards will be accommodated as much
+- * as possible via compile time or command-line options.  Since I only have
+- * a few drives, you generally need to send me patches...
+- *
+- * ----------------------------------
+- * TO DO LIST:
+- * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
+- *   boot
+- *
+- * ----------------------------------
+- * 1.00  Oct 31, 1994 -- Initial version.
+- * 1.01  Nov  2, 1994 -- Fixed problem with starting request in
+- *                       cdrom_check_status.
+- * 1.03  Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
+- * (from mlord)       -- minor changes to cdrom_setup()
+- *                    -- renamed ide_dev_s to ide_drive_t, enable irq on command
+- * 2.00  Nov 27, 1994 -- Generalize packet command interface;
+- *                       add audio ioctls.
+- * 2.01  Dec  3, 1994 -- Rework packet command interface to handle devices
+- *                       which send an interrupt when ready for a command.
+- * 2.02  Dec 11, 1994 -- Cache the TOC in the driver.
+- *                       Don't use SCMD_PLAYAUDIO_TI; it's not included
+- *                       in the current version of ATAPI.
+- *                       Try to use LBA instead of track or MSF addressing
+- *                       when possible.
+- *                       Don't wait for READY_STAT.
+- * 2.03  Jan 10, 1995 -- Rewrite block read routines to handle block sizes
+- *                       other than 2k and to move multiple sectors in a
+- *                       single transaction.
+- * 2.04  Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
+- *                       Thanks to Nick Saw <cwsaw at pts7.pts.mot.com> for
+- *                       help in figuring this out.  Ditto for Acer and
+- *                       Aztech drives, which seem to have the same problem.
+- * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
+- * 2.05  Jun  8, 1995 -- Don't attempt to retry after an illegal request
+- *                        or data protect error.
+- *                       Use HWIF and DEV_HWIF macros as in ide.c.
+- *                       Always try to do a request_sense after
+- *                        a failed command.
+- *                       Include an option to give textual descriptions
+- *                        of ATAPI errors.
+- *                       Fix a bug in handling the sector cache which
+- *                        showed up if the drive returned data in 512 byte
+- *                        blocks (like Pioneer drives).  Thanks to
+- *                        Richard Hirst <srh at gpt.co.uk> for diagnosing this.
+- *                       Properly supply the page number field in the
+- *                        MODE_SELECT command.
+- *                       PLAYAUDIO12 is broken on the Aztech; work around it.
+- * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
+- *                       (my apologies to Scott, but now ide-cd.c is independent)
+- * 3.00  Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
+- *                       Implement CDROMREADAUDIO ioctl (UNTESTED).
+- *                       Use input_ide_data() and output_ide_data().
+- *                       Add door locking.
+- *                       Fix usage count leak in cdrom_open, which happened
+- *                        when a read-write mount was attempted.
+- *                       Try to load the disk on open.
+- *                       Implement CDROMEJECT_SW ioctl (off by default).
+- *                       Read total cdrom capacity during open.
+- *                       Rearrange logic in cdrom_decode_status.  Issue
+- *                        request sense commands for failed packet commands
+- *                        from here instead of from cdrom_queue_packet_command.
+- *                        Fix a race condition in retrieving error information.
+- *                       Suppress printing normal unit attention errors and
+- *                        some drive not ready errors.
+- *                       Implement CDROMVOLREAD ioctl.
+- *                       Implement CDROMREADMODE1/2 ioctls.
+- *                       Fix race condition in setting up interrupt handlers
+- *                        when the `serialize' option is used.
+- * 3.01  Sep  2, 1995 -- Fix ordering of reenabling interrupts in
+- *                        cdrom_queue_request.
+- *                       Another try at using ide_[input,output]_data.
+- * 3.02  Sep 16, 1995 -- Stick total disk capacity in partition table as well.
+- *                       Make VERBOSE_IDE_CD_ERRORS dump failed command again.
+- *                       Dump out more information for ILLEGAL REQUEST errs.
+- *                       Fix handling of errors occurring before the
+- *                        packet command is transferred.
+- *                       Fix transfers with odd bytelengths.
+- * 3.03  Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
+- *                       `DCI-2S10' drives are broken too.
+- * 3.04  Nov 20, 1995 -- So are Vertos drives.
+- * 3.05  Dec  1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
+- * 3.06  Dec 16, 1995 -- Add support needed for partitions.
+- *                       More workarounds for Vertos bugs (based on patches
+- *                        from Holger Dietze <dietze at aix520.informatik.uni-leipzig.de>).
+- *                       Try to eliminate byteorder assumptions.
+- *                       Use atapi_cdrom_subchnl struct definition.
+- *                       Add STANDARD_ATAPI compilation option.
+- * 3.07  Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
+- *                        Vertos 300.
+- *                       Add NO_DOOR_LOCKING configuration option.
+- *                       Handle drive_cmd requests w/NULL args (for hdparm -t).
+- *                       Work around sporadic Sony55e audio play problem.
+- * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
+- *                        problem with "hde=cdrom" with no drive present.  -ml
+- * 3.08  Mar  6, 1996 -- More Vertos workarounds.
+- * 3.09  Apr  5, 1996 -- Add CDROMCLOSETRAY ioctl.
+- *                       Switch to using MSF addressing for audio commands.
+- *                       Reformat to match kernel tabbing style.
+- *                       Add CDROM_GET_UPC ioctl.
+- * 3.10  Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
+- * 3.11  Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko at colossus.escape.de>
+- *                       to remove redundant verify_area calls.
+- * 3.12  May  7, 1996 -- Rudimentary changer support.  Based on patches
+- *                        from Gerhard Zuber <zuber at berlin.snafu.de>.
+- *                       Let open succeed even if there's no loaded disc.
+- * 3.13  May 19, 1996 -- Fixes for changer code.
+- * 3.14  May 29, 1996 -- Add work-around for Vertos 600.
+- *                        (From Hennus Bergman <hennus at sky.ow.nl>.)
+- * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
+- *                        from Ben Galliart <bgallia at luc.edu> with 
+- *                        special help from Jeff Lightfoot 
+- *                        <jeffml at pobox.com>
+- * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
+- * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
+- * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
+- *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
+- * 3.18  Oct 31, 1996 -- Added module and DMA support.
+- *                       
+- *                       
+- * 4.00  Nov 5, 1996   -- New ide-cd maintainer,
+- *                                 Erik B. Andersen <andersee at debian.org>
+- *                     -- Newer Creative drives don't always set the error
+- *                          register correctly.  Make sure we see media changes
+- *                          regardless.
+- *                     -- Integrate with generic cdrom driver.
+- *                     -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
+- *                          a patch from Ciro Cattuto <>.
+- *                     -- Call set_device_ro.
+- *                     -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
+- *                          ioctls, based on patch by Erik Andersen
+- *                     -- Add some probes of drive capability during setup.
+- *
+- * 4.01  Nov 11, 1996  -- Split into ide-cd.c and ide-cd.h
+- *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE 
+- *                          ioctls in favor of a generalized approach 
+- *                          using the generic cdrom driver.
+- *                     -- Fully integrated with the 2.1.X kernel.
+- *                     -- Other stuff that I forgot (lots of changes)
+- *
+- * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio at netvision.net.il>
+- *                          to fix the drive door locking problems.
+- *
+- * 4.03  Dec 04, 1996  -- Added DSC overlap support.
+- * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch 
+- *                          by Ales Makarov (xmakarov at sun.felk.cvut.cz)
+- *
+- * 4.05  Nov 20, 1997  -- Modified to print more drive info on init
+- *                        Minor other changes
+- *                        Fix errors on CDROMSTOP (If you have a "Dolphin",
+- *                          you must define IHAVEADOLPHIN)
+- *                        Added identifier so new Sanyo CD-changer works
+- *                        Better detection if door locking isn't supported
+- *
+- * 4.06  Dec 17, 1997  -- fixed endless "tray open" messages  -ml
+- * 4.07  Dec 17, 1997  -- fallback to set pc->stat on "tray open"
+- * 4.08  Dec 18, 1997  -- spew less noise when tray is empty
+- *                     -- fix speed display for ACER 24X, 18X
+- * 4.09  Jan 04, 1998  -- fix handling of the last block so we return
+- *                         an end of file instead of an I/O error (Gadi)
+- * 4.10  Jan 24, 1998  -- fixed a bug so now changers can change to a new
+- *                         slot when there is no disc in the current slot.
+- *                     -- Fixed a memory leak where info->changer_info was
+- *                         malloc'ed but never free'd when closing the device.
+- *                     -- Cleaned up the global namespace a bit by making more
+- *                         functions static that should already have been.
+- * 4.11  Mar 12, 1998  -- Added support for the CDROM_SELECT_SPEED ioctl
+- *                         based on a patch for 2.0.33 by Jelle Foks 
+- *                         <jelle at scintilla.utwente.nl>, a patch for 2.0.33
+- *                         by Toni Giorgino <toni at pcape2.pi.infn.it>, the SCSI
+- *                         version, and my own efforts.  -erik
+- *                     -- Fixed a stupid bug which egcs was kind enough to
+- *                         inform me of where "Illegal mode for this track"
+- *                         was never returned due to a comparison on data
+- *                         types of limited range.
+- * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is 
+- *                         now set ionly for CD-R and CD-RW drives.  I had 
+- *                         removed this support because it produced errors.
+- *                         It produced errors _only_ for non-writers. duh.
+- * 4.13  May 05, 1998  -- Suppress useless "in progress of becoming ready"
+- *                         messages, since this is not an error.
+- *                     -- Change error messages to be const
+- *                     -- Remove a "\t" which looks ugly in the syslogs
+- * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
+- *                         since the .pdf version doesn't seem to work...
+- *                     -- Updated the TODO list to something more current.
+- *
+- * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess, 
+- *                         patch thanks to "Eddie C. Dost" <ecd at skynet.be>
+- *
+- * 4.50  Oct 19, 1998  -- New maintainers!
+- *                         Jens Axboe <axboe at image.dk>
+- *                         Chris Zwilling <chris at cloudnet.com>
+- *
+- * 4.51  Dec 23, 1998  -- Jens Axboe <axboe at image.dk>
+- *                      - ide_cdrom_reset enabled since the ide subsystem
+- *                         handles resets fine now. <axboe at image.dk>
+- *                      - Transfer size fix for Samsung CD-ROMs, thanks to
+- *                        "Ville Hallik" <ville.hallik at mail.ee>.
+- *                      - other minor stuff.
+- *
+- * 4.52  Jan 19, 1999  -- Jens Axboe <axboe at image.dk>
+- *                      - Detect DVD-ROM/RAM drives
+- *
+- * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
+- *                         drive in transfer size limit.
+- *                      - Fix the I/O error when doing eject without a medium
+- *                         loaded on some drives.
+- *                      - CDROMREADMODE2 is now implemented through
+- *                         CDROMREADRAW, since many drives don't support
+- *                         MODE2 (even though ATAPI 2.6 says they must).
+- *                      - Added ignore parameter to ide-cd (as a module), eg
+- *                         	insmod ide-cd ignore='hda hdb'
+- *                         Useful when using ide-cd in conjunction with
+- *                         ide-scsi. TODO: non-modular way of doing the
+- *                         same.
+- *
+- * 4.54  Aug 5, 1999	- Support for MMC2 class commands through the generic
+- *			  packet interface to cdrom.c.
+- *			- Unified audio ioctl support, most of it.
+- *			- cleaned up various deprecated verify_area().
+- *			- Added ide_cdrom_packet() as the interface for
+- *			  the Uniform generic_packet().
+- *			- bunch of other stuff, will fill in logs later.
+- *			- report 1 slot for non-changers, like the other
+- *			  cd-rom drivers. don't report select disc for
+- *			  non-changers as well.
+- *			- mask out audio playing, if the device can't do it.
+- *
+- * 4.55  Sep 1, 1999	- Eliminated the rest of the audio ioctls, except
+- *			  for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
+- *			  use this independently of the actual audio handling.
+- *			  They will disappear later when I get the time to
+- *			  do it cleanly.
+- *			- Minimize the TOC reading - only do it when we
+- *			  know a media change has occurred.
+- *			- Moved all the CDROMREADx ioctls to the Uniform layer.
+- *			- Heiko Eißfeldt <heiko at colossus.escape.de> supplied
+- *			  some fixes for CDI.
+- *			- CD-ROM leaving door locked fix from Andries
+- *			  Brouwer <Andries.Brouwer at cwi.nl>
+- *			- Erik Andersen <andersen at xmission.com> unified
+- *			  commands across the various drivers and how
+- *			  sense errors are handled.
+- *
+- * 4.56  Sep 12, 1999	- Removed changer support - it is now in the
+- *			  Uniform layer.
+- *			- Added partition based multisession handling.
+- *			- Mode sense and mode select moved to the
+- *			  Uniform layer.
+- *			- Fixed a problem with WPI CDS-32X drive - it
+- *			  failed the capabilities 
+- *
+- * 4.57  Apr 7, 2000	- Fixed sense reporting.
+- *			- Fixed possible oops in ide_cdrom_get_last_session()
+- *			- Fix locking mania and make ide_cdrom_reset relock
+- *			- Stop spewing errors to log when magicdev polls with
+- *			  TEST_UNIT_READY on some drives.
+- *			- Various fixes from Tobias Ringstrom:
+- *			  tray if it was locked prior to the reset.
+- *			  - cdrom_read_capacity returns one frame too little.
+- *			  - Fix real capacity reporting.
+- *
+- * 4.58  May 1, 2000	- Clean up ACER50 stuff.
+- *			- Fix small problem with ide_cdrom_capacity
+- *
+- * 4.59  Aug 11, 2000	- Fix changer problem in cdrom_read_toc, we weren't
+- *			  correctly sensing a disc change.
+- *			- Rearranged some code
+- *			- Use extended sense on drives that support it for
+- *			  correctly reporting tray status -- from
+- *			  Michael D Johnson <johnsom at orst.edu>
+- * 4.60  Dec 17, 2003	- Add mt rainier support
+- *			- Bump timeout for packet commands, matches sr
+- *			- Odd stuff
+- * 4.61  Jan 22, 2004	- support hardware sector sizes other than 2kB,
+- *			  Pascal Schmidt <der.eremit at email.de>
+- *
+- *************************************************************************/
+- 
+-#define IDECD_VERSION "4.61"
++ * For historical changelog please see:
++ *	Documentation/ide/ChangeLog.ide-cd.1994-2004
++ */
++
++#define IDECD_VERSION "5.00"
+ 
+ #include <linux/module.h>
+ #include <linux/types.h>
+@@ -313,6 +37,7 @@
+ #include <linux/ide.h>
+ #include <linux/completion.h>
+ #include <linux/mutex.h>
++#include <linux/bcd.h>
+ 
+ #include <scsi/scsi.h>	/* For SCSI -> ATAPI command conversion */
+ 
+@@ -360,11 +85,11 @@ static void ide_cd_put(struct cdrom_info *cd)
+    buffers. */
+ static void cdrom_saw_media_change (ide_drive_t *drive)
+ {
+-	struct cdrom_info *info = drive->driver_data;
+-	
+-	CDROM_STATE_FLAGS (drive)->media_changed = 1;
+-	CDROM_STATE_FLAGS (drive)->toc_valid = 0;
+-	info->nsectors_buffered = 0;
++	struct cdrom_info *cd = drive->driver_data;
++
++	cd->cd_flags |= IDE_CD_FLAG_MEDIA_CHANGED;
++	cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
++	cd->nsectors_buffered = 0;
+ }
+ 
+ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
+@@ -465,134 +190,14 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
+ 			}
+  		}
+  	}
+-#if VERBOSE_IDE_CD_ERRORS
+-	{
+-		int i;
+-		const char *s = "bad sense key!";
+-		char buf[80];
+-
+-		printk ("ATAPI device %s:\n", drive->name);
+-		if (sense->error_code==0x70)
+-			printk("  Error: ");
+-		else if (sense->error_code==0x71)
+-			printk("  Deferred Error: ");
+-		else if (sense->error_code == 0x7f)
+-			printk("  Vendor-specific Error: ");
+-		else
+-			printk("  Unknown Error Type: ");
+-
+-		if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
+-			s = sense_key_texts[sense->sense_key];
+-
+-		printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
+-
+-		if (sense->asc == 0x40) {
+-			sprintf(buf, "Diagnostic failure on component 0x%02x",
+-				 sense->ascq);
+-			s = buf;
+-		} else {
+-			int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
+-			unsigned long key = (sense->sense_key << 16);
+-			key |= (sense->asc << 8);
+-			if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
+-				key |= sense->ascq;
+-			s = NULL;
+-
+-			while (hi > lo) {
+-				mid = (lo + hi) / 2;
+-				if (sense_data_texts[mid].asc_ascq == key ||
+-				    sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
+-					s = sense_data_texts[mid].text;
+-					break;
+-				}
+-				else if (sense_data_texts[mid].asc_ascq > key)
+-					hi = mid;
+-				else
+-					lo = mid+1;
+-			}
+-		}
+-
+-		if (s == NULL) {
+-			if (sense->asc > 0x80)
+-				s = "(vendor-specific error)";
+-			else
+-				s = "(reserved error code)";
+-		}
+-
+-		printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+-			s, sense->asc, sense->ascq);
+-
+-		if (failed_command != NULL) {
+-
+-			int lo=0, mid, hi= ARRAY_SIZE(packet_command_texts);
+-			s = NULL;
+-
+-			while (hi > lo) {
+-				mid = (lo + hi) / 2;
+-				if (packet_command_texts[mid].packet_command ==
+-				    failed_command->cmd[0]) {
+-					s = packet_command_texts[mid].text;
+-					break;
+-				}
+-				if (packet_command_texts[mid].packet_command >
+-				    failed_command->cmd[0])
+-					hi = mid;
+-				else
+-					lo = mid+1;
+-			}
+-
+-			printk (KERN_ERR "  The failed \"%s\" packet command was: \n  \"", s);
+-			for (i=0; i<sizeof (failed_command->cmd); i++)
+-				printk ("%02x ", failed_command->cmd[i]);
+-			printk ("\"\n");
+-		}
+-
+-		/* The SKSV bit specifies validity of the sense_key_specific
+-		 * in the next two commands. It is bit 7 of the first byte.
+-		 * In the case of NOT_READY, if SKSV is set the drive can
+-		 * give us nice ETA readings.
+-		 */
+-		if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
+-			int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
+-			printk(KERN_ERR "  Command is %02d%% complete\n", progress / 0xffff);
+-
+-		}
+-
+-		if (sense->sense_key == ILLEGAL_REQUEST &&
+-		    (sense->sks[0] & 0x80) != 0) {
+-			printk(KERN_ERR "  Error in %s byte %d",
+-				(sense->sks[0] & 0x40) != 0 ?
+-				"command packet" : "command data",
+-				(sense->sks[1] << 8) + sense->sks[2]);
+ 
+-			if ((sense->sks[0] & 0x40) != 0)
+-				printk (" bit %d", sense->sks[0] & 0x07);
+-
+-			printk ("\n");
+-		}
+-	}
+-
+-#else /* not VERBOSE_IDE_CD_ERRORS */
+-
+-	/* Suppress printing unit attention and `in progress of becoming ready'
+-	   errors when we're not being verbose. */
+-
+-	if (sense->sense_key == UNIT_ATTENTION ||
+-	    (sense->sense_key == NOT_READY && (sense->asc == 4 ||
+-						sense->asc == 0x3a)))
+-		return;
+-
+-	printk(KERN_ERR "%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
+-		drive->name,
+-		sense->error_code, sense->sense_key,
+-		sense->asc, sense->ascq);
+-#endif /* not VERBOSE_IDE_CD_ERRORS */
++	ide_cd_log_error(drive->name, failed_command, sense);
+ }
+ 
+ /*
+  * Initialize a ide-cd packet command request
+  */
+-static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
++void ide_cd_init_rq(ide_drive_t *drive, struct request *rq)
+ {
+ 	struct cdrom_info *cd = drive->driver_data;
+ 
+@@ -611,7 +216,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
+ 		sense = &info->sense_data;
+ 
+ 	/* stuff the sense request in front of our current request */
+-	cdrom_prepare_request(drive, rq);
++	ide_cd_init_rq(drive, rq);
+ 
+ 	rq->data = sense;
+ 	rq->cmd[0] = GPCMD_REQUEST_SENSE;
+@@ -655,9 +260,9 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
  					BUG();
  			} else {
  				spin_lock_irqsave(&ide_lock, flags);
@@ -386717,7 +397704,86 @@
  				spin_unlock_irqrestore(&ide_lock, flags);
  			}
  		} else
-@@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
+@@ -718,7 +323,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+ 
+ 	} else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
+ 		/* All other functions, except for READ. */
+-		unsigned long flags;
+ 
+ 		/*
+ 		 * if we have an error, pass back CHECK_CONDITION as the
+@@ -756,15 +360,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+ 		 * remove failed request completely and end it when the
+ 		 * request sense has completed
+ 		 */
+-		if (stat & ERR_STAT) {
+-			spin_lock_irqsave(&ide_lock, flags);
+-			blkdev_dequeue_request(rq);
+-			HWGROUP(drive)->rq = NULL;
+-			spin_unlock_irqrestore(&ide_lock, flags);
+-
+-			cdrom_queue_request_sense(drive, rq->sense, rq);
+-		} else
+-			cdrom_end_request(drive, 0);
++		goto end_request;
+ 
+ 	} else if (blk_fs_request(rq)) {
+ 		int do_end_request = 0;
+@@ -844,23 +440,15 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+ 		   sense data. We need this in order to perform end of media
+ 		   processing */
+ 
+-		if (do_end_request) {
+-			if (stat & ERR_STAT) {
+-				unsigned long flags;
+-				spin_lock_irqsave(&ide_lock, flags);
+-				blkdev_dequeue_request(rq);
+-				HWGROUP(drive)->rq = NULL;
+-				spin_unlock_irqrestore(&ide_lock, flags);
++		if (do_end_request)
++			goto end_request;
+ 
+-				cdrom_queue_request_sense(drive, rq->sense, rq);
+-			} else
+-				cdrom_end_request(drive, 0);
+-		} else {
+-			/* If we got a CHECK_CONDITION status,
+-			   queue a request sense command. */
+-			if (stat & ERR_STAT)
+-				cdrom_queue_request_sense(drive, NULL, NULL);
+-		}
++		/*
++		 * If we got a CHECK_CONDITION status,
++		 * queue a request sense command.
++		 */
++		if (stat & ERR_STAT)
++			cdrom_queue_request_sense(drive, NULL, NULL);
+ 	} else {
+ 		blk_dump_rq_flags(rq, "ide-cd: bad rq");
+ 		cdrom_end_request(drive, 0);
+@@ -868,6 +456,21 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+ 
+ 	/* Retry, or handle the next request. */
+ 	return 1;
++
++end_request:
++	if (stat & ERR_STAT) {
++		unsigned long flags;
++
++		spin_lock_irqsave(&ide_lock, flags);
++		blkdev_dequeue_request(rq);
++		HWGROUP(drive)->rq = NULL;
++		spin_unlock_irqrestore(&ide_lock, flags);
++
++		cdrom_queue_request_sense(drive, rq->sense, rq);
++	} else
++		cdrom_end_request(drive, 0);
++
++	return 1;
+ }
+ 
+ static int cdrom_timer_expiry(ide_drive_t *drive)
+@@ -917,21 +520,15 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
  	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
  		return startstop;
  
@@ -386735,157 +397801,4011 @@
 -	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
 -	if (IDE_CONTROL_REG)
 -		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+- 
+-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 +	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
 +			   IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
-  
- 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
++
++	if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
  		/* waiting for CDB interrupt, not DMA yet. */
-@@ -1653,6 +1647,17 @@ static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
- 	return 1;
- }
+ 		if (info->dma)
+ 			drive->waiting_for_dma = 0;
+@@ -957,10 +554,6 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
+    by cdrom_start_packet_command.
+    HANDLER is the interrupt handler to call when the command completes
+    or there's data ready. */
+-/*
+- * changed 5 parameters to 3 for dvd-ram
+- * struct packet_command *pc; now packet_command_t *pc;
+- */
+ #define ATAPI_MIN_CDB_BYTES 12
+ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+ 					  struct request *rq,
+@@ -971,7 +564,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+ 	struct cdrom_info *info = drive->driver_data;
+ 	ide_startstop_t startstop;
  
-+/*
-+ * Called from blk_end_request_callback() after the data of the request
-+ * is completed and before the request is completed.
-+ * By returning value '1', blk_end_request_callback() returns immediately
-+ * without completing the request.
-+ */
-+static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+-	if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) {
++	if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
+ 		/* Here we should have been called after receiving an interrupt
+ 		   from the device.  DRQ should how be set. */
+ 
+@@ -1011,6 +604,27 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+  * Block read functions.
+  */
+ 
++typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
++
++static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
 +{
-+	return 1;
++	while (len > 0) {
++		int dum = 0;
++		xf(drive, &dum, sizeof(dum));
++		len -= sizeof(dum);
++	}
 +}
 +
- typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
- 
- /*
-@@ -1691,9 +1696,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
- 			return ide_error(drive, "dma error", stat);
- 		}
- 
--		end_that_request_chunk(rq, 1, rq->data_len);
--		rq->data_len = 0;
--		goto end_request;
-+		spin_lock_irqsave(&ide_lock, flags);
-+		if (__blk_end_request(rq, 0, rq->data_len))
-+			BUG();
-+		HWGROUP(drive)->rq = NULL;
-+		spin_unlock_irqrestore(&ide_lock, flags);
++static void ide_cd_drain_data(ide_drive_t *drive, int nsects)
++{
++	while (nsects > 0) {
++		static char dum[SECTOR_SIZE];
++
++		drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum));
++		nsects--;
++	}
++}
 +
-+		return ide_stopped;
+ /*
+  * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
+  * buffer.  Once the first sector is added, any subsequent sectors are
+@@ -1049,11 +663,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  	}
  
- 	/*
-@@ -1711,8 +1720,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
- 	/*
- 	 * If DRQ is clear, the command has completed.
- 	 */
--	if ((stat & DRQ_STAT) == 0)
--		goto end_request;
-+	if ((stat & DRQ_STAT) == 0) {
-+		spin_lock_irqsave(&ide_lock, flags);
-+		if (__blk_end_request(rq, 0, 0))
-+			BUG();
-+		HWGROUP(drive)->rq = NULL;
-+		spin_unlock_irqrestore(&ide_lock, flags);
-+
-+		return ide_stopped;
-+	}
+ 	/* Throw away any remaining data. */
+-	while (sectors_to_transfer > 0) {
+-		static char dum[SECTOR_SIZE];
+-		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
+-		--sectors_to_transfer;
+-	}
++	ide_cd_drain_data(drive, sectors_to_transfer);
+ }
  
- 	/*
- 	 * check which way to transfer data
-@@ -1765,7 +1781,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
- 		rq->data_len -= blen;
+ /*
+@@ -1062,23 +672,25 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
+  * ok; nonzero if the request has been terminated.
+  */
+ static
+-int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
++int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
+ {
+-	if (ireason == 2)
++	/*
++	 * ireason == 0: the drive wants to receive data from us
++	 * ireason == 2: the drive is expecting to transfer data to us
++	 */
++	if (ireason == (!rw << 1))
+ 		return 0;
+-	else if (ireason == 0) {
+-		/* Whoops... The drive is expecting to receive data from us! */
++	else if (ireason == (rw << 1)) {
++		ide_hwif_t *hwif = drive->hwif;
++		xfer_func_t *xf;
++
++		/* Whoops... */
+ 		printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
+ 				drive->name, __FUNCTION__);
+ 
+-		/* Throw some data at the drive so it doesn't hang
+-		   and quit this request. */
+-		while (len > 0) {
+-			int dum = 0;
+-			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
+-			len -= sizeof (dum);
+-		}
+-	} else  if (ireason == 1) {
++		xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes;
++		ide_cd_pad_transfer(drive, xf, len);
++	} else  if (rw == 0 && ireason == 1) {
+ 		/* Some drives (ASUS) seem to tell us that status
+ 		 * info is available. just get it and ignore.
+ 		 */
+@@ -1095,137 +707,28 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
+ }
  
- 		if (rq->bio)
--			end_that_request_chunk(rq, 1, blen);
-+			/*
-+			 * The request can't be completed until DRQ is cleared.
-+			 * So complete the data, but don't complete the request
-+			 * using the dummy function for the callback feature
-+			 * of blk_end_request_callback().
-+			 */
-+			blk_end_request_callback(rq, 0, blen,
-+						 cdrom_newpc_intr_dummy_cb);
- 		else
- 			rq->data += blen;
+ /*
+- * Interrupt routine.  Called when a read request has completed.
++ * Assume that the drive will always provide data in multiples of at least
++ * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
+  */
+-static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
++static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
+ {
+-	int stat;
+-	int ireason, len, sectors_to_transfer, nskip;
+-	struct cdrom_info *info = drive->driver_data;
+-	u8 lowcyl = 0, highcyl = 0;
+-	int dma = info->dma, dma_error = 0;
+-
+-	struct request *rq = HWGROUP(drive)->rq;
+-
+-	/*
+-	 * handle dma case
+-	 */
+-	if (dma) {
+-		info->dma = 0;
+-		dma_error = HWIF(drive)->ide_dma_end(drive);
+-		if (dma_error) {
+-			printk(KERN_ERR "%s: DMA read error\n", drive->name);
+-			ide_dma_off(drive);
+-		}
+-	}
+-
+-	if (cdrom_decode_status(drive, 0, &stat))
+-		return ide_stopped;
+-
+-	if (dma) {
+-		if (!dma_error) {
+-			ide_end_request(drive, 1, rq->nr_sectors);
+-			return ide_stopped;
+-		} else
+-			return ide_error(drive, "dma error", stat);
+-	}
+-
+-	/* Read the interrupt reason and the transfer length. */
+-	ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
+-	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+-	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+-
+-	len = lowcyl + (256 * highcyl);
+-
+-	/* If DRQ is clear, the command has completed. */
+-	if ((stat & DRQ_STAT) == 0) {
+-		/* If we're not done filling the current buffer, complain.
+-		   Otherwise, complete the command normally. */
+-		if (rq->current_nr_sectors > 0) {
+-			printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
+-				drive->name, rq->current_nr_sectors);
+-			rq->cmd_flags |= REQ_FAILED;
+-			cdrom_end_request(drive, 0);
+-		} else
+-			cdrom_end_request(drive, 1);
+-		return ide_stopped;
+-	}
+-
+-	/* Check that the drive is expecting to do the same thing we are. */
+-	if (cdrom_read_check_ireason (drive, len, ireason))
+-		return ide_stopped;
+-
+-	/* Assume that the drive will always provide data in multiples
+-	   of at least SECTOR_SIZE, as it gets hairy to keep track
+-	   of the transfers otherwise. */
+-	if ((len % SECTOR_SIZE) != 0) {
+-		printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n",
+-			drive->name, len);
+-		if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
+-			printk (KERN_ERR "  This drive is not supported by this version of the driver\n");
+-		else {
+-			printk (KERN_ERR "  Trying to limit transfer sizes\n");
+-			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+-		}
+-		cdrom_end_request(drive, 0);
+-		return ide_stopped;
+-	}
+-
+-	/* The number of sectors we need to read from the drive. */
+-	sectors_to_transfer = len / SECTOR_SIZE;
+-
+-	/* First, figure out if we need to bit-bucket
+-	   any of the leading sectors. */
+-	nskip = min_t(int, rq->current_nr_sectors - bio_cur_sectors(rq->bio), sectors_to_transfer);
+-
+-	while (nskip > 0) {
+-		/* We need to throw away a sector. */
+-		static char dum[SECTOR_SIZE];
+-		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
+-
+-		--rq->current_nr_sectors;
+-		--nskip;
+-		--sectors_to_transfer;
+-	}
++	struct cdrom_info *cd = drive->driver_data;
+ 
+-	/* Now loop while we still have data to read from the drive. */
+-	while (sectors_to_transfer > 0) {
+-		int this_transfer;
++	if ((len % SECTOR_SIZE) == 0)
++		return 0;
+ 
+-		/* If we've filled the present buffer but there's another
+-		   chained buffer after it, move on. */
+-		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+-			cdrom_end_request(drive, 1);
++	printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
++			drive->name, __FUNCTION__, len);
+ 
+-		/* If the buffers are full, cache the rest of the data in our
+-		   internal buffer. */
+-		if (rq->current_nr_sectors == 0) {
+-			cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
+-			sectors_to_transfer = 0;
+-		} else {
+-			/* Transfer data to the buffers.
+-			   Figure out how many sectors we can transfer
+-			   to the current buffer. */
+-			this_transfer = min_t(int, sectors_to_transfer,
+-					     rq->current_nr_sectors);
+-
+-			/* Read this_transfer sectors
+-			   into the current buffer. */
+-			while (this_transfer > 0) {
+-				HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+-				rq->buffer += SECTOR_SIZE;
+-				--rq->nr_sectors;
+-				--rq->current_nr_sectors;
+-				++rq->sector;
+-				--this_transfer;
+-				--sectors_to_transfer;
+-			}
+-		}
++	if (cd->cd_flags & IDE_CD_FLAG_LIMIT_NFRAMES)
++		printk(KERN_ERR "  This drive is not supported by "
++				"this version of the driver\n");
++	else {
++		printk(KERN_ERR "  Trying to limit transfer sizes\n");
++		cd->cd_flags |= IDE_CD_FLAG_LIMIT_NFRAMES;
  	}
-@@ -1786,14 +1809,6 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
  
- 	ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
- 	return ide_started;
--
--end_request:
--	spin_lock_irqsave(&ide_lock, flags);
--	blkdev_dequeue_request(rq);
--	end_that_request_last(rq, 1);
--	HWGROUP(drive)->rq = NULL;
--	spin_unlock_irqrestore(&ide_lock, flags);
--	return ide_stopped;
+-	/* Done moving data!  Wait for another interrupt. */
+-	ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL);
+-	return ide_started;
++	return 1;
  }
  
- static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
-diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
-index b178190..717e114 100644
---- a/drivers/ide/ide-disk.c
-+++ b/drivers/ide/ide-disk.c
-@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
- 	return 0;	/* lba_capacity value may be bad */
+ /*
+@@ -1287,48 +790,58 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
+ 	return 0;
  }
  
-+static const u8 ide_rw_cmds[] = {
-+	WIN_MULTREAD,
-+	WIN_MULTWRITE,
-+	WIN_MULTREAD_EXT,
-+	WIN_MULTWRITE_EXT,
-+	WIN_READ,
-+	WIN_WRITE,
-+	WIN_READ_EXT,
-+	WIN_WRITE_EXT,
-+	WIN_READDMA,
-+	WIN_WRITEDMA,
-+	WIN_READDMA_EXT,
-+	WIN_WRITEDMA_EXT,
-+};
-+
-+static const u8 ide_data_phases[] = {
-+	TASKFILE_MULTI_IN,
-+	TASKFILE_MULTI_OUT,
-+	TASKFILE_IN,
-+	TASKFILE_OUT,
-+	TASKFILE_IN_DMA,
-+	TASKFILE_OUT_DMA,
-+};
-+
-+static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
-+{
-+	u8 index, lba48, write;
-+
-+	lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
-+	write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
-+
-+	if (dma)
-+		index = drive->vdma ? 4 : 8;
-+	else
-+		index = drive->mult_count ? 0 : 4;
-+
-+	task->tf.command = ide_rw_cmds[index + lba48 + write];
-+
-+	if (dma)
-+		index = 8; /* fixup index */
-+
-+	task->data_phase = ide_data_phases[index / 2 + write];
-+}
++static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
 +
  /*
-  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
-  * using LBA if supported, or CHS otherwise, to address sectors.
-@@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+- * Routine to send a read packet command to the drive.
+- * This is usually called directly from cdrom_start_read.
++ * Routine to send a read/write packet command to the drive.
++ * This is usually called directly from cdrom_start_{read,write}().
+  * However, for drq_interrupt devices, it is called from an interrupt
+  * when the drive is ready to accept the command.
+  */
+-static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
++static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
  {
- 	ide_hwif_t *hwif	= HWIF(drive);
- 	unsigned int dma	= drive->using_dma;
-+	u16 nsectors		= (u16)rq->nr_sectors;
- 	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
--	task_ioreg_t command	= WIN_NOP;
+ 	struct request *rq = HWGROUP(drive)->rq;
+-	unsigned short sectors_per_frame;
+-	int nskip;
+ 
+-	sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
++	if (rq_data_dir(rq) == READ) {
++		unsigned short sectors_per_frame =
++			queue_hardsect_size(drive->queue) >> SECTOR_BITS;
++		int nskip = rq->sector & (sectors_per_frame - 1);
+ 
+-	/* If the requested sector doesn't start on a cdrom block boundary,
+-	   we must adjust the start of the transfer so that it does,
+-	   and remember to skip the first few sectors.
+-	   If the CURRENT_NR_SECTORS field is larger than the size
+-	   of the buffer, it will mean that we're to skip a number
+-	   of sectors equal to the amount by which CURRENT_NR_SECTORS
+-	   is larger than the buffer size. */
+-	nskip = rq->sector & (sectors_per_frame - 1);
+-	if (nskip > 0) {
+-		/* Sanity check... */
+-		if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&
+-			(rq->sector & (sectors_per_frame - 1))) {
+-			printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n",
+-				drive->name, rq->current_nr_sectors);
+-			cdrom_end_request(drive, 0);
+-			return ide_stopped;
++		/*
++		 * If the requested sector doesn't start on a frame boundary,
++		 * we must adjust the start of the transfer so that it does,
++		 * and remember to skip the first few sectors.
++		 *
++		 * If the rq->current_nr_sectors field is larger than the size
++		 * of the buffer, it will mean that we're to skip a number of
++		 * sectors equal to the amount by which rq->current_nr_sectors
++		 * is larger than the buffer size.
++		 */
++		if (nskip > 0) {
++			/* Sanity check... */
++			if (rq->current_nr_sectors !=
++			    bio_cur_sectors(rq->bio)) {
++				printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
++						drive->name, __FUNCTION__,
++						rq->current_nr_sectors);
++				cdrom_end_request(drive, 0);
++				return ide_stopped;
++			}
++			rq->current_nr_sectors += nskip;
+ 		}
+-		rq->current_nr_sectors += nskip;
+ 	}
+-
++#if 0
++	else
++		/* the immediate bit */
++		rq->cmd[1] = 1 << 3;
++#endif
+ 	/* Set up the command */
+ 	rq->timeout = ATAPI_WAIT_PC;
+ 
+ 	/* Send the command to the drive and return. */
+-	return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);
++	return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
+ }
+ 
+-
+ #define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */
+ #define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
+ #define IDECD_SEEK_TIMEOUT	(2 * WAIT_CMD)		/* 20 sec */
+@@ -1341,7 +854,8 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
+ 
+ 	if (cdrom_decode_status(drive, 0, &stat))
+ 		return ide_stopped;
+-	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
++
++	info->cd_flags |= IDE_CD_FLAG_SEEKING;
+ 
+ 	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
+ 		if (--retry == 0) {
+@@ -1397,184 +911,25 @@ static void restore_request (struct request *rq)
+ 	rq->q->prep_rq_fn(rq->q, rq);
+ }
+ 
+-/*
+- * Start a read request from the CD-ROM.
+- */
+-static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
+-{
+-	struct cdrom_info *info = drive->driver_data;
+-	struct request *rq = HWGROUP(drive)->rq;
+-	unsigned short sectors_per_frame;
+-
+-	sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+-
+-	/* We may be retrying this request after an error.  Fix up
+-	   any weirdness which might be present in the request packet. */
+-	restore_request(rq);
+-
+-	/* Satisfy whatever we can of this request from our cached sector. */
+-	if (cdrom_read_from_buffer(drive))
+-		return ide_stopped;
+-
+-	/* Clear the local sector buffer. */
+-	info->nsectors_buffered = 0;
+-
+-	/* use dma, if possible. */
+-	info->dma = drive->using_dma;
+-	if ((rq->sector & (sectors_per_frame - 1)) ||
+-	    (rq->nr_sectors & (sectors_per_frame - 1)))
+-		info->dma = 0;
+-
+-	/* Start sending the read request to the drive. */
+-	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
+-}
+-
+ /****************************************************************************
+  * Execute all other packet commands.
+  */
+ 
+-/* Interrupt routine for packet command completion. */
+-static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
++static void ide_cd_request_sense_fixup(struct request *rq)
+ {
+-	int ireason, len, thislen;
+-	struct request *rq = HWGROUP(drive)->rq;
+-	u8 lowcyl = 0, highcyl = 0;
+-	int stat;
+-
+-	/* Check for errors. */
+-	if (cdrom_decode_status(drive, 0, &stat))
+-		return ide_stopped;
+-
+-	/* Read the interrupt reason and the transfer length. */
+-	ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
+-	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+-	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+-
+-	len = lowcyl + (256 * highcyl);
+-
+-	/* If DRQ is clear, the command has completed.
+-	   Complain if we still have data left to transfer. */
+-	if ((stat & DRQ_STAT) == 0) {
+-		/* Some of the trailing request sense fields are optional, and
+-		   some drives don't send them.  Sigh. */
+-		if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+-		    rq->data_len > 0 &&
+-		    rq->data_len <= 5) {
+-			while (rq->data_len > 0) {
+-				*(unsigned char *)rq->data++ = 0;
+-				--rq->data_len;
+-			}
+-		}
+-
+-		if (rq->data_len == 0)
+-			cdrom_end_request(drive, 1);
+-		else {
+-			/* Comment this out, because this always happens 
+-			   right after a reset occurs, and it is annoying to 
+-			   always print expected stuff.  */
+-			/*
+-			printk ("%s: cdrom_pc_intr: data underrun %d\n",
+-				drive->name, pc->buflen);
+-			*/
+-			rq->cmd_flags |= REQ_FAILED;
+-			cdrom_end_request(drive, 0);
+-		}
+-		return ide_stopped;
+-	}
+-
+-	/* Figure out how much data to transfer. */
+-	thislen = rq->data_len;
+-	if (thislen > len) thislen = len;
+-
+-	/* The drive wants to be written to. */
+-	if (ireason == 0) {
+-		if (!rq->data) {
+-			blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
+-			goto confused;
+-		}
+-		/* Transfer the data. */
+-		HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
+-
+-		/* If we haven't moved enough data to satisfy the drive,
+-		   add some padding. */
+-		while (len > thislen) {
+-			int dum = 0;
+-			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+-			len -= sizeof(dum);
+-		}
+-
+-		/* Keep count of how much data we've moved. */
+-		rq->data += thislen;
+-		rq->data_len -= thislen;
+-	}
+-
+-	/* Same drill for reading. */
+-	else if (ireason == 2) {
+-		if (!rq->data) {
+-			blk_dump_rq_flags(rq, "cdrom_pc_intr, read");
+-			goto confused;
+-		}
+-		/* Transfer the data. */
+-		HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
+-
+-		/* If we haven't moved enough data to satisfy the drive,
+-		   add some padding. */
+-		while (len > thislen) {
+-			int dum = 0;
+-			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+-			len -= sizeof(dum);
++	/*
++	 * Some of the trailing request sense fields are optional,
++	 * and some drives don't send them.  Sigh.
++	 */
++	if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
++	    rq->data_len > 0 && rq->data_len <= 5)
++		while (rq->data_len > 0) {
++			*(u8 *)rq->data++ = 0;
++			--rq->data_len;
+ 		}
+-
+-		/* Keep count of how much data we've moved. */
+-		rq->data += thislen;
+-		rq->data_len -= thislen;
+-
+-		if (blk_sense_request(rq))
+-			rq->sense_len += thislen;
+-	} else {
+-confused:
+-		printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
+-			"appears confused (ireason = 0x%02x). "
+-			"Trying to recover by ending request.\n",
+-			drive->name, ireason);
+-		rq->cmd_flags |= REQ_FAILED;
+-		cdrom_end_request(drive, 0);
+-		return ide_stopped;
+-	}
+-
+-	/* Now we wait for another interrupt. */
+-	ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);
+-	return ide_started;
+ }
+ 
+-static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
+-{
+-	struct request *rq = HWGROUP(drive)->rq;
+-
+-	if (!rq->timeout)
+-		rq->timeout = ATAPI_WAIT_PC;
+-
+-	/* Send the command to the drive and return. */
+-	return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);
+-}
+-
+-
+-static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
+-{
+-	int len;
+-	struct request *rq = HWGROUP(drive)->rq;
+-	struct cdrom_info *info = drive->driver_data;
+-
+-	info->dma = 0;
+-	rq->cmd_flags &= ~REQ_FAILED;
+-	len = rq->data_len;
+-
+-	/* Start sending the command to the drive. */
+-	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
+-}
+-
+-
+-static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
++int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
+ {
+ 	struct request_sense sense;
+ 	int retries = 10;
+@@ -1623,59 +978,37 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+ }
+ 
+ /*
+- * Write handling
++ * Called from blk_end_request_callback() after the data of the request
++ * is completed and before the request is completed.
++ * By returning value '1', blk_end_request_callback() returns immediately
++ * without completing the request.
+  */
+-static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
++static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+ {
+-	/* Two notes about IDE interrupt reason here - 0 means that
+-	 * the drive wants to receive data from us, 2 means that
+-	 * the drive is expecting to transfer data to us.
+-	 */
+-	if (ireason == 0)
+-		return 0;
+-	else if (ireason == 2) {
+-		/* Whoops... The drive wants to send data. */
+-		printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
+-				drive->name, __FUNCTION__);
+-
+-		while (len > 0) {
+-			int dum = 0;
+-			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+-			len -= sizeof(dum);
+-		}
+-	} else {
+-		/* Drive wants a command packet, or invalid ireason... */
+-		printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
+-				drive->name, __FUNCTION__, ireason);
+-	}
+-
+-	cdrom_end_request(drive, 0);
+ 	return 1;
+ }
+ 
+-typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+-
+-/*
+- * best way to deal with dma that is not sector aligned right now... note
+- * that in this path we are not using ->data or ->buffer at all. this irs
+- * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the
+- * future.
+- */
+ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ {
+ 	struct cdrom_info *info = drive->driver_data;
+ 	struct request *rq = HWGROUP(drive)->rq;
+-	int dma_error, dma, stat, ireason, len, thislen;
+-	u8 lowcyl, highcyl;
+ 	xfer_func_t *xferfunc;
+-	unsigned long flags;
++	ide_expiry_t *expiry = NULL;
++	int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0;
++	int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
++	unsigned int timeout;
++	u8 lowcyl, highcyl;
+ 
+ 	/* Check for errors. */
+-	dma_error = 0;
+ 	dma = info->dma;
+ 	if (dma) {
+ 		info->dma = 0;
+ 		dma_error = HWIF(drive)->ide_dma_end(drive);
++		if (dma_error) {
++			printk(KERN_ERR "%s: DMA %s error\n", drive->name,
++					write ? "write" : "read");
++			ide_dma_off(drive);
++		}
+ 	}
+ 
+ 	if (cdrom_decode_status(drive, 0, &stat))
+@@ -1685,14 +1018,12 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 	 * using dma, transfer is complete now
+ 	 */
+ 	if (dma) {
+-		if (dma_error) {
+-			printk(KERN_ERR "ide-cd: dma error\n");
+-			ide_dma_off(drive);
++		if (dma_error)
+ 			return ide_error(drive, "dma error", stat);
++		if (blk_fs_request(rq)) {
++			ide_end_request(drive, 1, rq->nr_sectors);
++			return ide_stopped;
+ 		}
+-
+-		end_that_request_chunk(rq, 1, rq->data_len);
+-		rq->data_len = 0;
+ 		goto end_request;
+ 	}
+ 
+@@ -1704,54 +1035,120 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+ 
+ 	len = lowcyl + (256 * highcyl);
+-	thislen = rq->data_len;
++
++	thislen = blk_fs_request(rq) ? len : rq->data_len;
+ 	if (thislen > len)
+ 		thislen = len;
+ 
+ 	/*
+ 	 * If DRQ is clear, the command has completed.
+ 	 */
+-	if ((stat & DRQ_STAT) == 0)
++	if ((stat & DRQ_STAT) == 0) {
++		if (blk_fs_request(rq)) {
++			/*
++			 * If we're not done reading/writing, complain.
++			 * Otherwise, complete the command normally.
++			 */
++			uptodate = 1;
++			if (rq->current_nr_sectors > 0) {
++				printk(KERN_ERR "%s: %s: data underrun "
++						"(%d blocks)\n",
++						drive->name, __FUNCTION__,
++						rq->current_nr_sectors);
++				if (!write)
++					rq->cmd_flags |= REQ_FAILED;
++				uptodate = 0;
++			}
++			cdrom_end_request(drive, uptodate);
++			return ide_stopped;
++		} else if (!blk_pc_request(rq)) {
++			ide_cd_request_sense_fixup(rq);
++			/* Complain if we still have data left to transfer. */
++			uptodate = rq->data_len ? 0 : 1;
++		}
+ 		goto end_request;
++	}
+ 
+ 	/*
+ 	 * check which way to transfer data
+ 	 */
+-	if (rq_data_dir(rq) == WRITE) {
+-		/*
+-		 * write to drive
+-		 */
+-		if (cdrom_write_check_ireason(drive, len, ireason))
++	if (blk_fs_request(rq) || blk_pc_request(rq)) {
++		if (ide_cd_check_ireason(drive, len, ireason, write))
+ 			return ide_stopped;
+ 
+-		xferfunc = HWIF(drive)->atapi_output_bytes;
+-	} else  {
+-		/*
+-		 * read from drive
+-		 */
+-		if (cdrom_read_check_ireason(drive, len, ireason))
+-			return ide_stopped;
++		if (blk_fs_request(rq) && write == 0) {
++			int nskip;
++
++			if (ide_cd_check_transfer_size(drive, len)) {
++				cdrom_end_request(drive, 0);
++				return ide_stopped;
++			}
+ 
++			/*
++			 * First, figure out if we need to bit-bucket
++			 * any of the leading sectors.
++			 */
++			nskip = min_t(int, rq->current_nr_sectors
++					   - bio_cur_sectors(rq->bio),
++					   thislen >> 9);
++			if (nskip > 0) {
++				ide_cd_drain_data(drive, nskip);
++				rq->current_nr_sectors -= nskip;
++				thislen -= (nskip << 9);
++			}
++		}
++	}
++
++	if (ireason == 0) {
++		write = 1;
++		xferfunc = HWIF(drive)->atapi_output_bytes;
++	} else if (ireason == 2 || (ireason == 1 &&
++		   (blk_fs_request(rq) || blk_pc_request(rq)))) {
++		write = 0;
+ 		xferfunc = HWIF(drive)->atapi_input_bytes;
++	} else {
++		printk(KERN_ERR "%s: %s: The drive "
++				"appears confused (ireason = 0x%02x). "
++				"Trying to recover by ending request.\n",
++				drive->name, __FUNCTION__, ireason);
++		goto end_request;
+ 	}
+ 
+ 	/*
+ 	 * transfer data
+ 	 */
+ 	while (thislen > 0) {
+-		int blen = blen = rq->data_len;
+-		char *ptr = rq->data;
++		u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
++		int blen = rq->data_len;
+ 
+ 		/*
+ 		 * bio backed?
+ 		 */
+ 		if (rq->bio) {
+-			ptr = bio_data(rq->bio);
+-			blen = bio_iovec(rq->bio)->bv_len;
++			if (blk_fs_request(rq)) {
++				ptr = rq->buffer;
++				blen = rq->current_nr_sectors << 9;
++			} else {
++				ptr = bio_data(rq->bio);
++				blen = bio_iovec(rq->bio)->bv_len;
++			}
+ 		}
+ 
+ 		if (!ptr) {
+-			printk(KERN_ERR "%s: confused, missing data\n", drive->name);
++			if (blk_fs_request(rq) && !write)
++				/*
++				 * If the buffers are full, cache the rest
++				 * of the data in our internal buffer.
++				 */
++				cdrom_buffer_sectors(drive, rq->sector,
++						     thislen >> 9);
++			else {
++				printk(KERN_ERR "%s: confused, missing data\n",
++						drive->name);
++				blk_dump_rq_flags(rq, rq_data_dir(rq)
++						  ? "cdrom_newpc_intr, write"
++						  : "cdrom_newpc_intr, read");
++			}
+ 			break;
+ 		}
+ 
+@@ -1762,186 +1159,117 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+ 
+ 		thislen -= blen;
+ 		len -= blen;
+-		rq->data_len -= blen;
+-
+-		if (rq->bio)
+-			end_that_request_chunk(rq, 1, blen);
+-		else
+-			rq->data += blen;
+-	}
+-
+-	/*
+-	 * pad, if necessary
+-	 */
+-	if (len > 0) {
+-		while (len > 0) {
+-			int pad = 0;
+ 
+-			xferfunc(drive, &pad, sizeof(pad));
+-			len -= sizeof(pad);
+-		}
+-	}
+-
+-	BUG_ON(HWGROUP(drive)->handler != NULL);
+-
+-	ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
+-	return ide_started;
+-
+-end_request:
+-	spin_lock_irqsave(&ide_lock, flags);
+-	blkdev_dequeue_request(rq);
+-	end_that_request_last(rq, 1);
+-	HWGROUP(drive)->rq = NULL;
+-	spin_unlock_irqrestore(&ide_lock, flags);
+-	return ide_stopped;
+-}
+-
+-static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+-{
+-	int stat, ireason, len, sectors_to_transfer, uptodate;
+-	struct cdrom_info *info = drive->driver_data;
+-	int dma_error = 0, dma = info->dma;
+-	u8 lowcyl = 0, highcyl = 0;
++		if (blk_fs_request(rq)) {
++			rq->buffer += blen;
++			rq->nr_sectors -= (blen >> 9);
++			rq->current_nr_sectors -= (blen >> 9);
++			rq->sector += (blen >> 9);
+ 
+-	struct request *rq = HWGROUP(drive)->rq;
++			if (rq->current_nr_sectors == 0 && rq->nr_sectors)
++				cdrom_end_request(drive, 1);
++		} else {
++			rq->data_len -= blen;
+ 
+-	/* Check for errors. */
+-	if (dma) {
+-		info->dma = 0;
+-		dma_error = HWIF(drive)->ide_dma_end(drive);
+-		if (dma_error) {
+-			printk(KERN_ERR "%s: DMA write error\n", drive->name);
+-			ide_dma_off(drive);
++			/*
++			 * The request can't be completed until DRQ is cleared.
++			 * So complete the data, but don't complete the request
++			 * using the dummy function for the callback feature
++			 * of blk_end_request_callback().
++			 */
++			if (rq->bio)
++				blk_end_request_callback(rq, 0, blen,
++						 cdrom_newpc_intr_dummy_cb);
++			else
++				rq->data += blen;
+ 		}
+ 	}
+ 
+-	if (cdrom_decode_status(drive, 0, &stat))
+-		return ide_stopped;
++	if (write && blk_sense_request(rq))
++		rq->sense_len += thislen;
+ 
+ 	/*
+-	 * using dma, transfer is complete now
++	 * pad, if necessary
+ 	 */
+-	if (dma) {
+-		if (dma_error)
+-			return ide_error(drive, "dma error", stat);
++	if (!blk_fs_request(rq) && len > 0)
++		ide_cd_pad_transfer(drive, xferfunc, len);
+ 
+-		ide_end_request(drive, 1, rq->nr_sectors);
+-		return ide_stopped;
++	if (blk_pc_request(rq)) {
++		timeout = rq->timeout;
++	} else {
++		timeout = ATAPI_WAIT_PC;
++		if (!blk_fs_request(rq))
++			expiry = cdrom_timer_expiry;
+ 	}
+ 
+-	/* Read the interrupt reason and the transfer length. */
+-	ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
+-	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+-	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
++	ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
++	return ide_started;
+ 
+-	len = lowcyl + (256 * highcyl);
++end_request:
++	if (blk_pc_request(rq)) {
++		unsigned long flags;
+ 
+-	/* If DRQ is clear, the command has completed. */
+-	if ((stat & DRQ_STAT) == 0) {
+-		/* If we're not done writing, complain.
+-		 * Otherwise, complete the command normally.
+-		 */
+-		uptodate = 1;
+-		if (rq->current_nr_sectors > 0) {
+-			printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n",
+-					drive->name, __FUNCTION__,
+-					rq->current_nr_sectors);
+-			uptodate = 0;
+-		}
++		spin_lock_irqsave(&ide_lock, flags);
++		if (__blk_end_request(rq, 0, rq->data_len))
++			BUG();
++		HWGROUP(drive)->rq = NULL;
++		spin_unlock_irqrestore(&ide_lock, flags);
++	} else {
++		if (!uptodate)
++			rq->cmd_flags |= REQ_FAILED;
+ 		cdrom_end_request(drive, uptodate);
+-		return ide_stopped;
+ 	}
++	return ide_stopped;
++}
+ 
+-	/* Check that the drive is expecting to do the same thing we are. */
+-	if (cdrom_write_check_ireason(drive, len, ireason))
+-		return ide_stopped;
+-
+-	sectors_to_transfer = len / SECTOR_SIZE;
+-
+-	/*
+-	 * now loop and write out the data
+-	 */
+-	while (sectors_to_transfer > 0) {
+-		int this_transfer;
+-
+-		if (!rq->current_nr_sectors) {
+-			printk(KERN_ERR "%s: %s: confused, missing data\n",
+-					drive->name, __FUNCTION__);
+-			break;
+-		}
++static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
++{
++	struct cdrom_info *cd = drive->driver_data;
++	int write = rq_data_dir(rq) == WRITE;
++	unsigned short sectors_per_frame =
++		queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+ 
++	if (write) {
+ 		/*
+-		 * Figure out how many sectors we can transfer
++		 * disk has become write protected
+ 		 */
+-		this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors);
+-
+-		while (this_transfer > 0) {
+-			HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+-			rq->buffer += SECTOR_SIZE;
+-			--rq->nr_sectors;
+-			--rq->current_nr_sectors;
+-			++rq->sector;
+-			--this_transfer;
+-			--sectors_to_transfer;
++		if (cd->disk->policy) {
++			cdrom_end_request(drive, 0);
++			return ide_stopped;
+ 		}
+-
++	} else {
+ 		/*
+-		 * current buffer complete, move on
++		 * We may be retrying this request after an error.  Fix up any
++		 * weirdness which might be present in the request packet.
+ 		 */
+-		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+-			cdrom_end_request(drive, 1);
+-	}
+-
+-	/* re-arm handler */
+-	ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL);
+-	return ide_started;
+-}
+-
+-static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
+-{
+-	struct request *rq = HWGROUP(drive)->rq;
++		restore_request(rq);
+ 
+-#if 0	/* the immediate bit */
+-	rq->cmd[1] = 1 << 3;
+-#endif
+-	rq->timeout = ATAPI_WAIT_PC;
+-
+-	return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
+-}
+-
+-static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
+-{
+-	struct cdrom_info *info = drive->driver_data;
+-	struct gendisk *g = info->disk;
+-	unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
++		/* Satisfy whatever we can of this request from our cache. */
++		if (cdrom_read_from_buffer(drive))
++			return ide_stopped;
++	}
+ 
+ 	/*
+-	 * writes *must* be hardware frame aligned
++	 * use DMA, if possible / writes *must* be hardware frame aligned
+ 	 */
+ 	if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
+ 	    (rq->sector & (sectors_per_frame - 1))) {
+-		cdrom_end_request(drive, 0);
+-		return ide_stopped;
+-	}
+-
+-	/*
+-	 * disk has become write protected
+-	 */
+-	if (g->policy) {
+-		cdrom_end_request(drive, 0);
+-		return ide_stopped;
+-	}
+-
+-	info->nsectors_buffered = 0;
++		if (write) {
++			cdrom_end_request(drive, 0);
++			return ide_stopped;
++		}
++		cd->dma = 0;
++	} else
++		cd->dma = drive->using_dma;
+ 
+-	/* use dma, if possible. we don't need to check more, since we
+-	 * know that the transfer is always (at least!) frame aligned */
+-	info->dma = drive->using_dma ? 1 : 0;
++	/* Clear the local sector buffer. */
++	cd->nsectors_buffered = 0;
+ 
+-	info->devinfo.media_written = 1;
++	if (write)
++		cd->devinfo.media_written = 1;
+ 
+-	/* Start sending the write request to the drive. */
+-	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
++	/* Start sending the read/write request to the drive. */
++	return cdrom_start_packet_command(drive, 32768, cdrom_start_rw_cont);
+ }
+ 
+ static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
+@@ -1958,7 +1286,10 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
+ {
+ 	struct cdrom_info *info = drive->driver_data;
+ 
+-	rq->cmd_flags |= REQ_QUIET;
++	if (blk_pc_request(rq))
++		rq->cmd_flags |= REQ_QUIET;
++	else
++		rq->cmd_flags &= ~REQ_FAILED;
+ 
+ 	info->dma = 0;
+ 
+@@ -1995,7 +1326,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
+ 	struct cdrom_info *info = drive->driver_data;
+ 
+ 	if (blk_fs_request(rq)) {
+-		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
++		if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
+ 			unsigned long elapsed = jiffies - info->start_seek;
+ 			int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ 
+@@ -2006,22 +1337,16 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
+ 				}
+ 				printk (KERN_ERR "%s: DSC timeout\n", drive->name);
+ 			}
+-			CDROM_CONFIG_FLAGS(drive)->seeking = 0;
++			info->cd_flags &= ~IDE_CD_FLAG_SEEKING;
+ 		}
+ 		if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
+ 			action = cdrom_start_seek(drive, block);
+-		} else {
+-			if (rq_data_dir(rq) == READ)
+-				action = cdrom_start_read(drive, block);
+-			else
+-				action = cdrom_start_write(drive, rq);
+-		}
++		} else
++			action = cdrom_start_rw(drive, rq);
+ 		info->last_block = block;
+ 		return action;
+-	} else if (rq->cmd_type == REQ_TYPE_SENSE ||
++	} else if (blk_sense_request(rq) || blk_pc_request(rq) ||
+ 		   rq->cmd_type == REQ_TYPE_ATA_PC) {
+-		return cdrom_do_packet_command(drive);
+-	} else if (blk_pc_request(rq)) {
+ 		return cdrom_do_block_pc(drive, rq);
+ 	} else if (blk_special_request(rq)) {
+ 		/*
+@@ -2048,141 +1373,33 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
+  * can also be NULL, in which case no sense information is returned.
+  */
+ 
+-#if ! STANDARD_ATAPI
+-static inline
+-int bin2bcd (int x)
+-{
+-	return (x%10) | ((x/10) << 4);
+-}
+-
+-
+-static inline
+-int bcd2bin (int x)
+-{
+-	return (x >> 4) * 10 + (x & 0x0f);
+-}
+-
+ static
+ void msf_from_bcd (struct atapi_msf *msf)
+ {
+-	msf->minute = bcd2bin (msf->minute);
+-	msf->second = bcd2bin (msf->second);
+-	msf->frame  = bcd2bin (msf->frame);
+-}
+-
+-#endif /* not STANDARD_ATAPI */
+-
+-
+-static inline
+-void lba_to_msf (int lba, byte *m, byte *s, byte *f)
+-{
+-	lba += CD_MSF_OFFSET;
+-	lba &= 0xffffff;  /* negative lbas use only 24 bits */
+-	*m = lba / (CD_SECS * CD_FRAMES);
+-	lba %= (CD_SECS * CD_FRAMES);
+-	*s = lba / CD_FRAMES;
+-	*f = lba % CD_FRAMES;
+-}
+-
+-
+-static inline
+-int msf_to_lba (byte m, byte s, byte f)
+-{
+-	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
++	msf->minute = BCD2BIN(msf->minute);
++	msf->second = BCD2BIN(msf->second);
++	msf->frame  = BCD2BIN(msf->frame);
+ }
+ 
+-static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
++int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
+ {
+ 	struct request req;
+ 	struct cdrom_info *info = drive->driver_data;
+ 	struct cdrom_device_info *cdi = &info->devinfo;
+ 
+-	cdrom_prepare_request(drive, &req);
++	ide_cd_init_rq(drive, &req);
+ 
+ 	req.sense = sense;
+ 	req.cmd[0] = GPCMD_TEST_UNIT_READY;
+ 	req.cmd_flags |= REQ_QUIET;
+ 
+-#if ! STANDARD_ATAPI
+-        /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
+-           switch CDs instead of supporting the LOAD_UNLOAD opcode   */
+-
++	/*
++	 * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
++	 * switch CDs instead of supporting the LOAD_UNLOAD opcode.
++	 */
+ 	req.cmd[7] = cdi->sanyo_slot % 3;
+-#endif /* not STANDARD_ATAPI */
+ 
+-	return cdrom_queue_packet_command(drive, &req);
+-}
+-
+-
+-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
+-static int
+-cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
+-{
+-	struct request_sense my_sense;
+-	struct request req;
+-	int stat;
+-
+-	if (sense == NULL)
+-		sense = &my_sense;
+-
+-	/* If the drive cannot lock the door, just pretend. */
+-	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
+-		stat = 0;
+-	} else {
+-		cdrom_prepare_request(drive, &req);
+-		req.sense = sense;
+-		req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+-		req.cmd[4] = lockflag ? 1 : 0;
+-		stat = cdrom_queue_packet_command(drive, &req);
+-	}
+-
+-	/* If we got an illegal field error, the drive
+-	   probably cannot lock the door. */
+-	if (stat != 0 &&
+-	    sense->sense_key == ILLEGAL_REQUEST &&
+-	    (sense->asc == 0x24 || sense->asc == 0x20)) {
+-		printk (KERN_ERR "%s: door locking not supported\n",
+-			drive->name);
+-		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+-		stat = 0;
+-	}
+-	
+-	/* no medium, that's alright. */
+-	if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
+-		stat = 0;
+-
+-	if (stat == 0)
+-		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
+-
+-	return stat;
+-}
+-
+-
+-/* Eject the disk if EJECTFLAG is 0.
+-   If EJECTFLAG is 1, try to reload the disk. */
+-static int cdrom_eject(ide_drive_t *drive, int ejectflag,
+-		       struct request_sense *sense)
+-{
+-	struct request req;
+-	char loej = 0x02;
+-
+-	if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
+-		return -EDRIVE_CANT_DO_THIS;
+-	
+-	/* reload fails on some drives, if the tray is locked */
+-	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
+-		return 0;
+-
+-	cdrom_prepare_request(drive, &req);
+-
+-	/* only tell drive to close tray if open, if it can do that */
+-	if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
+-		loej = 0;
+-
+-	req.sense = sense;
+-	req.cmd[0] = GPCMD_START_STOP_UNIT;
+-	req.cmd[4] = loej | (ejectflag != 0);
+-	return cdrom_queue_packet_command(drive, &req);
++	return ide_cd_queue_pc(drive, &req);
+ }
+ 
+ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
+@@ -2197,7 +1414,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
+ 	int stat;
+ 	struct request req;
+ 
+-	cdrom_prepare_request(drive, &req);
++	ide_cd_init_rq(drive, &req);
+ 
+ 	req.sense = sense;
+ 	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+@@ -2205,7 +1422,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
+ 	req.data_len = sizeof(capbuf);
+ 	req.cmd_flags |= REQ_QUIET;
+ 
+-	stat = cdrom_queue_packet_command(drive, &req);
++	stat = ide_cd_queue_pc(drive, &req);
+ 	if (stat == 0) {
+ 		*capacity = 1 + be32_to_cpu(capbuf.lba);
+ 		*sectors_per_frame =
+@@ -2221,7 +1438,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
+ {
+ 	struct request req;
+ 
+-	cdrom_prepare_request(drive, &req);
++	ide_cd_init_rq(drive, &req);
+ 
+ 	req.sense = sense;
+ 	req.data =  buf;
+@@ -2236,12 +1453,11 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
+ 	if (msf_flag)
+ 		req.cmd[1] = 2;
+ 
+-	return cdrom_queue_packet_command(drive, &req);
++	return ide_cd_queue_pc(drive, &req);
+ }
+ 
+-
+ /* Try to read the entire TOC for the disk into our internal buffer. */
+-static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
++int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ {
+ 	int stat, ntracks, i;
+ 	struct cdrom_info *info = drive->driver_data;
+@@ -2268,7 +1484,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 	   If it is, just return. */
+ 	(void) cdrom_check_status(drive, sense);
+ 
+-	if (CDROM_STATE_FLAGS(drive)->toc_valid)
++	if (info->cd_flags & IDE_CD_FLAG_TOC_VALID)
+ 		return 0;
+ 
+ 	/* Try to get the total cdrom capacity and sector size. */
+@@ -2290,12 +1506,10 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 	if (stat)
+ 		return stat;
+ 
+-#if ! STANDARD_ATAPI
+-	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+-		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+-		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
++	if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
++		toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
++		toc->hdr.last_track  = BCD2BIN(toc->hdr.last_track);
+ 	}
+-#endif  /* not STANDARD_ATAPI */
+ 
+ 	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+ 	if (ntracks <= 0)
+@@ -2327,16 +1541,13 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 					   (ntracks + 1) *
+ 					   sizeof(struct atapi_toc_entry),
+ 					   sense);
+-		if (stat) {
++		if (stat)
+ 			return stat;
+-		}
+-#if ! STANDARD_ATAPI
+-		if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+-			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
+-			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
+-		} else
+-#endif  /* not STANDARD_ATAPI */
+-		{
++
++		if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
++			toc->hdr.first_track = (u8)BIN2BCD(CDROM_LEADOUT);
++			toc->hdr.last_track = (u8)BIN2BCD(CDROM_LEADOUT);
++		} else {
+ 			toc->hdr.first_track = CDROM_LEADOUT;
+ 			toc->hdr.last_track = CDROM_LEADOUT;
+ 		}
+@@ -2347,21 +1558,17 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 
+ 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
+ 
+-#if ! STANDARD_ATAPI
+-	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+-		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+-		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
++	if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
++		toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
++		toc->hdr.last_track  = BCD2BIN(toc->hdr.last_track);
+ 	}
+-#endif  /* not STANDARD_ATAPI */
+ 
+-	for (i=0; i<=ntracks; i++) {
+-#if ! STANDARD_ATAPI
+-		if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+-			if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+-				toc->ent[i].track = bcd2bin(toc->ent[i].track);
++	for (i = 0; i <= ntracks; i++) {
++		if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) {
++			if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD)
++				toc->ent[i].track = BCD2BIN(toc->ent[i].track);
+ 			msf_from_bcd(&toc->ent[i].addr.msf);
+ 		}
+-#endif  /* not STANDARD_ATAPI */
+ 		toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
+ 						   toc->ent[i].addr.msf.second,
+ 						   toc->ent[i].addr.msf.frame);
+@@ -2381,8 +1588,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 		toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
+ 	}
+ 
+-#if ! STANDARD_ATAPI
+-	if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
++	if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) {
+ 		/* Re-read multisession information using MSF format */
+ 		stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
+ 					   sizeof(ms_tmp), sense);
+@@ -2394,7 +1600,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 					  	   ms_tmp.ent.addr.msf.second,
+ 						   ms_tmp.ent.addr.msf.frame);
+ 	}
+-#endif  /* not STANDARD_ATAPI */
+ 
+ 	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
+ 
+@@ -2407,278 +1612,22 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+ 	}
+ 
+ 	/* Remember that we've read this stuff. */
+-	CDROM_STATE_FLAGS(drive)->toc_valid = 1;
++	info->cd_flags |= IDE_CD_FLAG_TOC_VALID;
+ 
+ 	return 0;
+ }
+ 
+-
+-static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
+-				 int buflen, struct request_sense *sense)
+-{
+-	struct request req;
+-
+-	cdrom_prepare_request(drive, &req);
+-
+-	req.sense = sense;
+-	req.data = buf;
+-	req.data_len = buflen;
+-	req.cmd[0] = GPCMD_READ_SUBCHANNEL;
+-	req.cmd[1] = 2;     /* MSF addressing */
+-	req.cmd[2] = 0x40;  /* request subQ data */
+-	req.cmd[3] = format;
+-	req.cmd[7] = (buflen >> 8);
+-	req.cmd[8] = (buflen & 0xff);
+-	return cdrom_queue_packet_command(drive, &req);
+-}
+-
+-/* ATAPI cdrom drives are free to select the speed you request or any slower
+-   rate :-( Requesting too fast a speed will _not_ produce an error. */
+-static int cdrom_select_speed(ide_drive_t *drive, int speed,
+-			      struct request_sense *sense)
+-{
+-	struct request req;
+-	cdrom_prepare_request(drive, &req);
+-
+-	req.sense = sense;
+-	if (speed == 0)
+-		speed = 0xffff; /* set to max */
+-	else
+-		speed *= 177;   /* Nx to kbytes/s */
+-
+-	req.cmd[0] = GPCMD_SET_SPEED;
+-	/* Read Drive speed in kbytes/second MSB */
+-	req.cmd[2] = (speed >> 8) & 0xff;	
+-	/* Read Drive speed in kbytes/second LSB */
+-	req.cmd[3] = speed & 0xff;
+-	if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
+-	    CDROM_CONFIG_FLAGS(drive)->cd_rw ||
+-	    CDROM_CONFIG_FLAGS(drive)->dvd_r) {
+-		/* Write Drive speed in kbytes/second MSB */
+-		req.cmd[4] = (speed >> 8) & 0xff;
+-		/* Write Drive speed in kbytes/second LSB */
+-		req.cmd[5] = speed & 0xff;
+-       }
+-
+-	return cdrom_queue_packet_command(drive, &req);
+-}
+-
+-static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
+-{
+-	struct request_sense sense;
+-	struct request req;
+-
+-	cdrom_prepare_request(drive, &req);
+-
+-	req.sense = &sense;
+-	req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+-	lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]);
+-	lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]);
+-
+-	return cdrom_queue_packet_command(drive, &req);
+-}
+-
+-static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
+-				struct atapi_toc_entry **ent)
+-{
+-	struct cdrom_info *info = drive->driver_data;
+-	struct atapi_toc *toc = info->toc;
+-	int ntracks;
+-
+-	/*
+-	 * don't serve cached data, if the toc isn't valid
+-	 */
+-	if (!CDROM_STATE_FLAGS(drive)->toc_valid)
+-		return -EINVAL;
+-
+-	/* Check validity of requested track number. */
+-	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+-	if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0;
+-	if (track == CDROM_LEADOUT)
+-		*ent = &toc->ent[ntracks];
+-	else if (track < toc->hdr.first_track ||
+-		 track > toc->hdr.last_track)
+-		return -EINVAL;
+-	else
+-		*ent = &toc->ent[track - toc->hdr.first_track];
+-
+-	return 0;
+-}
+-
+-/* the generic packet interface to cdrom.c */
+-static int ide_cdrom_packet(struct cdrom_device_info *cdi,
+-			    struct packet_command *cgc)
+-{
+-	struct request req;
+-	ide_drive_t *drive = cdi->handle;
+-
+-	if (cgc->timeout <= 0)
+-		cgc->timeout = ATAPI_WAIT_PC;
+-
+-	/* here we queue the commands from the uniform CD-ROM
+-	   layer. the packet must be complete, as we do not
+-	   touch it at all. */
+-	cdrom_prepare_request(drive, &req);
+-	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
+-	if (cgc->sense)
+-		memset(cgc->sense, 0, sizeof(struct request_sense));
+-	req.data = cgc->buffer;
+-	req.data_len = cgc->buflen;
+-	req.timeout = cgc->timeout;
+-
+-	if (cgc->quiet)
+-		req.cmd_flags |= REQ_QUIET;
+-
+-	req.sense = cgc->sense;
+-	cgc->stat = cdrom_queue_packet_command(drive, &req);
+-	if (!cgc->stat)
+-		cgc->buflen -= req.data_len;
+-	return cgc->stat;
+-}
+-
+-static
+-int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
+-			   unsigned int cmd, void *arg)
+-			   
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	struct cdrom_info *info = drive->driver_data;
+-	int stat;
+-
+-	switch (cmd) {
+-	/*
+-	 * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
+-	 * atapi doesn't support it
+-	 */
+-	case CDROMPLAYTRKIND: {
+-		unsigned long lba_start, lba_end;
+-		struct cdrom_ti *ti = arg;
+-		struct atapi_toc_entry *first_toc, *last_toc;
+-
+-		stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
+-		if (stat)
+-			return stat;
+-
+-		stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
+-		if (stat)
+-			return stat;
+-
+-		if (ti->cdti_trk1 != CDROM_LEADOUT)
+-			++last_toc;
+-		lba_start = first_toc->addr.lba;
+-		lba_end   = last_toc->addr.lba;
+-
+-		if (lba_end <= lba_start)
+-			return -EINVAL;
+-
+-		return cdrom_play_audio(drive, lba_start, lba_end);
+-	}
+-
+-	case CDROMREADTOCHDR: {
+-		struct cdrom_tochdr *tochdr = arg;
+-		struct atapi_toc *toc;
+-
+-		/* Make sure our saved TOC is valid. */
+-		stat = cdrom_read_toc(drive, NULL);
+-		if (stat)
+-			return stat;
+-
+-		toc = info->toc;
+-		tochdr->cdth_trk0 = toc->hdr.first_track;
+-		tochdr->cdth_trk1 = toc->hdr.last_track;
+-
+-		return 0;
+-	}
+-
+-	case CDROMREADTOCENTRY: {
+-		struct cdrom_tocentry *tocentry = arg;
+-		struct atapi_toc_entry *toce;
+-
+-		stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
+-		if (stat)
+-			return stat;
+-
+-		tocentry->cdte_ctrl = toce->control;
+-		tocentry->cdte_adr  = toce->adr;
+-		if (tocentry->cdte_format == CDROM_MSF) {
+-			lba_to_msf (toce->addr.lba,
+-				   &tocentry->cdte_addr.msf.minute,
+-				   &tocentry->cdte_addr.msf.second,
+-				   &tocentry->cdte_addr.msf.frame);
+-		} else
+-			tocentry->cdte_addr.lba = toce->addr.lba;
+-
+-		return 0;
+-	}
+-
+-	default:
+-		return -EINVAL;
+-	}
+-}
+-
+-static
+-int ide_cdrom_reset (struct cdrom_device_info *cdi)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	struct request_sense sense;
+-	struct request req;
+-	int ret;
+-
+-	cdrom_prepare_request(drive, &req);
+-	req.cmd_type = REQ_TYPE_SPECIAL;
+-	req.cmd_flags = REQ_QUIET;
+-	ret = ide_do_drive_cmd(drive, &req, ide_wait);
+-
+-	/*
+-	 * A reset will unlock the door. If it was previously locked,
+-	 * lock it again.
+-	 */
+-	if (CDROM_STATE_FLAGS(drive)->door_locked)
+-		(void) cdrom_lockdoor(drive, 1, &sense);
+-
+-	return ret;
+-}
+-
+-
+-static
+-int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	struct request_sense sense;
+-
+-	if (position) {
+-		int stat = cdrom_lockdoor(drive, 0, &sense);
+-		if (stat)
+-			return stat;
+-	}
+-
+-	return cdrom_eject(drive, !position, &sense);
+-}
+-
+-static
+-int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	return cdrom_lockdoor(drive, lock, NULL);
+-}
+-
+-static
+-int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
++int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
+ {
+ 	struct cdrom_info *info = drive->driver_data;
+ 	struct cdrom_device_info *cdi = &info->devinfo;
+ 	struct packet_command cgc;
+-	int stat, attempts = 3, size = sizeof(*cap);
++	int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
+ 
+-	/*
+-	 * ACER50 (and others?) require the full spec length mode sense
+-	 * page capabilities size, but older drives break.
+-	 */
+-	if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+-	    !strcmp(drive->id->model, "WPI CDS-32X")))
+-		size -= sizeof(cap->pad);
++	if ((info->cd_flags & IDE_CD_FLAG_FULL_CAPS_PAGE) == 0)
++		size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
+ 
+-	init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN);
++	init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
+ 	do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ 		stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+ 		if (!stat)
+@@ -2687,177 +1636,33 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag
+ 	return stat;
+ }
+ 
+-static
+-void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page *cap)
+-{
+-	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
+-	if (!drive->id->model[0] &&
+-	    !strncmp(drive->id->fw_rev, "241N", 4)) {
+-		CDROM_STATE_FLAGS(drive)->current_speed  =
+-			(le16_to_cpu(cap->curspeed) + (176/2)) / 176;
+-		CDROM_CONFIG_FLAGS(drive)->max_speed =
+-			(le16_to_cpu(cap->maxspeed) + (176/2)) / 176;
+-	} else {
+-		CDROM_STATE_FLAGS(drive)->current_speed  =
+-			(be16_to_cpu(cap->curspeed) + (176/2)) / 176;
+-		CDROM_CONFIG_FLAGS(drive)->max_speed =
+-			(be16_to_cpu(cap->maxspeed) + (176/2)) / 176;
+-	}
+-}
+-
+-static
+-int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	struct request_sense sense;
+-	struct atapi_capabilities_page cap;
+-	int stat;
+-
+-	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
+-		return stat;
+-
+-	if (!ide_cdrom_get_capabilities(drive, &cap)) {
+-		ide_cdrom_update_speed(drive, &cap);
+-		cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+-	}
+-        return 0;
+-}
+-
+-/*
+- * add logic to try GET_EVENT command first to check for media and tray
+- * status. this should be supported by newer cd-r/w and all DVD etc
+- * drives
+- */
+-static
+-int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	struct media_event_desc med;
+-	struct request_sense sense;
+-	int stat;
+-
+-	if (slot_nr != CDSL_CURRENT)
+-		return -EINVAL;
+-
+-	stat = cdrom_check_status(drive, &sense);
+-	if (!stat || sense.sense_key == UNIT_ATTENTION)
+-		return CDS_DISC_OK;
+-
+-	if (!cdrom_get_media_event(cdi, &med)) {
+-		if (med.media_present)
+-			return CDS_DISC_OK;
+-		else if (med.door_open)
+-			return CDS_TRAY_OPEN;
+-		else
+-			return CDS_NO_DISC;
+-	}
+-
+-	if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04)
+-		return CDS_DISC_OK;
+-
+-	/*
+-	 * If not using Mt Fuji extended media tray reports,
+-	 * just return TRAY_OPEN since ATAPI doesn't provide
+-	 * any other way to detect this...
+-	 */
+-	if (sense.sense_key == NOT_READY) {
+-		if (sense.asc == 0x3a && sense.ascq == 1)
+-			return CDS_NO_DISC;
+-		else
+-			return CDS_TRAY_OPEN;
+-	}
+-	return CDS_DRIVE_NOT_READY;
+-}
+-
+-static
+-int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
+-				struct cdrom_multisession *ms_info)
+-{
+-	struct atapi_toc *toc;
+-	ide_drive_t *drive = cdi->handle;
+-	struct cdrom_info *info = drive->driver_data;
+-	struct request_sense sense;
+-	int ret;
+-
+-	if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
+-		if ((ret = cdrom_read_toc(drive, &sense)))
+-			return ret;
+-
+-	toc = info->toc;
+-	ms_info->addr.lba = toc->last_session_lba;
+-	ms_info->xa_flag = toc->xa_flag;
+-
+-	return 0;
+-}
+-
+-static
+-int ide_cdrom_get_mcn (struct cdrom_device_info *cdi,
+-		       struct cdrom_mcn *mcn_info)
++void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
+ {
+-	int stat;
+-	char mcnbuf[24];
+-	ide_drive_t *drive = cdi->handle;
+-
+-/* get MCN */
+-	if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
+-		return stat;
+-
+-	memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
+-		sizeof (mcn_info->medium_catalog_number)-1);
+-	mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1]
+-		= '\0';
+-
+-	return 0;
+-}
+-
++	struct cdrom_info *cd = drive->driver_data;
++	u16 curspeed, maxspeed;
+ 
++	curspeed = *(u16 *)&buf[8 + 14];
++	maxspeed = *(u16 *)&buf[8 +  8];
+ 
+-/****************************************************************************
+- * Other driver requests (open, close, check media change).
+- */
+-
+-static
+-int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
+-				       int slot_nr)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-	int retval;
+-	
+-	if (slot_nr == CDSL_CURRENT) {
+-		(void) cdrom_check_status(drive, NULL);
+-		retval = CDROM_STATE_FLAGS(drive)->media_changed;
+-		CDROM_STATE_FLAGS(drive)->media_changed = 0;
+-		return retval;
++	if (cd->cd_flags & IDE_CD_FLAG_LE_SPEED_FIELDS) {
++		curspeed = le16_to_cpu(curspeed);
++		maxspeed = le16_to_cpu(maxspeed);
+ 	} else {
+-		return -EINVAL;
++		curspeed = be16_to_cpu(curspeed);
++		maxspeed = be16_to_cpu(maxspeed);
+ 	}
+-}
+-
+-
+-static
+-int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose)
+-{
+-	return 0;
+-}
+ 
+-/*
+- * Close down the device.  Invalidate all cached blocks.
+- */
+-
+-static
+-void ide_cdrom_release_real (struct cdrom_device_info *cdi)
+-{
+-	ide_drive_t *drive = cdi->handle;
+-
+-	if (!cdi->use_count)
+-		CDROM_STATE_FLAGS(drive)->toc_valid = 0;
++	cd->current_speed = (curspeed + (176/2)) / 176;
++	cd->max_speed = (maxspeed + (176/2)) / 176;
+ }
+ 
++#define IDE_CD_CAPABILITIES \
++	(CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
++	 CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
++	 CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
++	 CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
++	 CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
+ 
+-
+-/****************************************************************************
+- * Device initialization.
+- */
+ static struct cdrom_device_ops ide_cdrom_dops = {
+ 	.open			= ide_cdrom_open_real,
+ 	.release		= ide_cdrom_release_real,
+@@ -2870,14 +1675,7 @@ static struct cdrom_device_ops ide_cdrom_dops = {
+ 	.get_mcn		= ide_cdrom_get_mcn,
+ 	.reset			= ide_cdrom_reset,
+ 	.audio_ioctl		= ide_cdrom_audio_ioctl,
+-	.capability		= CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
+-				CDC_SELECT_SPEED | CDC_SELECT_DISC |
+-				CDC_MULTI_SESSION | CDC_MCN |
+-				CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
+-				CDC_DRIVE_STATUS | CDC_CD_R |
+-				CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
+-				CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW |
+-				CDC_MRW_W | CDC_RAM,
++	.capability		= IDE_CD_CAPABILITIES,
+ 	.generic_packet		= ide_cdrom_packet,
+ };
+ 
+@@ -2887,35 +1685,12 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
+ 	struct cdrom_device_info *devinfo = &info->devinfo;
+ 
+ 	devinfo->ops = &ide_cdrom_dops;
+-	devinfo->mask = 0;
+-	devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
++	devinfo->speed = info->current_speed;
+ 	devinfo->capacity = nslots;
+ 	devinfo->handle = drive;
+ 	strcpy(devinfo->name, drive->name);
+-	
+-	/* set capability mask to match the probe. */
+-	if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
+-		devinfo->mask |= CDC_CD_R;
+-	if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
+-		devinfo->mask |= CDC_CD_RW;
+-	if (!CDROM_CONFIG_FLAGS(drive)->dvd)
+-		devinfo->mask |= CDC_DVD;
+-	if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
+-		devinfo->mask |= CDC_DVD_R;
+-	if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+-		devinfo->mask |= CDC_DVD_RAM;
+-	if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
+-		devinfo->mask |= CDC_SELECT_DISC;
+-	if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
+-		devinfo->mask |= CDC_PLAY_AUDIO;
+-	if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
+-		devinfo->mask |= CDC_CLOSE_TRAY;
+-	if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
+-		devinfo->mask |= CDC_MO_DRIVE;
+-	if (!CDROM_CONFIG_FLAGS(drive)->ram)
+-		devinfo->mask |= CDC_RAM;
+-
+-	if (CDROM_CONFIG_FLAGS(drive)->no_speed_select)
++
++	if (info->cd_flags & IDE_CD_FLAG_NO_SPEED_SELECT)
+ 		devinfo->mask |= CDC_SELECT_SPEED;
+ 
+ 	devinfo->disk = info->disk;
+@@ -2925,22 +1700,25 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
+ static
+ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+ {
+-	struct cdrom_info *info = drive->driver_data;
+-	struct cdrom_device_info *cdi = &info->devinfo;
+-	struct atapi_capabilities_page cap;
++	struct cdrom_info *cd = drive->driver_data;
++	struct cdrom_device_info *cdi = &cd->devinfo;
++	u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
++	mechtype_t mechtype;
+ 	int nslots = 1;
+ 
++	cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
++		     CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
++		     CDC_MO_DRIVE | CDC_RAM);
++
+ 	if (drive->media == ide_optical) {
+-		CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
+-		CDROM_CONFIG_FLAGS(drive)->ram = 1;
++		cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
+ 		printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name);
+ 		return nslots;
+ 	}
+ 
+-	if (CDROM_CONFIG_FLAGS(drive)->nec260 ||
+-	    !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) {
+-		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
+-		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
++	if (cd->cd_flags & IDE_CD_FLAG_PRE_ATAPI12) {
++		cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT;
++		cdi->mask &= ~CDC_PLAY_AUDIO;
+ 		return nslots;
+ 	}
+ 
+@@ -2954,83 +1732,66 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+ 	cdi->handle = drive;
+ 	cdi->ops = &ide_cdrom_dops;
+ 
+-	if (ide_cdrom_get_capabilities(drive, &cap))
++	if (ide_cdrom_get_capabilities(drive, buf))
+ 		return 0;
+ 
+-	if (cap.lock == 0)
+-		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+-	if (cap.eject)
+-		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
+-	if (cap.cd_r_write)
+-		CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
+-	if (cap.cd_rw_write) {
+-		CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
+-		CDROM_CONFIG_FLAGS(drive)->ram = 1;
+-	}
+-	if (cap.test_write)
+-		CDROM_CONFIG_FLAGS(drive)->test_write = 1;
+-	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
+-		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
+-	if (cap.dvd_ram_write) {
+-		CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
+-		CDROM_CONFIG_FLAGS(drive)->ram = 1;
+-	}
+-	if (cap.dvd_r_write)
+-		CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
+-	if (cap.audio_play)
+-		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+-	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
+-		CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
+-
+-	/* Some drives used by Apple don't advertise audio play
+-	 * but they do support reading TOC & audio datas
+-	 */
+-	if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+-	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+-	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+-	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+-		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
++	if ((buf[8 + 6] & 0x01) == 0)
++		cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
++	if (buf[8 + 6] & 0x08)
++		cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT;
++	if (buf[8 + 3] & 0x01)
++		cdi->mask &= ~CDC_CD_R;
++	if (buf[8 + 3] & 0x02)
++		cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
++	if (buf[8 + 2] & 0x38)
++		cdi->mask &= ~CDC_DVD;
++	if (buf[8 + 3] & 0x20)
++		cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
++	if (buf[8 + 3] & 0x10)
++		cdi->mask &= ~CDC_DVD_R;
++	if ((buf[8 + 4] & 0x01) || (cd->cd_flags & IDE_CD_FLAG_PLAY_AUDIO_OK))
++		cdi->mask &= ~CDC_PLAY_AUDIO;
++
++	mechtype = buf[8 + 6] >> 5;
++	if (mechtype == mechtype_caddy || mechtype == mechtype_popup)
++		cdi->mask |= CDC_CLOSE_TRAY;
+ 
+-#if ! STANDARD_ATAPI
+ 	if (cdi->sanyo_slot > 0) {
+-		CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
++		cdi->mask &= ~CDC_SELECT_DISC;
+ 		nslots = 3;
++	} else if (mechtype == mechtype_individual_changer ||
++		   mechtype == mechtype_cartridge_changer) {
++		nslots = cdrom_number_of_slots(cdi);
++		if (nslots > 1)
++			cdi->mask &= ~CDC_SELECT_DISC;
+ 	}
+ 
+-	else
+-#endif /* not STANDARD_ATAPI */
+-	if (cap.mechtype == mechtype_individual_changer ||
+-	    cap.mechtype == mechtype_cartridge_changer) {
+-		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
+-			CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+-			CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
+-		}
+-	}
++	ide_cdrom_update_speed(drive, buf);
+ 
+-	ide_cdrom_update_speed(drive, &cap);
+-	/* don't print speed if the drive reported 0.
+-	 */
+ 	printk(KERN_INFO "%s: ATAPI", drive->name);
+-	if (CDROM_CONFIG_FLAGS(drive)->max_speed)
+-		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
+-	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
+ 
+-	if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+-        	printk(" DVD%s%s", 
+-        	(CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
+-        	(CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
++	/* don't print speed if the drive reported 0 */
++	if (cd->max_speed)
++		printk(KERN_CONT " %dX", cd->max_speed);
+ 
+-        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+-        	printk(" CD%s%s", 
+-        	(CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
+-        	(CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
++	printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
+ 
+-        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
+-        	printk(" changer w/%d slots", nslots);
+-        else 	
+-        	printk(" drive");
++	if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
++		printk(KERN_CONT " DVD%s%s",
++				 (cdi->mask & CDC_DVD_R) ? "" : "-R",
++				 (cdi->mask & CDC_DVD_RAM) ? "" : "-RAM");
+ 
+-	printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(cap.buffer_size));
++	if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
++		printk(KERN_CONT " CD%s%s",
++				 (cdi->mask & CDC_CD_R) ? "" : "-R",
++				 (cdi->mask & CDC_CD_RW) ? "" : "/RW");
++
++	if ((cdi->mask & CDC_SELECT_DISC) == 0)
++		printk(KERN_CONT " changer w/%d slots", nslots);
++	else
++		printk(KERN_CONT " drive");
++
++	printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(*(u16 *)&buf[8 + 12]));
+ 
+ 	return nslots;
+ }
+@@ -3123,11 +1884,74 @@ static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
+ 	return 0;
+ }
+ 
++struct cd_list_entry {
++	const char	*id_model;
++	const char	*id_firmware;
++	unsigned int	cd_flags;
++};
++
++static const struct cd_list_entry ide_cd_quirks_list[] = {
++	/* Limit transfer size per interrupt. */
++	{ "SAMSUNG CD-ROM SCR-2430", NULL,   IDE_CD_FLAG_LIMIT_NFRAMES	    },
++	{ "SAMSUNG CD-ROM SCR-2432", NULL,   IDE_CD_FLAG_LIMIT_NFRAMES	    },
++	/* SCR-3231 doesn't support the SET_CD_SPEED command. */
++	{ "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_CD_FLAG_NO_SPEED_SELECT    },
++	/* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
++	{ "NEC CD-ROM DRIVE:260",    "1.01", IDE_CD_FLAG_TOCADDR_AS_BCD |
++					     IDE_CD_FLAG_PRE_ATAPI12,	    },
++	/* Vertos 300, some versions of this drive like to talk BCD. */
++	{ "V003S0DS",		     NULL,   IDE_CD_FLAG_VERTOS_300_SSD,    },
++	/* Vertos 600 ESD. */
++	{ "V006E0DS",		     NULL,   IDE_CD_FLAG_VERTOS_600_ESD,    },
++	/*
++	 * Sanyo 3 CD changer uses a non-standard command for CD changing
++	 * (by default standard ATAPI support for CD changers is used).
++	 */
++	{ "CD-ROM CDR-C3 G",	     NULL,   IDE_CD_FLAG_SANYO_3CD	    },
++	{ "CD-ROM CDR-C3G",	     NULL,   IDE_CD_FLAG_SANYO_3CD	    },
++	{ "CD-ROM CDR_C36",	     NULL,   IDE_CD_FLAG_SANYO_3CD	    },
++	/* Stingray 8X CD-ROM. */
++	{ "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_CD_FLAG_PRE_ATAPI12},
++	/*
++	 * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
++	 * mode sense page capabilities size, but older drives break.
++	 */
++	{ "ATAPI CD ROM DRIVE 50X MAX",	NULL,	IDE_CD_FLAG_FULL_CAPS_PAGE  },
++	{ "WPI CDS-32X",		NULL,	IDE_CD_FLAG_FULL_CAPS_PAGE  },
++	/* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
++	{ "",			     "241N", IDE_CD_FLAG_LE_SPEED_FIELDS    },
++	/*
++	 * Some drives used by Apple don't advertise audio play
++	 * but they do support reading TOC & audio datas.
++	 */
++	{ "MATSHITADVD-ROM SR-8187", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK	    },
++	{ "MATSHITADVD-ROM SR-8186", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK	    },
++	{ "MATSHITADVD-ROM SR-8176", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK	    },
++	{ "MATSHITADVD-ROM SR-8174", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK	    },
++	{ NULL, NULL, 0 }
++};
++
++static unsigned int ide_cd_flags(struct hd_driveid *id)
++{
++	const struct cd_list_entry *cle = ide_cd_quirks_list;
++
++	while (cle->id_model) {
++		if (strcmp(cle->id_model, id->model) == 0 &&
++		    (cle->id_firmware == NULL ||
++		     strstr(id->fw_rev, cle->id_firmware)))
++			return cle->cd_flags;
++		cle++;
++	}
++
++	return 0;
++}
++
+ static
+ int ide_cdrom_setup (ide_drive_t *drive)
+ {
+-	struct cdrom_info *info = drive->driver_data;
+-	struct cdrom_device_info *cdi = &info->devinfo;
++	struct cdrom_info *cd = drive->driver_data;
++	struct cdrom_device_info *cdi = &cd->devinfo;
++	struct hd_driveid *id = drive->id;
+ 	int nslots;
+ 
+ 	blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
+@@ -3138,101 +1962,21 @@ int ide_cdrom_setup (ide_drive_t *drive)
+ 
+ 	drive->special.all	= 0;
+ 
+-	CDROM_STATE_FLAGS(drive)->media_changed = 1;
+-	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
+-	CDROM_STATE_FLAGS(drive)->door_locked   = 0;
++	cd->cd_flags = IDE_CD_FLAG_MEDIA_CHANGED | IDE_CD_FLAG_NO_EJECT |
++		       ide_cd_flags(id);
+ 
+-#if NO_DOOR_LOCKING
+-	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+-#else
+-	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
+-#endif
++	if ((id->config & 0x0060) == 0x20)
++		cd->cd_flags |= IDE_CD_FLAG_DRQ_INTERRUPT;
+ 
+-	CDROM_CONFIG_FLAGS(drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20);
+-	CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+-	CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+-	CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+-	CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+-	CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+-	CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+-	CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+-	CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+-	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+-	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+-	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
+-	
+-	/* limit transfer size per interrupt. */
+-	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
+-	/* a testament to the nice quality of Samsung drives... */
+-	if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
+-		CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+-	else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
+-		CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+-	/* the 3231 model does not support the SET_CD_SPEED command */
+-	else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
+-		CDROM_CONFIG_FLAGS(drive)->no_speed_select = 1;
+-
+-#if ! STANDARD_ATAPI
+-	/* by default Sanyo 3 CD changer support is turned off and
+-           ATAPI Rev 2.2+ standard support for CD changers is used */
+-	cdi->sanyo_slot = 0;
+-
+-	CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+-	CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+-	CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+-	CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+-	CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
+-
+-	if (strcmp (drive->id->model, "V003S0DS") == 0 &&
+-	    drive->id->fw_rev[4] == '1' &&
+-	    drive->id->fw_rev[6] <= '2') {
+-		/* Vertos 300.
+-		   Some versions of this drive like to talk BCD. */
+-		CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+-	}
+-
+-	else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
+-	    drive->id->fw_rev[4] == '1' &&
+-	    drive->id->fw_rev[6] <= '2') {
+-		/* Vertos 600 ESD. */
+-		CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+-	}
+-	else if (strcmp(drive->id->model, "NEC CD-ROM DRIVE:260") == 0 &&
+-		 strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+-		/* Old NEC260 (not R).
+-		   This drive was released before the 1.2 version
+-		   of the spec. */
+-		CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
+-	}
+-	else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+-		 strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+-		/* Wearnes */
+-		CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+-		CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+-	}
+-        /* Sanyo 3 CD changer uses a non-standard command
+-           for CD changing */
+-        else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
+-                 (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
+-                 (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
+-                 /* uses CD in slot 0 when value is set to 3 */
+-                 cdi->sanyo_slot = 3;
+-        }
+-#endif /* not STANDARD_ATAPI */
+-
+-	info->toc		= NULL;
+-	info->buffer		= NULL;
+-	info->sector_buffered	= 0;
+-	info->nsectors_buffered	= 0;
+-	info->changer_info      = NULL;
+-	info->last_block	= 0;
+-	info->start_seek	= 0;
++	if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_300_SSD) &&
++	    id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
++		cd->cd_flags |= (IDE_CD_FLAG_TOCTRACKS_AS_BCD |
++				 IDE_CD_FLAG_TOCADDR_AS_BCD);
++	else if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_600_ESD) &&
++		 id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
++		cd->cd_flags |= IDE_CD_FLAG_TOCTRACKS_AS_BCD;
++	else if (cd->cd_flags & IDE_CD_FLAG_SANYO_3CD)
++		cdi->sanyo_slot = 3;	/* 3 => use CD in slot 0 */
+ 
+ 	nslots = ide_cdrom_probe_capabilities (drive);
+ 
+@@ -3247,7 +1991,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
+ 
+ 	if (ide_cdrom_register(drive, nslots)) {
+ 		printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+-		info->devinfo.handle = NULL;
++		cd->devinfo.handle = NULL;
+ 		return 1;
+ 	}
+ 	ide_cdrom_add_settings(drive);
+@@ -3287,7 +2031,6 @@ static void ide_cd_release(struct kref *kref)
+ 
+ 	kfree(info->buffer);
+ 	kfree(info->toc);
+-	kfree(info->changer_info);
+ 	if (devinfo->handle == drive && unregister_cdrom(devinfo))
+ 		printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+ 				"driver.\n", __FUNCTION__, drive->name);
+@@ -3443,7 +2186,9 @@ static int idecd_revalidate_disk(struct gendisk *disk)
+ {
+ 	struct cdrom_info *info = ide_cd_g(disk);
+ 	struct request_sense sense;
+-	cdrom_read_toc(info->drive, &sense);
++
++	ide_cd_read_toc(info->drive, &sense);
++
+ 	return  0;
+ }
+ 
+@@ -3518,7 +2263,7 @@ static int ide_cd_probe(ide_drive_t *drive)
+ 		goto failed;
+ 	}
+ 
+-	cdrom_read_toc(drive, &sense);
++	ide_cd_read_toc(drive, &sense);
+ 	g->fops = &idecd_ops;
+ 	g->flags |= GENHD_FL_REMOVABLE;
+ 	add_disk(g);
+@@ -3541,6 +2286,7 @@ static int __init ide_cdrom_init(void)
+ }
+ 
+ MODULE_ALIAS("ide:*m-cdrom*");
++MODULE_ALIAS("ide-cd");
+ module_init(ide_cdrom_init);
+ module_exit(ide_cdrom_exit);
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
+index 1b302fe..22e3751 100644
+--- a/drivers/ide/ide-cd.h
++++ b/drivers/ide/ide-cd.h
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/ide_cd.h
+- *
+  *  Copyright (C) 1996-98  Erik Andersen
+  *  Copyright (C) 1998-2000 Jens Axboe
+  */
+@@ -10,31 +8,6 @@
+ #include <linux/cdrom.h>
+ #include <asm/byteorder.h>
+ 
+-/* Turn this on to have the driver print out the meanings of the
+-   ATAPI error codes.  This will use up additional kernel-space
+-   memory, though. */
+-
+-#ifndef VERBOSE_IDE_CD_ERRORS
+-#define VERBOSE_IDE_CD_ERRORS 1
+-#endif
+-
+-
+-/* Turning this on will remove code to work around various nonstandard
+-   ATAPI implementations.  If you know your drive follows the standard,
+-   this will give you a slightly smaller kernel. */
+-
+-#ifndef STANDARD_ATAPI
+-#define STANDARD_ATAPI 0
+-#endif
+-
+-
+-/* Turning this on will disable the door-locking functionality.
+-   This is apparently needed for supermount. */
+-
+-#ifndef NO_DOOR_LOCKING
+-#define NO_DOOR_LOCKING 0
+-#endif
+-
+ /*
+  * typical timeout for packet command
+  */
+@@ -49,68 +22,47 @@
+ #endif
+ #define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
+ #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
+-#define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE >> SECTOR_BITS)
+-#define SECTORS_MAX		(131072 >> SECTOR_BITS)
+-
+-#define BLOCKS_PER_FRAME	(CD_FRAMESIZE / BLOCK_SIZE)
+-
+-/* special command codes for strategy routine. */
+-#define PACKET_COMMAND        4315
+-#define REQUEST_SENSE_COMMAND 4316
+-#define RESET_DRIVE_COMMAND   4317
+-
+-
+-/* Configuration flags.  These describe the capabilities of the drive.
+-   They generally do not change after initialization, unless we learn
+-   more about the drive from stuff failing. */
+-struct ide_cd_config_flags {
+-	__u8 drq_interrupt	: 1; /* Device sends an interrupt when ready
+-					for a packet command. */
+-	__u8 no_doorlock	: 1; /* Drive cannot lock the door. */
+-	__u8 no_eject		: 1; /* Drive cannot eject the disc. */
+-	__u8 nec260		: 1; /* Drive is a pre-1.2 NEC 260 drive. */
+-	__u8 playmsf_as_bcd	: 1; /* PLAYMSF command takes BCD args. */
+-	__u8 tocaddr_as_bcd	: 1; /* TOC addresses are in BCD. */
+-	__u8 toctracks_as_bcd	: 1; /* TOC track numbers are in BCD. */
+-	__u8 subchan_as_bcd	: 1; /* Subchannel info is in BCD. */
+-	__u8 is_changer		: 1; /* Drive is a changer. */
+-	__u8 cd_r		: 1; /* Drive can write to CD-R media . */
+-	__u8 cd_rw		: 1; /* Drive can write to CD-R/W media . */
+-	__u8 dvd		: 1; /* Drive is a DVD-ROM */
+-	__u8 dvd_r		: 1; /* Drive can write DVD-R */
+-	__u8 dvd_ram		: 1; /* Drive can write DVD-RAM */
+-	__u8 ram		: 1; /* generic WRITE (dvd-ram/mrw) */
+-	__u8 test_write		: 1; /* Drive can fake writes */
+-	__u8 supp_disc_present	: 1; /* Changer can report exact contents
+-					of slots. */
+-	__u8 limit_nframes	: 1; /* Drive does not provide data in
+-					multiples of SECTOR_SIZE when more
+-					than one interrupt is needed. */
+-	__u8 seeking		: 1; /* Seeking in progress */
+-	__u8 audio_play		: 1; /* can do audio related commands */
+-	__u8 close_tray		: 1; /* can close the tray */
+-	__u8 writing		: 1; /* pseudo write in progress */
+-	__u8 mo_drive		: 1; /* drive is an MO device */
+-	__u8 no_speed_select	: 1; /* SET_CD_SPEED command is unsupported. */
+-	__u8 reserved		: 1;
+-	byte max_speed;		     /* Max speed of the drive */
+-};
+-#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
+ 
+- 
+-/* State flags.  These give information about the current state of the
+-   drive, and will change during normal operation. */
+-struct ide_cd_state_flags {
+-	__u8 media_changed : 1; /* Driver has noticed a media change. */
+-	__u8 toc_valid     : 1; /* Saved TOC information is current. */
+-	__u8 door_locked   : 1; /* We think that the drive door is locked. */
+-	__u8 writing       : 1; /* the drive is currently writing */
+-	__u8 reserved      : 4;
+-	byte current_speed;	/* Current speed of the drive */
++/* Capabilities Page size including 8 bytes of Mode Page Header */
++#define ATAPI_CAPABILITIES_PAGE_SIZE		(8 + 20)
++#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE	4
++
++enum {
++	/* Device sends an interrupt when ready for a packet command. */
++	IDE_CD_FLAG_DRQ_INTERRUPT	= (1 << 0),
++	/* Drive cannot lock the door. */
++	IDE_CD_FLAG_NO_DOORLOCK		= (1 << 1),
++	/* Drive cannot eject the disc. */
++	IDE_CD_FLAG_NO_EJECT		= (1 << 2),
++	/* Drive is a pre ATAPI 1.2 drive. */
++	IDE_CD_FLAG_PRE_ATAPI12		= (1 << 3),
++	/* TOC addresses are in BCD. */
++	IDE_CD_FLAG_TOCADDR_AS_BCD	= (1 << 4),
++	/* TOC track numbers are in BCD. */
++	IDE_CD_FLAG_TOCTRACKS_AS_BCD	= (1 << 5),
++	/*
++	 * Drive does not provide data in multiples of SECTOR_SIZE
++	 * when more than one interrupt is needed.
++	 */
++	IDE_CD_FLAG_LIMIT_NFRAMES	= (1 << 6),
++	/* Seeking in progress. */
++	IDE_CD_FLAG_SEEKING		= (1 << 7),
++	/* Driver has noticed a media change. */
++	IDE_CD_FLAG_MEDIA_CHANGED	= (1 << 8),
++	/* Saved TOC information is current. */
++	IDE_CD_FLAG_TOC_VALID		= (1 << 9),
++	/* We think that the drive door is locked. */
++	IDE_CD_FLAG_DOOR_LOCKED		= (1 << 10),
++	/* SET_CD_SPEED command is unsupported. */
++	IDE_CD_FLAG_NO_SPEED_SELECT	= (1 << 11),
++	IDE_CD_FLAG_VERTOS_300_SSD	= (1 << 12),
++	IDE_CD_FLAG_VERTOS_600_ESD	= (1 << 13),
++	IDE_CD_FLAG_SANYO_3CD		= (1 << 14),
++	IDE_CD_FLAG_FULL_CAPS_PAGE	= (1 << 15),
++	IDE_CD_FLAG_PLAY_AUDIO_OK	= (1 << 16),
++	IDE_CD_FLAG_LE_SPEED_FIELDS	= (1 << 17),
+ };
+ 
+-#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
+-
+ /* Structure of a MSF cdrom address. */
+ struct atapi_msf {
+ 	byte reserved;
+@@ -155,310 +107,6 @@ struct atapi_toc {
+ 	  /* One extra for the leadout. */
+ };
+ 
+-
+-/* This structure is annoyingly close to, but not identical with,
+-   the cdrom_subchnl structure from cdrom.h. */
+-struct atapi_cdrom_subchnl {
+- 	u_char  acdsc_reserved;
+- 	u_char  acdsc_audiostatus;
+- 	u_short acdsc_length;
+-	u_char  acdsc_format;
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	u_char  acdsc_ctrl:     4;
+-	u_char  acdsc_adr:      4;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	u_char  acdsc_adr:	4;
+-	u_char  acdsc_ctrl:	4;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-	u_char  acdsc_trk;
+-	u_char  acdsc_ind;
+-	union {
+-		struct atapi_msf msf;
+-		int	lba;
+-	} acdsc_absaddr;
+-	union {
+-		struct atapi_msf msf;
+-		int	lba;
+-	} acdsc_reladdr;
+-};
+-
+-
+-
+-/* This should probably go into cdrom.h along with the other
+- * generic stuff now in the Mt. Fuji spec.
+- */
+-struct atapi_capabilities_page {
+-	struct mode_page_header header;
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 parameters_saveable : 1;
+-	__u8 reserved1           : 1;
+-	__u8 page_code           : 6;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	__u8 page_code           : 6;
+-	__u8 reserved1           : 1;
+-	__u8 parameters_saveable : 1;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-	byte     page_length;
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 reserved2           : 2;
+-	/* Drive supports reading of DVD-RAM discs */
+-	__u8 dvd_ram_read        : 1;
+-	/* Drive supports reading of DVD-R discs */
+-	__u8 dvd_r_read          : 1;
+-	/* Drive supports reading of DVD-ROM discs */
+-	__u8 dvd_rom             : 1;
+-	/* Drive supports reading CD-R discs with addressing method 2 */
+-	__u8 method2             : 1; /* reserved in 1.2 */
+-	/* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
+-	__u8 cd_rw_read		 : 1; /* reserved in 1.2 */
+-	/* Drive supports read from CD-R discs (orange book, part II) */
+-	__u8 cd_r_read           : 1; /* reserved in 1.2 */
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	/* Drive supports read from CD-R discs (orange book, part II) */
+-	__u8 cd_r_read           : 1; /* reserved in 1.2 */
+-	/* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
+-	__u8 cd_rw_read          : 1; /* reserved in 1.2 */
+-	/* Drive supports reading CD-R discs with addressing method 2 */
+-	__u8 method2             : 1;
+-	/* Drive supports reading of DVD-ROM discs */
+-	__u8 dvd_rom             : 1;
+-	/* Drive supports reading of DVD-R discs */
+-	__u8 dvd_r_read          : 1;
+-	/* Drive supports reading of DVD-RAM discs */
+-	__u8 dvd_ram_read        : 1;
+-	__u8 reserved2		 : 2;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 reserved3           : 2;
+-	/* Drive can write DVD-RAM discs */
+-	__u8 dvd_ram_write       : 1;
+-	/* Drive can write DVD-R discs */
+-	__u8 dvd_r_write         : 1;
+-	__u8 reserved3a          : 1;
+-	/* Drive can fake writes */
+-	__u8 test_write          : 1;
+-	/* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
+-	__u8 cd_rw_write	 : 1; /* reserved in 1.2 */
+-	/* Drive supports write to CD-R discs (orange book, part II) */
+-	__u8 cd_r_write          : 1; /* reserved in 1.2 */
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	/* Drive can write to CD-R discs (orange book, part II) */
+-	__u8 cd_r_write          : 1; /* reserved in 1.2 */
+-	/* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
+-	__u8 cd_rw_write	 : 1; /* reserved in 1.2 */
+-	/* Drive can fake writes */
+-	__u8 test_write          : 1;
+-	__u8 reserved3a          : 1;
+-	/* Drive can write DVD-R discs */
+-	__u8 dvd_r_write         : 1;
+-	/* Drive can write DVD-RAM discs */
+-	__u8 dvd_ram_write       : 1;
+-	__u8 reserved3           : 2;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 reserved4           : 1;
+-	/* Drive can read multisession discs. */
+-	__u8 multisession        : 1;
+-	/* Drive can read mode 2, form 2 data. */
+-	__u8 mode2_form2         : 1;
+-	/* Drive can read mode 2, form 1 (XA) data. */
+-	__u8 mode2_form1         : 1;
+-	/* Drive supports digital output on port 2. */
+-	__u8 digport2            : 1;
+-	/* Drive supports digital output on port 1. */
+-	__u8 digport1            : 1;
+-	/* Drive can deliver a composite audio/video data stream. */
+-	__u8 composite           : 1;
+-	/* Drive supports audio play operations. */
+-	__u8 audio_play          : 1;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	/* Drive supports audio play operations. */
+-	__u8 audio_play          : 1;
+-	/* Drive can deliver a composite audio/video data stream. */
+-	__u8 composite           : 1;
+-	/* Drive supports digital output on port 1. */
+-	__u8 digport1            : 1;
+-	/* Drive supports digital output on port 2. */
+-	__u8 digport2            : 1;
+-	/* Drive can read mode 2, form 1 (XA) data. */
+-	__u8 mode2_form1         : 1;
+-	/* Drive can read mode 2, form 2 data. */
+-	__u8 mode2_form2         : 1;
+-	/* Drive can read multisession discs. */
+-	__u8 multisession        : 1;
+-	__u8 reserved4           : 1;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 reserved5           : 1;
+-	/* Drive can return Media Catalog Number (UPC) info. */
+-	__u8 upc                 : 1;
+-	/* Drive can return International Standard Recording Code info. */
+-	__u8 isrc                : 1;
+-	/* Drive supports C2 error pointers. */
+-	__u8 c2_pointers         : 1;
+-	/* R-W data will be returned deinterleaved and error corrected. */
+-	__u8 rw_corr             : 1;
+-	/* Subchannel reads can return combined R-W information. */
+-	__u8 rw_supported        : 1;
+-	/* Drive can continue a read cdda operation from a loss of streaming.*/
+-	__u8 cdda_accurate       : 1;
+-	/* Drive can read Red Book audio data. */
+-	__u8 cdda                : 1;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	/* Drive can read Red Book audio data. */
+-	__u8 cdda                : 1;
+-	/* Drive can continue a read cdda operation from a loss of streaming.*/
+-	__u8 cdda_accurate       : 1;
+-	/* Subchannel reads can return combined R-W information. */
+-	__u8 rw_supported        : 1;
+-	/* R-W data will be returned deinterleaved and error corrected. */
+-	__u8 rw_corr             : 1;
+-	/* Drive supports C2 error pointers. */
+-	__u8 c2_pointers         : 1;
+-	/* Drive can return International Standard Recording Code info. */
+-	__u8 isrc                : 1;
+-	/* Drive can return Media Catalog Number (UPC) info. */
+-	__u8 upc                 : 1;
+-	__u8 reserved5           : 1;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	/* Drive mechanism types. */
+-	mechtype_t mechtype	 : 3;
+-	__u8 reserved6           : 1;
+-	/* Drive can eject a disc or changer cartridge. */
+-	__u8 eject               : 1;
+-	/* State of prevent/allow jumper. */
+-	__u8 prevent_jumper      : 1;
+-	/* Present state of door lock. */
+-	__u8 lock_state          : 1;
+-	/* Drive can lock the door. */
+-	__u8 lock                : 1;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-
+-	/* Drive can lock the door. */
+-	__u8 lock                : 1;
+-	/* Present state of door lock. */
+-	__u8 lock_state          : 1;
+-	/* State of prevent/allow jumper. */
+-	__u8 prevent_jumper      : 1;
+-	/* Drive can eject a disc or changer cartridge. */
+-	__u8 eject               : 1;
+-	__u8 reserved6           : 1;
+-	/* Drive mechanism types. */
+-	mechtype_t mechtype	 : 3;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 reserved7           : 4;
+-	/* Drive supports software slot selection. */
+-	__u8 sss                 : 1;  /* reserved in 1.2 */
+-	/* Changer can report exact contents of slots. */
+-	__u8 disc_present        : 1;  /* reserved in 1.2 */
+-	/* Audio for each channel can be muted independently. */
+-	__u8 separate_mute       : 1;
+-	/* Audio level for each channel can be controlled independently. */
+-	__u8 separate_volume     : 1;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-
+-	/* Audio level for each channel can be controlled independently. */
+-	__u8 separate_volume     : 1;
+-	/* Audio for each channel can be muted independently. */
+-	__u8 separate_mute       : 1;
+-	/* Changer can report exact contents of slots. */
+-	__u8 disc_present        : 1;  /* reserved in 1.2 */
+-	/* Drive supports software slot selection. */
+-	__u8 sss                 : 1;  /* reserved in 1.2 */
+-	__u8 reserved7           : 4;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-	/* Note: the following four fields are returned in big-endian form. */
+-	/* Maximum speed (in kB/s). */
+-	unsigned short maxspeed;
+-	/* Number of discrete volume levels. */
+-	unsigned short n_vol_levels;
+-	/* Size of cache in drive, in kB. */
+-	unsigned short buffer_size;
+-	/* Current speed (in kB/s). */
+-	unsigned short curspeed;
+-	char pad[4];
+-};
+-
+-
+-struct atapi_mechstat_header {
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 fault         : 1;
+-	__u8 changer_state : 2;
+-	__u8 curslot       : 5;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	__u8 curslot       : 5;
+-	__u8 changer_state : 2;
+-	__u8 fault         : 1;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 mech_state    : 3;
+-	__u8 door_open     : 1;
+-	__u8 reserved1     : 4;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	__u8 reserved1     : 4;
+-	__u8 door_open     : 1;
+-	__u8 mech_state    : 3;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-	byte     curlba[3];
+-	byte     nslots;
+-	__u16	 slot_tablelen;
+-};
+-
+-
+-struct atapi_slot {
+-#if defined(__BIG_ENDIAN_BITFIELD)
+-	__u8 disc_present : 1;
+-	__u8 reserved1    : 6;
+-	__u8 change       : 1;
+-#elif defined(__LITTLE_ENDIAN_BITFIELD)
+-	__u8 change       : 1;
+-	__u8 reserved1    : 6;
+-	__u8 disc_present : 1;
+-#else
+-#error "Please fix <asm/byteorder.h>"
+-#endif
+-
+-	byte reserved2[3];
+-};
+-
+-struct atapi_changer_info {
+-	struct atapi_mechstat_header hdr;
+-	struct atapi_slot slots[0];
+-};
+-
+ /* Extra per-device info for cdrom drives. */
+ struct cdrom_info {
+ 	ide_drive_t	*drive;
+@@ -483,11 +131,11 @@ struct cdrom_info {
+ 	int dma;
+ 	unsigned long last_block;
+ 	unsigned long start_seek;
+-	/* Buffer to hold mechanism status and changer slot table. */
+-	struct atapi_changer_info *changer_info;
+ 
+-	struct ide_cd_config_flags	config_flags;
+-	struct ide_cd_state_flags	state_flags;
++	unsigned int cd_flags;
++
++	u8 max_speed;		/* Max speed of the drive. */
++	u8 current_speed;	/* Current speed of the drive. */
+ 
+         /* Per-device info needed by cdrom.c generic driver. */
+         struct cdrom_device_info devinfo;
+@@ -495,250 +143,30 @@ struct cdrom_info {
+ 	unsigned long write_timeout;
+ };
+ 
+-/****************************************************************************
+- * Descriptions of ATAPI error codes.
+- */
+-
+-/* This stuff should be in cdrom.h, since it is now generic... */
+-
+-/* ATAPI sense keys (from table 140 of ATAPI 2.6) */
+-#define NO_SENSE                0x00
+-#define RECOVERED_ERROR         0x01
+-#define NOT_READY               0x02
+-#define MEDIUM_ERROR            0x03
+-#define HARDWARE_ERROR          0x04
+-#define ILLEGAL_REQUEST         0x05
+-#define UNIT_ATTENTION          0x06
+-#define DATA_PROTECT            0x07
+-#define BLANK_CHECK             0x08
+-#define ABORTED_COMMAND         0x0b
+-#define MISCOMPARE              0x0e
+-
+- 
+-
+-/* This stuff should be in cdrom.h, since it is now generic... */
+-#if VERBOSE_IDE_CD_ERRORS
+-
+- /* The generic packet command opcodes for CD/DVD Logical Units,
+- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ 
+-static const struct {
+-	unsigned short packet_command;
+-	const char * const text;
+-} packet_command_texts[] = {
+-	{ GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
+-	{ GPCMD_REQUEST_SENSE, "Request Sense" },
+-	{ GPCMD_FORMAT_UNIT, "Format Unit" },
+-	{ GPCMD_INQUIRY, "Inquiry" },
+-	{ GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
+-	{ GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+-	{ GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
+-	{ GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
+-	{ GPCMD_READ_10, "Read 10" },
+-	{ GPCMD_WRITE_10, "Write 10" },
+-	{ GPCMD_SEEK, "Seek" },
+-	{ GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
+-	{ GPCMD_VERIFY_10, "Verify 10" },
+-	{ GPCMD_FLUSH_CACHE, "Flush Cache" },
+-	{ GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
+-	{ GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
+-	{ GPCMD_READ_HEADER, "Read Header" },
+-	{ GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
+-	{ GPCMD_GET_CONFIGURATION, "Get Configuration" },
+-	{ GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
+-	{ GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
+-	{ GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" },
+-	{ GPCMD_PAUSE_RESUME, "Pause/Resume" },
+-	{ GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
+-	{ GPCMD_READ_DISC_INFO, "Read Disc Info" },
+-	{ GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
+-	{ GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
+-	{ GPCMD_SEND_OPC, "Send OPC" },
+-	{ GPCMD_MODE_SELECT_10, "Mode Select 10" },
+-	{ GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
+-	{ GPCMD_MODE_SENSE_10, "Mode Sense 10" },
+-	{ GPCMD_CLOSE_TRACK, "Close Track" },
+-	{ GPCMD_BLANK, "Blank" },
+-	{ GPCMD_SEND_EVENT, "Send Event" },
+-	{ GPCMD_SEND_KEY, "Send Key" },
+-	{ GPCMD_REPORT_KEY, "Report Key" },
+-	{ GPCMD_LOAD_UNLOAD, "Load/Unload" },
+-	{ GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
+-	{ GPCMD_READ_12, "Read 12" },
+-	{ GPCMD_GET_PERFORMANCE, "Get Performance" },
+-	{ GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
+-	{ GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
+-	{ GPCMD_SET_STREAMING, "Set Streaming" },
+-	{ GPCMD_READ_CD_MSF, "Read CD MSF" },
+-	{ GPCMD_SCAN, "Scan" },
+-	{ GPCMD_SET_SPEED, "Set Speed" },
+-	{ GPCMD_PLAY_CD, "Play CD" },
+-	{ GPCMD_MECHANISM_STATUS, "Mechanism Status" },
+-	{ GPCMD_READ_CD, "Read CD" },
+-};
+-
+-
+-
+-/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+-static const char * const sense_key_texts[16] = {
+-	"No sense data",
+-	"Recovered error",
+-	"Not ready",
+-	"Medium error",
+-	"Hardware error",
+-	"Illegal request",
+-	"Unit attention",
+-	"Data protect",
+-	"Blank check",
+-	"(reserved)",
+-	"(reserved)",
+-	"Aborted command",
+-	"(reserved)",
+-	"(reserved)",
+-	"Miscompare",
+-	"(reserved)",
+-};
+-
+-/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+-static const struct {
+-	unsigned long asc_ascq;
+-	const char * const text;
+-} sense_data_texts[] = {
+-	{ 0x000000, "No additional sense information" },
+-	{ 0x000011, "Play operation in progress" },
+-	{ 0x000012, "Play operation paused" },
+-	{ 0x000013, "Play operation successfully completed" },
+-	{ 0x000014, "Play operation stopped due to error" },
+-	{ 0x000015, "No current audio status to return" },
+-	{ 0x010c0a, "Write error - padding blocks added" },
+-	{ 0x011700, "Recovered data with no error correction applied" },
+-	{ 0x011701, "Recovered data with retries" },
+-	{ 0x011702, "Recovered data with positive head offset" },
+-	{ 0x011703, "Recovered data with negative head offset" },
+-	{ 0x011704, "Recovered data with retries and/or CIRC applied" },
+-	{ 0x011705, "Recovered data using previous sector ID" },
+-	{ 0x011800, "Recovered data with error correction applied" },
+-	{ 0x011801, "Recovered data with error correction and retries applied"},
+-	{ 0x011802, "Recovered data - the data was auto-reallocated" },
+-	{ 0x011803, "Recovered data with CIRC" },
+-	{ 0x011804, "Recovered data with L-EC" },
+-	{ 0x015d00, 
+-	    "Failure prediction threshold exceeded - Predicted logical unit failure" },
+-	{ 0x015d01, 
+-	    "Failure prediction threshold exceeded - Predicted media failure" },
+-	{ 0x015dff, "Failure prediction threshold exceeded - False" },
+-	{ 0x017301, "Power calibration area almost full" },
+-	{ 0x020400, "Logical unit not ready - cause not reportable" },
+-	/* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
+-	{ 0x020401,
+-	  "Logical unit not ready - in progress [sic] of becoming ready" },
+-	{ 0x020402, "Logical unit not ready - initializing command required" },
+-	{ 0x020403, "Logical unit not ready - manual intervention required" },
+-	{ 0x020404, "Logical unit not ready - format in progress" },
+-	{ 0x020407, "Logical unit not ready - operation in progress" },
+-	{ 0x020408, "Logical unit not ready - long write in progress" },
+-	{ 0x020600, "No reference position found (media may be upside down)" },
+-	{ 0x023000, "Incompatible medium installed" },
+-	{ 0x023a00, "Medium not present" },
+-	{ 0x025300, "Media load or eject failed" },
+-	{ 0x025700, "Unable to recover table of contents" },
+-	{ 0x030300, "Peripheral device write fault" },
+-	{ 0x030301, "No write current" },
+-	{ 0x030302, "Excessive write errors" },
+-	{ 0x030c00, "Write error" },
+-	{ 0x030c01, "Write error - Recovered with auto reallocation" },
+-	{ 0x030c02, "Write error - auto reallocation failed" },
+-	{ 0x030c03, "Write error - recommend reassignment" },
+-	{ 0x030c04, "Compression check miscompare error" },
+-	{ 0x030c05, "Data expansion occurred during compress" },
+-	{ 0x030c06, "Block not compressible" },
+-	{ 0x030c07, "Write error - recovery needed" },
+-	{ 0x030c08, "Write error - recovery failed" },
+-	{ 0x030c09, "Write error - loss of streaming" },
+-	{ 0x031100, "Unrecovered read error" },
+-	{ 0x031106, "CIRC unrecovered error" },
+-	{ 0x033101, "Format command failed" },
+-	{ 0x033200, "No defect spare location available" },
+-	{ 0x033201, "Defect list update failure" },
+-	{ 0x035100, "Erase failure" },
+-	{ 0x037200, "Session fixation error" },
+-	{ 0x037201, "Session fixation error writin lead-in" },
+-	{ 0x037202, "Session fixation error writin lead-out" },
+-	{ 0x037300, "CD control error" },
+-	{ 0x037302, "Power calibration area is full" },
+-	{ 0x037303, "Power calibration area error" },
+-	{ 0x037304, "Program memory area / RMA update failure" },
+-	{ 0x037305, "Program memory area / RMA is full" },
+-	{ 0x037306, "Program memory area / RMA is (almost) full" },
+-
+-	{ 0x040200, "No seek complete" },
+-	{ 0x040300, "Write fault" },
+-	{ 0x040900, "Track following error" },
+-	{ 0x040901, "Tracking servo failure" },
+-	{ 0x040902, "Focus servo failure" },
+-	{ 0x040903, "Spindle servo failure" },
+-	{ 0x041500, "Random positioning error" },
+-	{ 0x041501, "Mechanical positioning or changer error" },
+-	{ 0x041502, "Positioning error detected by read of medium" },
+-	{ 0x043c00, "Mechanical positioning or changer error" },
+-	{ 0x044000, "Diagnostic failure on component (ASCQ)" },
+-	{ 0x044400, "Internal CD/DVD logical unit failure" },
+-	{ 0x04b600, "Media load mechanism failed" },
+-	{ 0x051a00, "Parameter list length error" },
+-	{ 0x052000, "Invalid command operation code" },
+-	{ 0x052100, "Logical block address out of range" },
+-	{ 0x052102, "Invalid address for write" },
+-	{ 0x052400, "Invalid field in command packet" },
+-	{ 0x052600, "Invalid field in parameter list" },
+-	{ 0x052601, "Parameter not supported" },
+-	{ 0x052602, "Parameter value invalid" },
+-	{ 0x052700, "Write protected media" },
+-	{ 0x052c00, "Command sequence error" },
+-	{ 0x052c03, "Current program area is not empty" },
+-	{ 0x052c04, "Current program area is empty" },
+-	{ 0x053001, "Cannot read medium - unknown format" },
+-	{ 0x053002, "Cannot read medium - incompatible format" },
+-	{ 0x053900, "Saving parameters not supported" },
+-	{ 0x054e00, "Overlapped commands attempted" },
+-	{ 0x055302, "Medium removal prevented" },
+-	{ 0x055500, "System resource failure" },
+-	{ 0x056300, "End of user area encountered on this track" },
+-	{ 0x056400, "Illegal mode for this track or incompatible medium" },
+-	{ 0x056f00, "Copy protection key exchange failure - Authentication failure" },
+-	{ 0x056f01, "Copy protection key exchange failure - Key not present" },
+-	{ 0x056f02, "Copy protection key exchange failure - Key not established" },
+-	{ 0x056f03, "Read of scrambled sector without authentication" },
+-	{ 0x056f04, "Media region code is mismatched to logical unit" },
+-	{ 0x056f05,  "Drive region must be permanent / region reset count error" },
+-	{ 0x057203, "Session fixation error - incomplete track in session" },
+-	{ 0x057204, "Empty or partially written reserved track" },
+-	{ 0x057205, "No more RZONE reservations are allowed" },
+-	{ 0x05bf00, "Loss of streaming" },
+-	{ 0x062800, "Not ready to ready transition, medium may have changed" },
+-	{ 0x062900, "Power on, reset or hardware reset occurred" },
+-	{ 0x062a00, "Parameters changed" },
+-	{ 0x062a01, "Mode parameters changed" },
+-	{ 0x062e00, "Insufficient time for operation" },
+-	{ 0x063f00, "Logical unit operating conditions have changed" },
+-	{ 0x063f01, "Microcode has been changed" },
+-	{ 0x065a00, "Operator request or state change input (unspecified)" },
+-	{ 0x065a01, "Operator medium removal request" },
+-	{ 0x0bb900, "Play operation aborted" },
+-
+-	/* Here we use 0xff for the key (not a valid key) to signify
+-	 * that these can have _any_ key value associated with them... */
+-	{ 0xff0401, "Logical unit is in process of becoming ready" },
+-	{ 0xff0400, "Logical unit not ready, cause not reportable" },
+-	{ 0xff0402, "Logical unit not ready, initializing command required" },
+-	{ 0xff0403, "Logical unit not ready, manual intervention required" },
+-	{ 0xff0500, "Logical unit does not respond to selection" },
+-	{ 0xff0800, "Logical unit communication failure" },
+-	{ 0xff0802, "Logical unit communication parity error" },
+-	{ 0xff0801, "Logical unit communication time-out" },
+-	{ 0xff2500, "Logical unit not supported" },
+-	{ 0xff4c00, "Logical unit failed self-configuration" },
+-	{ 0xff3e00, "Logical unit has not self-configured yet" },
+-};
+-#endif
+-
++/* ide-cd_verbose.c */
++void ide_cd_log_error(const char *, struct request *, struct request_sense *);
++
++/* ide-cd.c functions used by ide-cd_ioctl.c */
++void ide_cd_init_rq(ide_drive_t *, struct request *);
++int ide_cd_queue_pc(ide_drive_t *, struct request *);
++int ide_cd_read_toc(ide_drive_t *, struct request_sense *);
++int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
++void ide_cdrom_update_speed(ide_drive_t *, u8 *);
++int cdrom_check_status(ide_drive_t *, struct request_sense *);
++
++/* ide-cd_ioctl.c */
++int ide_cdrom_open_real(struct cdrom_device_info *, int);
++void ide_cdrom_release_real(struct cdrom_device_info *);
++int ide_cdrom_drive_status(struct cdrom_device_info *, int);
++int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int);
++int ide_cdrom_tray_move(struct cdrom_device_info *, int);
++int ide_cdrom_lock_door(struct cdrom_device_info *, int);
++int ide_cdrom_select_speed(struct cdrom_device_info *, int);
++int ide_cdrom_get_last_session(struct cdrom_device_info *,
++			       struct cdrom_multisession *);
++int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
++int ide_cdrom_reset(struct cdrom_device_info *cdi);
++int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
++int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *);
+ 
+ #endif /* _IDE_CD_H */
+diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
+new file mode 100644
+index 0000000..b68284d
+--- /dev/null
++++ b/drivers/ide/ide-cd_ioctl.c
+@@ -0,0 +1,475 @@
++/*
++ * cdrom.c IOCTLs handling for ide-cd driver.
++ *
++ * Copyright (C) 1994-1996  Scott Snyder <snyder at fnald0.fnal.gov>
++ * Copyright (C) 1996-1998  Erik Andersen <andersee at debian.org>
++ * Copyright (C) 1998-2000  Jens Axboe <axboe at suse.de>
++ */
++
++#include <linux/kernel.h>
++#include <linux/cdrom.h>
++#include <linux/ide.h>
++#include <scsi/scsi.h>
++
++#include "ide-cd.h"
++
++/****************************************************************************
++ * Other driver requests (open, close, check media change).
++ */
++int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
++{
++	return 0;
++}
++
++/*
++ * Close down the device.  Invalidate all cached blocks.
++ */
++void ide_cdrom_release_real(struct cdrom_device_info *cdi)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct cdrom_info *cd = drive->driver_data;
++
++	if (!cdi->use_count)
++		cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
++}
++
++/*
++ * add logic to try GET_EVENT command first to check for media and tray
++ * status. this should be supported by newer cd-r/w and all DVD etc
++ * drives
++ */
++int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct media_event_desc med;
++	struct request_sense sense;
++	int stat;
++
++	if (slot_nr != CDSL_CURRENT)
++		return -EINVAL;
++
++	stat = cdrom_check_status(drive, &sense);
++	if (!stat || sense.sense_key == UNIT_ATTENTION)
++		return CDS_DISC_OK;
++
++	if (!cdrom_get_media_event(cdi, &med)) {
++		if (med.media_present)
++			return CDS_DISC_OK;
++		else if (med.door_open)
++			return CDS_TRAY_OPEN;
++		else
++			return CDS_NO_DISC;
++	}
++
++	if (sense.sense_key == NOT_READY && sense.asc == 0x04
++			&& sense.ascq == 0x04)
++		return CDS_DISC_OK;
++
++	/*
++	 * If not using Mt Fuji extended media tray reports,
++	 * just return TRAY_OPEN since ATAPI doesn't provide
++	 * any other way to detect this...
++	 */
++	if (sense.sense_key == NOT_READY) {
++		if (sense.asc == 0x3a && sense.ascq == 1)
++			return CDS_NO_DISC;
++		else
++			return CDS_TRAY_OPEN;
++	}
++	return CDS_DRIVE_NOT_READY;
++}
++
++int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
++				       int slot_nr)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct cdrom_info *cd = drive->driver_data;
++	int retval;
++
++	if (slot_nr == CDSL_CURRENT) {
++		(void) cdrom_check_status(drive, NULL);
++		retval = (cd->cd_flags & IDE_CD_FLAG_MEDIA_CHANGED) ? 1 : 0;
++		cd->cd_flags &= ~IDE_CD_FLAG_MEDIA_CHANGED;
++		return retval;
++	} else {
++		return -EINVAL;
++	}
++}
++
++/* Eject the disk if EJECTFLAG is 0.
++   If EJECTFLAG is 1, try to reload the disk. */
++static
++int cdrom_eject(ide_drive_t *drive, int ejectflag,
++		struct request_sense *sense)
++{
++	struct cdrom_info *cd = drive->driver_data;
++	struct cdrom_device_info *cdi = &cd->devinfo;
++	struct request req;
++	char loej = 0x02;
++
++	if ((cd->cd_flags & IDE_CD_FLAG_NO_EJECT) && !ejectflag)
++		return -EDRIVE_CANT_DO_THIS;
++
++	/* reload fails on some drives, if the tray is locked */
++	if ((cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) && ejectflag)
++		return 0;
++
++	ide_cd_init_rq(drive, &req);
++
++	/* only tell drive to close tray if open, if it can do that */
++	if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
++		loej = 0;
++
++	req.sense = sense;
++	req.cmd[0] = GPCMD_START_STOP_UNIT;
++	req.cmd[4] = loej | (ejectflag != 0);
++
++	return ide_cd_queue_pc(drive, &req);
++}
++
++/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
++static
++int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
++		    struct request_sense *sense)
++{
++	struct cdrom_info *cd = drive->driver_data;
++	struct request_sense my_sense;
++	struct request req;
++	int stat;
++
++	if (sense == NULL)
++		sense = &my_sense;
++
++	/* If the drive cannot lock the door, just pretend. */
++	if (cd->cd_flags & IDE_CD_FLAG_NO_DOORLOCK) {
++		stat = 0;
++	} else {
++		ide_cd_init_rq(drive, &req);
++		req.sense = sense;
++		req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
++		req.cmd[4] = lockflag ? 1 : 0;
++		stat = ide_cd_queue_pc(drive, &req);
++	}
++
++	/* If we got an illegal field error, the drive
++	   probably cannot lock the door. */
++	if (stat != 0 &&
++	    sense->sense_key == ILLEGAL_REQUEST &&
++	    (sense->asc == 0x24 || sense->asc == 0x20)) {
++		printk(KERN_ERR "%s: door locking not supported\n",
++			drive->name);
++		cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
++		stat = 0;
++	}
++
++	/* no medium, that's alright. */
++	if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
++		stat = 0;
++
++	if (stat == 0) {
++		if (lockflag)
++			cd->cd_flags |= IDE_CD_FLAG_DOOR_LOCKED;
++		else
++			cd->cd_flags &= ~IDE_CD_FLAG_DOOR_LOCKED;
++	}
++
++	return stat;
++}
++
++int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct request_sense sense;
++
++	if (position) {
++		int stat = ide_cd_lockdoor(drive, 0, &sense);
++
++		if (stat)
++			return stat;
++	}
++
++	return cdrom_eject(drive, !position, &sense);
++}
++
++int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
++{
++	ide_drive_t *drive = cdi->handle;
++
++	return ide_cd_lockdoor(drive, lock, NULL);
++}
++
++/*
++ * ATAPI devices are free to select the speed you request or any slower
++ * rate. :-(  Requesting too fast a speed will _not_ produce an error.
++ */
++int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct cdrom_info *cd = drive->driver_data;
++	struct request rq;
++	struct request_sense sense;
++	u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
++	int stat;
++
++	ide_cd_init_rq(drive, &rq);
++
++	rq.sense = &sense;
++
++	if (speed == 0)
++		speed = 0xffff; /* set to max */
++	else
++		speed *= 177;   /* Nx to kbytes/s */
++
++	rq.cmd[0] = GPCMD_SET_SPEED;
++	/* Read Drive speed in kbytes/second MSB/LSB */
++	rq.cmd[2] = (speed >> 8) & 0xff;
++	rq.cmd[3] = speed & 0xff;
++	if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
++	    (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
++		/* Write Drive speed in kbytes/second MSB/LSB */
++		rq.cmd[4] = (speed >> 8) & 0xff;
++		rq.cmd[5] = speed & 0xff;
++	}
++
++	stat = ide_cd_queue_pc(drive, &rq);
++
++	if (!ide_cdrom_get_capabilities(drive, buf)) {
++		ide_cdrom_update_speed(drive, buf);
++		cdi->speed = cd->current_speed;
++	}
++
++	return 0;
++}
++
++int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
++			       struct cdrom_multisession *ms_info)
++{
++	struct atapi_toc *toc;
++	ide_drive_t *drive = cdi->handle;
++	struct cdrom_info *info = drive->driver_data;
++	struct request_sense sense;
++	int ret;
++
++	if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0 || !info->toc) {
++		ret = ide_cd_read_toc(drive, &sense);
++		if (ret)
++			return ret;
++	}
++
++	toc = info->toc;
++	ms_info->addr.lba = toc->last_session_lba;
++	ms_info->xa_flag = toc->xa_flag;
++
++	return 0;
++}
++
++int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
++		      struct cdrom_mcn *mcn_info)
++{
++	ide_drive_t *drive = cdi->handle;
++	int stat, mcnlen;
++	struct request rq;
++	char buf[24];
++
++	ide_cd_init_rq(drive, &rq);
++
++	rq.data = buf;
++	rq.data_len = sizeof(buf);
++
++	rq.cmd[0] = GPCMD_READ_SUBCHANNEL;
++	rq.cmd[1] = 2;		/* MSF addressing */
++	rq.cmd[2] = 0x40;	/* request subQ data */
++	rq.cmd[3] = 2;		/* format */
++	rq.cmd[8] = sizeof(buf);
++
++	stat = ide_cd_queue_pc(drive, &rq);
++	if (stat)
++		return stat;
++
++	mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
++	memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
++	mcn_info->medium_catalog_number[mcnlen] = '\0';
++
++	return 0;
++}
++
++int ide_cdrom_reset(struct cdrom_device_info *cdi)
++{
++	ide_drive_t *drive = cdi->handle;
++	struct cdrom_info *cd = drive->driver_data;
++	struct request_sense sense;
++	struct request req;
++	int ret;
++
++	ide_cd_init_rq(drive, &req);
++	req.cmd_type = REQ_TYPE_SPECIAL;
++	req.cmd_flags = REQ_QUIET;
++	ret = ide_do_drive_cmd(drive, &req, ide_wait);
++
++	/*
++	 * A reset will unlock the door. If it was previously locked,
++	 * lock it again.
++	 */
++	if (cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED)
++		(void)ide_cd_lockdoor(drive, 1, &sense);
++
++	return ret;
++}
++
++static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
++				struct atapi_toc_entry **ent)
++{
++	struct cdrom_info *info = drive->driver_data;
++	struct atapi_toc *toc = info->toc;
++	int ntracks;
++
++	/*
++	 * don't serve cached data, if the toc isn't valid
++	 */
++	if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0)
++		return -EINVAL;
++
++	/* Check validity of requested track number. */
++	ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
++
++	if (toc->hdr.first_track == CDROM_LEADOUT)
++		ntracks = 0;
++
++	if (track == CDROM_LEADOUT)
++		*ent = &toc->ent[ntracks];
++	else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
++		return -EINVAL;
++	else
++		*ent = &toc->ent[track - toc->hdr.first_track];
++
++	return 0;
++}
++
++static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
++{
++	struct cdrom_ti *ti = arg;
++	struct atapi_toc_entry *first_toc, *last_toc;
++	unsigned long lba_start, lba_end;
++	int stat;
++	struct request rq;
++	struct request_sense sense;
++
++	stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
++	if (stat)
++		return stat;
++
++	stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
++	if (stat)
++		return stat;
++
++	if (ti->cdti_trk1 != CDROM_LEADOUT)
++		++last_toc;
++	lba_start = first_toc->addr.lba;
++	lba_end   = last_toc->addr.lba;
++
++	if (lba_end <= lba_start)
++		return -EINVAL;
++
++	ide_cd_init_rq(drive, &rq);
++
++	rq.sense = &sense;
++	rq.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
++	lba_to_msf(lba_start,   &rq.cmd[3], &rq.cmd[4], &rq.cmd[5]);
++	lba_to_msf(lba_end - 1, &rq.cmd[6], &rq.cmd[7], &rq.cmd[8]);
++
++	return ide_cd_queue_pc(drive, &rq);
++}
++
++static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
++{
++	struct cdrom_info *cd = drive->driver_data;
++	struct cdrom_tochdr *tochdr = arg;
++	struct atapi_toc *toc;
++	int stat;
++
++	/* Make sure our saved TOC is valid. */
++	stat = ide_cd_read_toc(drive, NULL);
++	if (stat)
++		return stat;
++
++	toc = cd->toc;
++	tochdr->cdth_trk0 = toc->hdr.first_track;
++	tochdr->cdth_trk1 = toc->hdr.last_track;
++
++	return 0;
++}
++
++static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
++{
++	struct cdrom_tocentry *tocentry = arg;
++	struct atapi_toc_entry *toce;
++	int stat;
++
++	stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
++	if (stat)
++		return stat;
++
++	tocentry->cdte_ctrl = toce->control;
++	tocentry->cdte_adr  = toce->adr;
++	if (tocentry->cdte_format == CDROM_MSF) {
++		lba_to_msf(toce->addr.lba,
++			   &tocentry->cdte_addr.msf.minute,
++			   &tocentry->cdte_addr.msf.second,
++			   &tocentry->cdte_addr.msf.frame);
++	} else
++		tocentry->cdte_addr.lba = toce->addr.lba;
++
++	return 0;
++}
++
++int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
++			  unsigned int cmd, void *arg)
++{
++	ide_drive_t *drive = cdi->handle;
++
++	switch (cmd) {
++	/*
++	 * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
++	 * atapi doesn't support it
++	 */
++	case CDROMPLAYTRKIND:
++		return ide_cd_fake_play_trkind(drive, arg);
++	case CDROMREADTOCHDR:
++		return ide_cd_read_tochdr(drive, arg);
++	case CDROMREADTOCENTRY:
++		return ide_cd_read_tocentry(drive, arg);
++	default:
++		return -EINVAL;
++	}
++}
++
++/* the generic packet interface to cdrom.c */
++int ide_cdrom_packet(struct cdrom_device_info *cdi,
++			    struct packet_command *cgc)
++{
++	struct request req;
++	ide_drive_t *drive = cdi->handle;
++
++	if (cgc->timeout <= 0)
++		cgc->timeout = ATAPI_WAIT_PC;
++
++	/* here we queue the commands from the uniform CD-ROM
++	   layer. the packet must be complete, as we do not
++	   touch it at all. */
++	ide_cd_init_rq(drive, &req);
++	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
++	if (cgc->sense)
++		memset(cgc->sense, 0, sizeof(struct request_sense));
++	req.data = cgc->buffer;
++	req.data_len = cgc->buflen;
++	req.timeout = cgc->timeout;
++
++	if (cgc->quiet)
++		req.cmd_flags |= REQ_QUIET;
++
++	req.sense = cgc->sense;
++	cgc->stat = ide_cd_queue_pc(drive, &req);
++	if (!cgc->stat)
++		cgc->buflen -= req.data_len;
++	return cgc->stat;
++}
+diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
+new file mode 100644
+index 0000000..6ed7ca0
+--- /dev/null
++++ b/drivers/ide/ide-cd_verbose.c
+@@ -0,0 +1,359 @@
++/*
++ * Verbose error logging for ATAPI CD/DVD devices.
++ *
++ * Copyright (C) 1994-1996  Scott Snyder <snyder at fnald0.fnal.gov>
++ * Copyright (C) 1996-1998  Erik Andersen <andersee at debian.org>
++ * Copyright (C) 1998-2000  Jens Axboe <axboe at suse.de>
++ */
++
++#include <linux/kernel.h>
++#include <linux/blkdev.h>
++#include <linux/cdrom.h>
++#include <scsi/scsi.h>
++
++#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
++void ide_cd_log_error(const char *name, struct request *failed_command,
++		      struct request_sense *sense)
++{
++	/* Suppress printing unit attention and `in progress of becoming ready'
++	   errors when we're not being verbose. */
++	if (sense->sense_key == UNIT_ATTENTION ||
++	    (sense->sense_key == NOT_READY && (sense->asc == 4 ||
++						sense->asc == 0x3a)))
++		return;
++
++	printk(KERN_ERR "%s: error code: 0x%02x  sense_key: 0x%02x  "
++			"asc: 0x%02x  ascq: 0x%02x\n",
++			name, sense->error_code, sense->sense_key,
++			sense->asc, sense->ascq);
++}
++#else
++/* The generic packet command opcodes for CD/DVD Logical Units,
++ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
++static const struct {
++	unsigned short packet_command;
++	const char * const text;
++} packet_command_texts[] = {
++	{ GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
++	{ GPCMD_REQUEST_SENSE, "Request Sense" },
++	{ GPCMD_FORMAT_UNIT, "Format Unit" },
++	{ GPCMD_INQUIRY, "Inquiry" },
++	{ GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
++	{ GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
++	{ GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
++	{ GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
++	{ GPCMD_READ_10, "Read 10" },
++	{ GPCMD_WRITE_10, "Write 10" },
++	{ GPCMD_SEEK, "Seek" },
++	{ GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
++	{ GPCMD_VERIFY_10, "Verify 10" },
++	{ GPCMD_FLUSH_CACHE, "Flush Cache" },
++	{ GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
++	{ GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
++	{ GPCMD_READ_HEADER, "Read Header" },
++	{ GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
++	{ GPCMD_GET_CONFIGURATION, "Get Configuration" },
++	{ GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
++	{ GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
++	{ GPCMD_GET_EVENT_STATUS_NOTIFICATION,
++		"Get Event Status Notification" },
++	{ GPCMD_PAUSE_RESUME, "Pause/Resume" },
++	{ GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
++	{ GPCMD_READ_DISC_INFO, "Read Disc Info" },
++	{ GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
++	{ GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
++	{ GPCMD_SEND_OPC, "Send OPC" },
++	{ GPCMD_MODE_SELECT_10, "Mode Select 10" },
++	{ GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
++	{ GPCMD_MODE_SENSE_10, "Mode Sense 10" },
++	{ GPCMD_CLOSE_TRACK, "Close Track" },
++	{ GPCMD_BLANK, "Blank" },
++	{ GPCMD_SEND_EVENT, "Send Event" },
++	{ GPCMD_SEND_KEY, "Send Key" },
++	{ GPCMD_REPORT_KEY, "Report Key" },
++	{ GPCMD_LOAD_UNLOAD, "Load/Unload" },
++	{ GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
++	{ GPCMD_READ_12, "Read 12" },
++	{ GPCMD_GET_PERFORMANCE, "Get Performance" },
++	{ GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
++	{ GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
++	{ GPCMD_SET_STREAMING, "Set Streaming" },
++	{ GPCMD_READ_CD_MSF, "Read CD MSF" },
++	{ GPCMD_SCAN, "Scan" },
++	{ GPCMD_SET_SPEED, "Set Speed" },
++	{ GPCMD_PLAY_CD, "Play CD" },
++	{ GPCMD_MECHANISM_STATUS, "Mechanism Status" },
++	{ GPCMD_READ_CD, "Read CD" },
++};
++
++/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
++static const char * const sense_key_texts[16] = {
++	"No sense data",
++	"Recovered error",
++	"Not ready",
++	"Medium error",
++	"Hardware error",
++	"Illegal request",
++	"Unit attention",
++	"Data protect",
++	"Blank check",
++	"(reserved)",
++	"(reserved)",
++	"Aborted command",
++	"(reserved)",
++	"(reserved)",
++	"Miscompare",
++	"(reserved)",
++};
++
++/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
++static const struct {
++	unsigned long asc_ascq;
++	const char * const text;
++} sense_data_texts[] = {
++	{ 0x000000, "No additional sense information" },
++	{ 0x000011, "Play operation in progress" },
++	{ 0x000012, "Play operation paused" },
++	{ 0x000013, "Play operation successfully completed" },
++	{ 0x000014, "Play operation stopped due to error" },
++	{ 0x000015, "No current audio status to return" },
++	{ 0x010c0a, "Write error - padding blocks added" },
++	{ 0x011700, "Recovered data with no error correction applied" },
++	{ 0x011701, "Recovered data with retries" },
++	{ 0x011702, "Recovered data with positive head offset" },
++	{ 0x011703, "Recovered data with negative head offset" },
++	{ 0x011704, "Recovered data with retries and/or CIRC applied" },
++	{ 0x011705, "Recovered data using previous sector ID" },
++	{ 0x011800, "Recovered data with error correction applied" },
++	{ 0x011801, "Recovered data with error correction and retries applied"},
++	{ 0x011802, "Recovered data - the data was auto-reallocated" },
++	{ 0x011803, "Recovered data with CIRC" },
++	{ 0x011804, "Recovered data with L-EC" },
++	{ 0x015d00, "Failure prediction threshold exceeded"
++		    " - Predicted logical unit failure" },
++	{ 0x015d01, "Failure prediction threshold exceeded"
++		    " - Predicted media failure" },
++	{ 0x015dff, "Failure prediction threshold exceeded - False" },
++	{ 0x017301, "Power calibration area almost full" },
++	{ 0x020400, "Logical unit not ready - cause not reportable" },
++	/* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
++	{ 0x020401, "Logical unit not ready"
++		    " - in progress [sic] of becoming ready" },
++	{ 0x020402, "Logical unit not ready - initializing command required" },
++	{ 0x020403, "Logical unit not ready - manual intervention required" },
++	{ 0x020404, "Logical unit not ready - format in progress" },
++	{ 0x020407, "Logical unit not ready - operation in progress" },
++	{ 0x020408, "Logical unit not ready - long write in progress" },
++	{ 0x020600, "No reference position found (media may be upside down)" },
++	{ 0x023000, "Incompatible medium installed" },
++	{ 0x023a00, "Medium not present" },
++	{ 0x025300, "Media load or eject failed" },
++	{ 0x025700, "Unable to recover table of contents" },
++	{ 0x030300, "Peripheral device write fault" },
++	{ 0x030301, "No write current" },
++	{ 0x030302, "Excessive write errors" },
++	{ 0x030c00, "Write error" },
++	{ 0x030c01, "Write error - Recovered with auto reallocation" },
++	{ 0x030c02, "Write error - auto reallocation failed" },
++	{ 0x030c03, "Write error - recommend reassignment" },
++	{ 0x030c04, "Compression check miscompare error" },
++	{ 0x030c05, "Data expansion occurred during compress" },
++	{ 0x030c06, "Block not compressible" },
++	{ 0x030c07, "Write error - recovery needed" },
++	{ 0x030c08, "Write error - recovery failed" },
++	{ 0x030c09, "Write error - loss of streaming" },
++	{ 0x031100, "Unrecovered read error" },
++	{ 0x031106, "CIRC unrecovered error" },
++	{ 0x033101, "Format command failed" },
++	{ 0x033200, "No defect spare location available" },
++	{ 0x033201, "Defect list update failure" },
++	{ 0x035100, "Erase failure" },
++	{ 0x037200, "Session fixation error" },
++	{ 0x037201, "Session fixation error writin lead-in" },
++	{ 0x037202, "Session fixation error writin lead-out" },
++	{ 0x037300, "CD control error" },
++	{ 0x037302, "Power calibration area is full" },
++	{ 0x037303, "Power calibration area error" },
++	{ 0x037304, "Program memory area / RMA update failure" },
++	{ 0x037305, "Program memory area / RMA is full" },
++	{ 0x037306, "Program memory area / RMA is (almost) full" },
++	{ 0x040200, "No seek complete" },
++	{ 0x040300, "Write fault" },
++	{ 0x040900, "Track following error" },
++	{ 0x040901, "Tracking servo failure" },
++	{ 0x040902, "Focus servo failure" },
++	{ 0x040903, "Spindle servo failure" },
++	{ 0x041500, "Random positioning error" },
++	{ 0x041501, "Mechanical positioning or changer error" },
++	{ 0x041502, "Positioning error detected by read of medium" },
++	{ 0x043c00, "Mechanical positioning or changer error" },
++	{ 0x044000, "Diagnostic failure on component (ASCQ)" },
++	{ 0x044400, "Internal CD/DVD logical unit failure" },
++	{ 0x04b600, "Media load mechanism failed" },
++	{ 0x051a00, "Parameter list length error" },
++	{ 0x052000, "Invalid command operation code" },
++	{ 0x052100, "Logical block address out of range" },
++	{ 0x052102, "Invalid address for write" },
++	{ 0x052400, "Invalid field in command packet" },
++	{ 0x052600, "Invalid field in parameter list" },
++	{ 0x052601, "Parameter not supported" },
++	{ 0x052602, "Parameter value invalid" },
++	{ 0x052700, "Write protected media" },
++	{ 0x052c00, "Command sequence error" },
++	{ 0x052c03, "Current program area is not empty" },
++	{ 0x052c04, "Current program area is empty" },
++	{ 0x053001, "Cannot read medium - unknown format" },
++	{ 0x053002, "Cannot read medium - incompatible format" },
++	{ 0x053900, "Saving parameters not supported" },
++	{ 0x054e00, "Overlapped commands attempted" },
++	{ 0x055302, "Medium removal prevented" },
++	{ 0x055500, "System resource failure" },
++	{ 0x056300, "End of user area encountered on this track" },
++	{ 0x056400, "Illegal mode for this track or incompatible medium" },
++	{ 0x056f00, "Copy protection key exchange failure"
++		    " - Authentication failure" },
++	{ 0x056f01, "Copy protection key exchange failure - Key not present" },
++	{ 0x056f02, "Copy protection key exchange failure"
++		     " - Key not established" },
++	{ 0x056f03, "Read of scrambled sector without authentication" },
++	{ 0x056f04, "Media region code is mismatched to logical unit" },
++	{ 0x056f05, "Drive region must be permanent"
++		    " / region reset count error" },
++	{ 0x057203, "Session fixation error - incomplete track in session" },
++	{ 0x057204, "Empty or partially written reserved track" },
++	{ 0x057205, "No more RZONE reservations are allowed" },
++	{ 0x05bf00, "Loss of streaming" },
++	{ 0x062800, "Not ready to ready transition, medium may have changed" },
++	{ 0x062900, "Power on, reset or hardware reset occurred" },
++	{ 0x062a00, "Parameters changed" },
++	{ 0x062a01, "Mode parameters changed" },
++	{ 0x062e00, "Insufficient time for operation" },
++	{ 0x063f00, "Logical unit operating conditions have changed" },
++	{ 0x063f01, "Microcode has been changed" },
++	{ 0x065a00, "Operator request or state change input (unspecified)" },
++	{ 0x065a01, "Operator medium removal request" },
++	{ 0x0bb900, "Play operation aborted" },
++	/* Here we use 0xff for the key (not a valid key) to signify
++	 * that these can have _any_ key value associated with them... */
++	{ 0xff0401, "Logical unit is in process of becoming ready" },
++	{ 0xff0400, "Logical unit not ready, cause not reportable" },
++	{ 0xff0402, "Logical unit not ready, initializing command required" },
++	{ 0xff0403, "Logical unit not ready, manual intervention required" },
++	{ 0xff0500, "Logical unit does not respond to selection" },
++	{ 0xff0800, "Logical unit communication failure" },
++	{ 0xff0802, "Logical unit communication parity error" },
++	{ 0xff0801, "Logical unit communication time-out" },
++	{ 0xff2500, "Logical unit not supported" },
++	{ 0xff4c00, "Logical unit failed self-configuration" },
++	{ 0xff3e00, "Logical unit has not self-configured yet" },
++};
++
++void ide_cd_log_error(const char *name, struct request *failed_command,
++		      struct request_sense *sense)
++{
++	int i;
++	const char *s = "bad sense key!";
++	char buf[80];
++
++	printk(KERN_ERR "ATAPI device %s:\n", name);
++	if (sense->error_code == 0x70)
++		printk(KERN_CONT "  Error: ");
++	else if (sense->error_code == 0x71)
++		printk("  Deferred Error: ");
++	else if (sense->error_code == 0x7f)
++		printk(KERN_CONT "  Vendor-specific Error: ");
++	else
++		printk(KERN_CONT "  Unknown Error Type: ");
++
++	if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
++		s = sense_key_texts[sense->sense_key];
++
++	printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
++
++	if (sense->asc == 0x40) {
++		sprintf(buf, "Diagnostic failure on component 0x%02x",
++			sense->ascq);
++		s = buf;
++	} else {
++		int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
++		unsigned long key = (sense->sense_key << 16);
++
++		key |= (sense->asc << 8);
++		if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
++			key |= sense->ascq;
++		s = NULL;
++
++		while (hi > lo) {
++			mid = (lo + hi) / 2;
++			if (sense_data_texts[mid].asc_ascq == key ||
++			    sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
++				s = sense_data_texts[mid].text;
++				break;
++			} else if (sense_data_texts[mid].asc_ascq > key)
++				hi = mid;
++			else
++				lo = mid + 1;
++		}
++	}
++
++	if (s == NULL) {
++		if (sense->asc > 0x80)
++			s = "(vendor-specific error)";
++		else
++			s = "(reserved error code)";
++	}
++
++	printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
++			s, sense->asc, sense->ascq);
++
++	if (failed_command != NULL) {
++		int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts);
++		s = NULL;
++
++		while (hi > lo) {
++			mid = (lo + hi) / 2;
++			if (packet_command_texts[mid].packet_command ==
++			    failed_command->cmd[0]) {
++				s = packet_command_texts[mid].text;
++				break;
++			}
++			if (packet_command_texts[mid].packet_command >
++			    failed_command->cmd[0])
++				hi = mid;
++			else
++				lo = mid + 1;
++		}
++
++		printk(KERN_ERR "  The failed \"%s\" packet command "
++				"was: \n  \"", s);
++		for (i = 0; i < sizeof(failed_command->cmd); i++)
++			printk(KERN_CONT "%02x ", failed_command->cmd[i]);
++		printk(KERN_CONT "\"\n");
++	}
++
++	/* The SKSV bit specifies validity of the sense_key_specific
++	 * in the next two commands. It is bit 7 of the first byte.
++	 * In the case of NOT_READY, if SKSV is set the drive can
++	 * give us nice ETA readings.
++	 */
++	if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
++		int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
++
++		printk(KERN_ERR "  Command is %02d%% complete\n",
++				progress / 0xffff);
++	}
++
++	if (sense->sense_key == ILLEGAL_REQUEST &&
++	    (sense->sks[0] & 0x80) != 0) {
++		printk(KERN_ERR "  Error in %s byte %d",
++				(sense->sks[0] & 0x40) != 0 ?
++				"command packet" : "command data",
++				(sense->sks[1] << 8) + sense->sks[2]);
++
++		if ((sense->sks[0] & 0x40) != 0)
++			printk(KERN_CONT " bit %d", sense->sks[0] & 0x07);
++
++		printk(KERN_CONT "\n");
++	}
++}
++#endif
+diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
+index b178190..3c69822 100644
+--- a/drivers/ide/ide-disk.c
++++ b/drivers/ide/ide-disk.c
+@@ -1,10 +1,9 @@
+ /*
+- *  linux/drivers/ide/ide-disk.c	Version 1.18	Mar 05, 2003
+- *
+- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+- *  Copyright (C) 1998-2002  Linux ATA Development
+- *				Andre Hedrick <andre at linux-ide.org>
+- *  Copyright (C) 2003	     Red Hat <alan at redhat.com>
++ *  Copyright (C) 1994-1998	   Linus Torvalds & authors (see below)
++ *  Copyright (C) 1998-2002	   Linux ATA Development
++ *				      Andre Hedrick <andre at linux-ide.org>
++ *  Copyright (C) 2003		   Red Hat <alan at redhat.com>
++ *  Copyright (C) 2003-2005, 2007  Bartlomiej Zolnierkiewicz
+  */
+ 
+ /*
+@@ -129,6 +128,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
+ 	return 0;	/* lba_capacity value may be bad */
+ }
+ 
++static const u8 ide_rw_cmds[] = {
++	WIN_MULTREAD,
++	WIN_MULTWRITE,
++	WIN_MULTREAD_EXT,
++	WIN_MULTWRITE_EXT,
++	WIN_READ,
++	WIN_WRITE,
++	WIN_READ_EXT,
++	WIN_WRITE_EXT,
++	WIN_READDMA,
++	WIN_WRITEDMA,
++	WIN_READDMA_EXT,
++	WIN_WRITEDMA_EXT,
++};
++
++static const u8 ide_data_phases[] = {
++	TASKFILE_MULTI_IN,
++	TASKFILE_MULTI_OUT,
++	TASKFILE_IN,
++	TASKFILE_OUT,
++	TASKFILE_IN_DMA,
++	TASKFILE_OUT_DMA,
++};
++
++static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
++{
++	u8 index, lba48, write;
++
++	lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
++	write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
++
++	if (dma)
++		index = drive->vdma ? 4 : 8;
++	else
++		index = drive->mult_count ? 0 : 4;
++
++	task->tf.command = ide_rw_cmds[index + lba48 + write];
++
++	if (dma)
++		index = 8; /* fixup index */
++
++	task->data_phase = ide_data_phases[index / 2 + write];
++}
++
+ /*
+  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
+  * using LBA if supported, or CHS otherwise, to address sectors.
+@@ -137,11 +180,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+ 	unsigned int dma	= drive->using_dma;
++	u16 nsectors		= (u16)rq->nr_sectors;
+ 	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+-	task_ioreg_t command	= WIN_NOP;
 -	ata_nsector_t		nsectors;
 -
 -	nsectors.all		= (u16) rq->nr_sectors;
@@ -386895,7 +401815,7 @@
  
  	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
  		if (block + rq->nr_sectors > 1ULL << 28)
-@@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+@@ -155,121 +198,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
  		ide_map_sg(drive, rq);
  	}
  
@@ -387014,7 +401934,9 @@
 -	}
 -
 -	if (rq_data_dir(rq) == READ) {
--
++	if (rq_data_dir(rq))
++		task.tf_flags |= IDE_TFLAG_WRITE;
+ 
 -		if (drive->mult_count) {
 -			hwif->data_phase = TASKFILE_MULTI_IN;
 -			command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
@@ -387022,9 +401944,7 @@
 -			hwif->data_phase = TASKFILE_IN;
 -			command = lba48 ? WIN_READ_EXT : WIN_READ;
 -		}
-+	if (rq_data_dir(rq))
-+		task.tf_flags |= IDE_TFLAG_WRITE;
- 
+-
 -		ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
 -		return ide_started;
 -	} else {
@@ -387058,7 +401978,7 @@
  }
  
  /*
-@@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
+@@ -307,57 +300,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
   * Queries for true maximum capacity of the drive.
   * Returns maximum LBA address (> 0) of the drive, 0 if failed.
   */
@@ -387130,13 +402050,14 @@
  	return addr;
  }
  
-@@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
+@@ -365,67 +330,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
   * Sets maximum virtual LBA address of the drive.
   * Returns new maximum virtual LBA address (> 0) or 0 on failure.
   */
 -static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
--{
--	ide_task_t args;
++static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
+ {
+ 	ide_task_t args;
 -	unsigned long addr_set = 0;
 -	
 -	addr_req--;
@@ -387163,9 +402084,8 @@
 -}
 -
 -static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
-+static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
- {
- 	ide_task_t args;
+-{
+-	ide_task_t args;
 -	unsigned long long addr_set = 0;
 +	struct ide_taskfile *tf = &args.tf;
 +	u64 addr_set = 0;
@@ -387221,7 +402141,7 @@
  	return addr_set;
  }
  
-@@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
+@@ -471,10 +406,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
  	int lba48 = idedisk_supports_lba48(drive->id);
  
  	capacity = drive->capacity64;
@@ -387234,7 +402154,7 @@
  
  	if (ide_in_drive_list(drive->id, hpa_list)) {
  		/*
-@@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
+@@ -495,10 +428,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
  			 capacity, sectors_to_MB(capacity),
  			 set_max, sectors_to_MB(set_max));
  
@@ -387247,7 +402167,7 @@
  	if (set_max) {
  		drive->capacity64 = set_max;
  		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
-@@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
+@@ -556,32 +487,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
  static int smart_enable(ide_drive_t *drive)
  {
  	ide_task_t args;
@@ -387296,7 +402216,7 @@
  }
  
  static int proc_idedisk_read_cache
-@@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = {
+@@ -659,19 +590,20 @@ static ide_proc_entry_t idedisk_proc[] = {
  static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
  {
  	ide_drive_t *drive = q->queuedata;
@@ -387324,7 +402244,7 @@
  }
  
  /*
-@@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
+@@ -687,8 +619,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
  
  	if (drive->special.b.set_multmode)
  		return -EBUSY;
@@ -387336,7 +402256,7 @@
  	drive->mult_req = arg;
  	drive->special.b.set_multmode = 1;
  	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-@@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg)
+@@ -753,12 +687,11 @@ static int write_cache(ide_drive_t *drive, int arg)
  
  	if (ide_id_has_flush_cache(drive->id)) {
  		memset(&args, 0, sizeof(ide_task_t));
@@ -387353,7 +402273,7 @@
  		if (err == 0)
  			drive->wcache = arg;
  	}
-@@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
+@@ -774,12 +707,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
  
  	memset(&args, 0, sizeof(ide_task_t));
  	if (ide_id_has_flush_cache_ext(drive->id))
@@ -387370,7 +402290,7 @@
  }
  
  static int set_acoustic (ide_drive_t *drive, int arg)
-@@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
+@@ -790,13 +722,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
  		return -EINVAL;
  
  	memset(&args, 0, sizeof(ide_task_t));
@@ -387389,7 +402309,7 @@
  	drive->acoustic = arg;
  	return 0;
  }
-@@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
+@@ -832,7 +762,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
  	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,			1,	1,	&drive->bios_head,	NULL);
  	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,			1,	1,	&drive->bios_sect,	NULL);
  	ide_add_setting(drive,	"address",	SETTING_RW,	TYPE_BYTE,	0,	2,			1,	1,	&drive->addressing,	set_lba_addressing);
@@ -387397,7 +402317,7 @@
  	ide_add_setting(drive,	"multcount",	SETTING_RW,	TYPE_BYTE,	0,	id->max_multsect,	1,	1,	&drive->mult_count,	set_multcount);
  	ide_add_setting(drive,	"nowerr",	SETTING_RW,	TYPE_BYTE,	0,	1,			1,	1,	&drive->nowerr,		set_nowerr);
  	ide_add_setting(drive,	"lun",		SETTING_RW,	TYPE_INT,	0,	7,			1,	1,	&drive->lun,		NULL);
-@@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = {
+@@ -1041,6 +970,17 @@ static ide_driver_t idedisk_driver = {
  #endif
  };
  
@@ -387415,7 +402335,7 @@
  static int idedisk_open(struct inode *inode, struct file *filp)
  {
  	struct gendisk *disk = inode->i_bdev->bd_disk;
-@@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
+@@ -1055,18 +995,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
  	idkp->openers++;
  
  	if (drive->removable && idkp->openers == 1) {
@@ -387435,7 +402355,7 @@
  			drive->doorlocking = 0;
  	}
  	return 0;
-@@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
+@@ -1082,12 +1017,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
  		ide_cacheflush_p(drive);
  
  	if (drive->removable && idkp->openers == 1) {
@@ -387450,10 +402370,37 @@
  	}
  
 diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
-index 4703837..5bf3203 100644
+index 4703837..7beaf1e 100644
 --- a/drivers/ide/ide-dma.c
 +++ b/drivers/ide/ide-dma.c
-@@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+@@ -1,15 +1,13 @@
+ /*
+- *  linux/drivers/ide/ide-dma.c		Version 4.10	June 9, 2000
++ *  Copyright (C) 1995-1998   Mark Lord
++ *  Copyright (C) 1999-2000   Andre Hedrick <andre at linux-ide.org>
++ *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
+  *
+- *  Copyright (c) 1999-2000	Andre Hedrick <andre at linux-ide.org>
+  *  May be copied or modified under the terms of the GNU General Public License
+  */
+ 
+ /*
+  *  Special Thanks to Mark for his Six years of work.
+- *
+- *  Copyright (c) 1995-1998  Mark Lord
+- *  May be copied or modified under the terms of the GNU General Public License
+  */
+ 
+ /*
+@@ -85,6 +83,7 @@
+ #include <linux/ide.h>
+ #include <linux/delay.h>
+ #include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
+ 
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -153,13 +152,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
  		if (!dma_stat) {
  			struct request *rq = HWGROUP(drive)->rq;
  
@@ -387468,7 +402415,95 @@
  			return ide_stopped;
  		}
  		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-@@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
+@@ -175,16 +168,15 @@ static int ide_dma_good_drive(ide_drive_t *drive)
+ 	return ide_in_drive_list(drive->id, drive_whitelist);
+ }
+ 
+-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ /**
+  *	ide_build_sglist	-	map IDE scatter gather for DMA I/O
+  *	@drive: the drive to build the DMA table for
+  *	@rq: the request holding the sg list
+  *
+- *	Perform the PCI mapping magic necessary to access the source or
+- *	target buffers of a request via PCI DMA. The lower layers of the
++ *	Perform the DMA mapping magic necessary to access the source or
++ *	target buffers of a request via DMA.  The lower layers of the
+  *	kernel provide the necessary cache management so that we can
+- *	operate in a portable fashion
++ *	operate in a portable fashion.
+  */
+ 
+ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
+@@ -192,20 +184,20 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 	struct scatterlist *sg = hwif->sg_table;
+ 
+-	BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256);
+-
+ 	ide_map_sg(drive, rq);
+ 
+ 	if (rq_data_dir(rq) == READ)
+-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++		hwif->sg_dma_direction = DMA_FROM_DEVICE;
+ 	else
+-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
++		hwif->sg_dma_direction = DMA_TO_DEVICE;
+ 
+-	return pci_map_sg(hwif->pci_dev, sg, hwif->sg_nents, hwif->sg_dma_direction);
++	return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
++			  hwif->sg_dma_direction);
+ }
+ 
+ EXPORT_SYMBOL_GPL(ide_build_sglist);
+ 
++#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ /**
+  *	ide_build_dmatable	-	build IDE DMA table
+  *
+@@ -290,16 +282,17 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
+ 			*--table |= cpu_to_le32(0x80000000);
+ 		return count;
+ 	}
++
+ 	printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
++
+ use_pio_instead:
+-	pci_unmap_sg(hwif->pci_dev,
+-		     hwif->sg_table,
+-		     hwif->sg_nents,
+-		     hwif->sg_dma_direction);
++	ide_destroy_dmatable(drive);
++
+ 	return 0; /* revert to PIO for this request */
+ }
+ 
+ EXPORT_SYMBOL_GPL(ide_build_dmatable);
++#endif
+ 
+ /**
+  *	ide_destroy_dmatable	-	clean up DMA mapping
+@@ -314,15 +307,15 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
+  
+ void ide_destroy_dmatable (ide_drive_t *drive)
+ {
+-	struct pci_dev *dev = HWIF(drive)->pci_dev;
+-	struct scatterlist *sg = HWIF(drive)->sg_table;
+-	int nents = HWIF(drive)->sg_nents;
++	ide_hwif_t *hwif = drive->hwif;
+ 
+-	pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
++	dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
++		     hwif->sg_dma_direction);
+ }
+ 
+ EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+ 
++#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+ /**
+  *	config_drive_for_dma	-	attempt to activate IDE DMA
+  *	@drive: the drive to place in DMA mode
+@@ -408,23 +401,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
  }
  
  /**
@@ -387504,7 +402539,7 @@
  
  /**
   *	ide_dma_off_quietly	-	Generic DMA kill
-@@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
+@@ -438,11 +437,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
  	drive->using_dma = 0;
  	ide_toggle_bounce(drive, 0);
  
@@ -387517,7 +402552,7 @@
  
  /**
   *	ide_dma_off	-	disable DMA on a device
-@@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
+@@ -455,56 +453,27 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
  void ide_dma_off(ide_drive_t *drive)
  {
  	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
@@ -387528,7 +402563,7 @@
  EXPORT_SYMBOL(ide_dma_off);
  
 -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
- /**
+-/**
 - *	ide_dma_host_on	-	Enable DMA on a host
 - *	@drive: drive to enable for DMA
 - *
@@ -387549,7 +402584,7 @@
 -
 -EXPORT_SYMBOL(ide_dma_host_on);
 -
--/**
+ /**
 - *	__ide_dma_on		-	Enable DMA on a device
 + *	ide_dma_on		-	Enable DMA on a device
   *	@drive: drive to enable DMA on
@@ -387575,13 +402610,12 @@
  }
  
 -EXPORT_SYMBOL(__ide_dma_on);
-+EXPORT_SYMBOL(ide_dma_on);
- 
+-
 +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
  /**
   *	ide_dma_setup	-	begin a DMA phase
   *	@drive: target device
-@@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
+@@ -759,6 +728,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
  
  static int ide_tune_dma(ide_drive_t *drive)
  {
@@ -387589,7 +402623,7 @@
  	u8 speed;
  
  	if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
-@@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive)
+@@ -771,15 +741,21 @@ static int ide_tune_dma(ide_drive_t *drive)
  	if (ide_id_dma_bug(drive))
  		return 0;
  
@@ -387615,7 +402649,7 @@
  		return 0;
  
  	if (ide_set_dma_mode(drive, speed))
-@@ -824,25 +803,23 @@ err_out:
+@@ -824,25 +800,23 @@ err_out:
  
  int ide_set_dma(ide_drive_t *drive)
  {
@@ -387653,7 +402687,91 @@
  }
  
  #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-@@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+@@ -870,10 +844,10 @@ EXPORT_SYMBOL(ide_dma_timeout);
+ static void ide_release_dma_engine(ide_hwif_t *hwif)
+ {
+ 	if (hwif->dmatable_cpu) {
+-		pci_free_consistent(hwif->pci_dev,
+-				    PRD_ENTRIES * PRD_BYTES,
+-				    hwif->dmatable_cpu,
+-				    hwif->dmatable_dma);
++		struct pci_dev *pdev = to_pci_dev(hwif->dev);
++
++		pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES,
++				    hwif->dmatable_cpu, hwif->dmatable_dma);
+ 		hwif->dmatable_cpu = NULL;
+ 	}
+ }
+@@ -901,7 +875,9 @@ int ide_release_dma(ide_hwif_t *hwif)
+ 
+ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
+ {
+-	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
++
++	hwif->dmatable_cpu = pci_alloc_consistent(pdev,
+ 						  PRD_ENTRIES * PRD_BYTES,
+ 						  &hwif->dmatable_dma);
+ 
+@@ -914,19 +890,19 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
+ 	return 1;
+ }
+ 
+-static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
++static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base)
+ {
+ 	printk(KERN_INFO "    %s: MMIO-DMA ", hwif->name);
+ 
+ 	return 0;
+ }
+ 
+-static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
++static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base)
+ {
+ 	printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
+-	       hwif->name, base, base + ports - 1);
++	       hwif->name, base, base + 7);
+ 
+-	if (!request_region(base, ports, hwif->name)) {
++	if (!request_region(base, 8, hwif->name)) {
+ 		printk(" -- Error, ports in use.\n");
+ 		return 1;
+ 	}
+@@ -938,7 +914,7 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
+ 			if (!request_region(hwif->extra_base,
+ 					    hwif->cds->extra, hwif->cds->name)) {
+ 				printk(" -- Error, extra ports in use.\n");
+-				release_region(base, ports);
++				release_region(base, 8);
+ 				return 1;
+ 			}
+ 			hwif->extra_ports = hwif->cds->extra;
+@@ -948,17 +924,19 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
+ 	return 0;
+ }
+ 
+-static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
++static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base)
+ {
+ 	if (hwif->mmio)
+-		return ide_mapped_mmio_dma(hwif, base,ports);
++		return ide_mapped_mmio_dma(hwif, base);
+ 
+-	return ide_iomio_dma(hwif, base, ports);
++	return ide_iomio_dma(hwif, base);
+ }
+ 
+-void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
++void ide_setup_dma(ide_hwif_t *hwif, unsigned long base)
+ {
+-	if (ide_dma_iobase(hwif, base, num_ports))
++	u8 dma_stat;
++
++	if (ide_dma_iobase(hwif, base))
+ 		return;
+ 
+ 	if (ide_allocate_dma_engine(hwif)) {
+@@ -968,30 +946,19 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
  
  	hwif->dma_base = base;
  
@@ -387662,13 +402780,17 @@
 -	else
 -		hwif->dma_master = base;
 -
- 	if (!(hwif->dma_command))
- 		hwif->dma_command	= hwif->dma_base;
- 	if (!(hwif->dma_vendor1))
-@@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
- 	if (!(hwif->dma_prdtable))
- 		hwif->dma_prdtable	= (hwif->dma_base + 4);
- 
+-	if (!(hwif->dma_command))
+-		hwif->dma_command	= hwif->dma_base;
+-	if (!(hwif->dma_vendor1))
+-		hwif->dma_vendor1	= (hwif->dma_base + 1);
+-	if (!(hwif->dma_status))
+-		hwif->dma_status	= (hwif->dma_base + 2);
+-	if (!(hwif->dma_vendor3))
+-		hwif->dma_vendor3	= (hwif->dma_base + 3);
+-	if (!(hwif->dma_prdtable))
+-		hwif->dma_prdtable	= (hwif->dma_base + 4);
+-
 -	if (!hwif->dma_off_quietly)
 -		hwif->dma_off_quietly = &ide_dma_off_quietly;
 -	if (!hwif->dma_host_off)
@@ -387677,25 +402799,135 @@
 -		hwif->ide_dma_on = &__ide_dma_on;
 -	if (!hwif->dma_host_on)
 -		hwif->dma_host_on = &ide_dma_host_on;
++	if (!hwif->dma_command)
++		hwif->dma_command	= hwif->dma_base + 0;
++	if (!hwif->dma_vendor1)
++		hwif->dma_vendor1	= hwif->dma_base + 1;
++	if (!hwif->dma_status)
++		hwif->dma_status	= hwif->dma_base + 2;
++	if (!hwif->dma_vendor3)
++		hwif->dma_vendor3	= hwif->dma_base + 3;
++	if (!hwif->dma_prdtable)
++		hwif->dma_prdtable	= hwif->dma_base + 4;
++
 +	if (!hwif->dma_host_set)
 +		hwif->dma_host_set = &ide_dma_host_set;
  	if (!hwif->dma_setup)
  		hwif->dma_setup = &ide_dma_setup;
  	if (!hwif->dma_exec_cmd)
-@@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
- 		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
- 	}
- 	printk("\n");
+@@ -1007,15 +974,10 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+ 	if (!hwif->dma_lost_irq)
+ 		hwif->dma_lost_irq = &ide_dma_lost_irq;
+ 
+-	if (hwif->chipset != ide_trm290) {
+-		u8 dma_stat = hwif->INB(hwif->dma_status);
+-		printk(", BIOS settings: %s:%s, %s:%s",
+-		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+-	}
+-	printk("\n");
 -
 -	BUG_ON(!hwif->dma_master);
++	dma_stat = hwif->INB(hwif->dma_status);
++	printk(KERN_CONT ", BIOS settings: %s:%s, %s:%s\n",
++	       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "PIO",
++	       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "PIO");
  }
  
  EXPORT_SYMBOL_GPL(ide_setup_dma);
 diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
-index 04a3578..ff8232e 100644
+index 04a3578..3512637 100644
 --- a/drivers/ide/ide-floppy.c
 +++ b/drivers/ide/ide-floppy.c
-@@ -369,27 +369,6 @@ typedef struct ide_floppy_obj {
+@@ -1,13 +1,12 @@
+ /*
+- * linux/drivers/ide/ide-floppy.c	Version 0.99	Feb 24 2002
++ * IDE ATAPI floppy driver.
+  *
+- * Copyright (C) 1996 - 1999 Gadi Oxman <gadio at netvision.net.il>
+- * Copyright (C) 2000 - 2002 Paul Bristow <paul at paulbristow.net>
++ * Copyright (C) 1996-1999  Gadi Oxman <gadio at netvision.net.il>
++ * Copyright (C) 2000-2002  Paul Bristow <paul at paulbristow.net>
++ * Copyright (C) 2005       Bartlomiej Zolnierkiewicz
+  */
+ 
+ /*
+- * IDE ATAPI floppy driver.
+- *
+  * The driver currently doesn't have any fancy features, just the bare
+  * minimum read/write support.
+  *
+@@ -17,67 +16,8 @@
+  * Iomega Zip 100/250
+  * Iomega PC Card Clik!/PocketZip
+  *
+- * Many thanks to Lode Leroy <Lode.Leroy at www.ibase.be>, who tested so many
+- * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive.
+- *
+- * Ver 0.1   Oct 17 96   Initial test version, mostly based on ide-tape.c.
+- * Ver 0.2   Oct 31 96   Minor changes.
+- * Ver 0.3   Dec  2 96   Fixed error recovery bug.
+- * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
+- * Ver 0.5   Feb 21 97   Add partitions support.
+- *                       Use the minimum of the LBA and CHS capacities.
+- *                       Avoid hwgroup->rq == NULL on the last irq.
+- *                       Fix potential null dereferencing with DEBUG_LOG.
+- * Ver 0.8   Dec  7 97   Increase irq timeout from 10 to 50 seconds.
+- *                       Add media write-protect detection.
+- *                       Issue START command only if TEST UNIT READY fails.
+- *                       Add work-around for IOMEGA ZIP revision 21.D.
+- *                       Remove idefloppy_get_capabilities().
+- * Ver 0.9   Jul  4 99   Fix a bug which might have caused the number of
+- *                        bytes requested on each interrupt to be zero.
+- *                        Thanks to <shanos at es.co.nz> for pointing this out.
+- * Ver 0.9.sv Jan 6 01   Sam Varshavchik <mrsam at courier-mta.com>
+- *                       Implement low level formatting.  Reimplemented
+- *                       IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp
+- *                       bit.  My LS-120 drive barfs on
+- *                       IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me.
+- *                       Compromise by not reporting a failure to get this
+- *                       mode page.  Implemented four IOCTLs in order to
+- *                       implement formatting.  IOCTls begin with 0x4600,
+- *                       0x46 is 'F' as in Format.
+- *            Jan 9 01   Userland option to select format verify.
+- *                       Added PC_SUPPRESS_ERROR flag - some idefloppy drives
+- *                       do not implement IDEFLOPPY_CAPABILITIES_PAGE, and
+- *                       return a sense error.  Suppress error reporting in
+- *                       this particular case in order to avoid spurious
+- *                       errors in syslog.  The culprit is
+- *                       idefloppy_get_capability_page(), so move it to
+- *                       idefloppy_begin_format() so that it's not used
+- *                       unless absolutely necessary.
+- *                       If drive does not support format progress indication
+- *                       monitor the dsc bit in the status register.
+- *                       Also, O_NDELAY on open will allow the device to be
+- *                       opened without a disk available.  This can be used to
+- *                       open an unformatted disk, or get the device capacity.
+- * Ver 0.91  Dec 11 99   Added IOMEGA Clik! drive support by 
+- *     		   <paul at paulbristow.net>
+- * Ver 0.92  Oct 22 00   Paul Bristow became official maintainer for this 
+- *           		   driver.  Included Powerbook internal zip kludge.
+- * Ver 0.93  Oct 24 00   Fixed bugs for Clik! drive
+- *                        no disk on insert and disk change now works
+- * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
+- * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
+- * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
+- *                       including set_bit patch from Rusty Russell
+- * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
+- * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
+- * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+- *                        fix a lost interrupt problem. It appears the busy
+- *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+- *                        drive before the drive was actually ready.
+- * Ver 0.98a Oct 29 01   Expose delay value so we can play.
+- * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code 
+- *                        to support new PocketZip drives 
++ * For a historical changelog see
++ * Documentation/ide/ChangeLog.ide-floppy.1996-2002
+  */
+ 
+ #define IDEFLOPPY_VERSION "0.99.newide"
+@@ -369,27 +309,6 @@ typedef struct ide_floppy_obj {
  #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
  #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
  
@@ -387723,7 +402955,7 @@
  /*
   *	Error codes which are returned in rq->errors to the higher part
   *	of the driver.
-@@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
+@@ -793,9 +712,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
  {
  	idefloppy_pc_t *pc;
  	struct request *rq;
@@ -387734,7 +402966,7 @@
  	pc = idefloppy_next_pc_storage(drive);
  	rq = idefloppy_next_rq_storage(drive);
  	idefloppy_create_request_sense_cmd(pc);
-@@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
+@@ -809,12 +727,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
  static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
  {
  	idefloppy_floppy_t *floppy = drive->driver_data;
@@ -387750,7 +402982,7 @@
  
  	debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
  		__FUNCTION__);
-@@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+@@ -830,16 +748,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
  	}
  
  	/* Clear the interrupt */
@@ -387770,7 +403002,7 @@
  			/* Error detected */
  			debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
  				drive->name);
-@@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+@@ -870,32 +788,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
  	}
  
  	/* Get the number of bytes to transfer */
@@ -387812,7 +403044,7 @@
  				BUG_ON(HWGROUP(drive)->handler != NULL);
  				ide_set_handler(drive,
  						&idefloppy_pc_intr,
-@@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+@@ -911,23 +829,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
  	if (test_bit(PC_WRITING, &pc->flags)) {
  		if (pc->buffer != NULL)
  			/* Write the current buffer */
@@ -387844,7 +403076,7 @@
  
  	BUG_ON(HWGROUP(drive)->handler != NULL);
  	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
-@@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+@@ -943,15 +859,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
  {
  	ide_startstop_t startstop;
  	idefloppy_floppy_t *floppy = drive->driver_data;
@@ -387863,7 +403095,7 @@
  		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
  				"issuing a packet command\n");
  		return ide_do_reset(drive);
-@@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+@@ -991,15 +907,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
  {
  	idefloppy_floppy_t *floppy = drive->driver_data;
  	ide_startstop_t startstop;
@@ -387882,7 +403114,7 @@
  		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
  				"while issuing a packet command\n");
  		return ide_do_reset(drive);
-@@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
+@@ -1041,21 +957,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
  {
  	idefloppy_floppy_t *floppy = drive->driver_data;
  	ide_hwif_t *hwif = drive->hwif;
@@ -387906,7 +403138,7 @@
  
  	if (floppy->failed_pc == NULL &&
  	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-@@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
+@@ -1093,25 +997,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
  	/* We haven't transferred any data yet */
  	pc->actually_transferred = 0;
  	pc->current_position = pc->buffer;
@@ -387938,7 +403170,7 @@
  		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
  		hwif->dma_start(drive);
  	}
-@@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+@@ -1665,14 +1564,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
  		/* Else assume format_unit has finished, and we're
  		** at 0x10000 */
  	} else {
@@ -387956,6 +403188,70 @@
  	}
  	if (put_user(progress_indication, arg))
  		return (-EFAULT);
+@@ -1699,7 +1598,6 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+ {
+ 	struct idefloppy_id_gcw gcw;
+ #if IDEFLOPPY_DEBUG_INFO
+-	u16 mask,i;
+ 	char buffer[80];
+ #endif /* IDEFLOPPY_DEBUG_INFO */
+ 
+@@ -1746,55 +1644,6 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+ 		default: sprintf(buffer, "Reserved");break;
+ 	}
+ 	printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+-	printk(KERN_INFO "Model: %.40s\n",id->model);
+-	printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+-	printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+-	printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+-	printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+-	printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+-	printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+-	printk(KERN_INFO "Single Word DMA supported modes:\n");
+-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+-		if (id->dma_1word & mask)
+-			printk(KERN_INFO "   Mode %d%s\n", i,
+-			(id->dma_1word & (mask << 8)) ? " (active)" : "");
+-	}
+-	printk(KERN_INFO "Multi Word DMA supported modes:\n");
+-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+-		if (id->dma_mword & mask)
+-			printk(KERN_INFO "   Mode %d%s\n", i,
+-			(id->dma_mword & (mask << 8)) ? " (active)" : "");
+-	}
+-	if (id->field_valid & 0x0002) {
+-		printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+-			id->eide_pio_modes & 1 ? "Mode 3":"None");
+-		if (id->eide_dma_min == 0)
+-			sprintf(buffer, "Not supported");
+-		else
+-			sprintf(buffer, "%d ns",id->eide_dma_min);
+-		printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+-		if (id->eide_dma_time == 0)
+-			sprintf(buffer, "Not supported");
+-		else
+-			sprintf(buffer, "%d ns",id->eide_dma_time);
+-		printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+-		if (id->eide_pio == 0)
+-			sprintf(buffer, "Not supported");
+-		else
+-			sprintf(buffer, "%d ns",id->eide_pio);
+-		printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+-			buffer);
+-		if (id->eide_pio_iordy == 0)
+-			sprintf(buffer, "Not supported");
+-		else
+-			sprintf(buffer, "%d ns",id->eide_pio_iordy);
+-		printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+-	} else
+-		printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+ #endif /* IDEFLOPPY_DEBUG_INFO */
+ 
+ 	if (gcw.protocol != 2)
 diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
 index 0f72b98..bb30c29 100644
 --- a/drivers/ide/ide-generic.c
@@ -387979,7 +403275,7 @@
  	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
  		ide_release_lock();	/* for atari only */
 diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
-index bef781f..e6bb9cf 100644
+index bef781f..4bddef0 100644
 --- a/drivers/ide/ide-io.c
 +++ b/drivers/ide/ide-io.c
 @@ -58,15 +58,19 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
@@ -388527,6 +403823,15 @@
  			/* local CPU only,
  			 * as if we were handling an interrupt */
  			local_irq_disable();
+@@ -1608,7 +1487,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
+ 		 * remove all the ifdef PCI crap
+ 		 */
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+-		if (hwif->pci_dev && !hwif->pci_dev->vendor)
++		if (hwif->chipset != ide_pci)
+ #endif	/* CONFIG_BLK_DEV_IDEPCI */
+ 		{
+ 			/*
 @@ -1710,7 +1589,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
  void ide_init_drive_cmd (struct request *rq)
  {
@@ -388556,10 +403861,17 @@
 +
 +EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
 diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
-index bb9693d..e2a7e95 100644
+index bb9693d..16b1f6e 100644
 --- a/drivers/ide/ide-iops.c
 +++ b/drivers/ide/ide-iops.c
-@@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/ide-iops.c	Version 0.37	Mar 05, 2003
+- *
+  *  Copyright (C) 2000-2002	Andre Hedrick <andre at linux-ide.org>
+  *  Copyright (C) 2003		Red Hat <alan at redhat.com>
+  *
+@@ -158,14 +156,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
  
  EXPORT_SYMBOL(default_hwif_mmiops);
  
@@ -388574,7 +403886,7 @@
  void SELECT_DRIVE (ide_drive_t *drive)
  {
  	if (HWIF(drive)->selectproc)
-@@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
+@@ -175,26 +165,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
  
  EXPORT_SYMBOL(SELECT_DRIVE);
  
@@ -388601,7 +403913,7 @@
  /*
   * Some localbus EIDE interfaces require a special access sequence
   * when using 32-bit I/O instructions to transfer data.  We call this
-@@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive)
+@@ -449,7 +425,6 @@ int drive_is_ready (ide_drive_t *drive)
  	udelay(1);
  #endif
  
@@ -388609,7 +403921,7 @@
  	/*
  	 * We do a passive status test under shared PCI interrupts on
  	 * cards that truly share the ATA side interrupt, but may also share
-@@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive)
+@@ -459,7 +434,6 @@ int drive_is_ready (ide_drive_t *drive)
  	if (IDE_CONTROL_REG)
  		stat = hwif->INB(IDE_ALTSTATUS_REG);
  	else
@@ -388617,7 +403929,7 @@
  		/* Note: this may clear a pending IRQ!! */
  		stat = hwif->INB(IDE_STATUS_REG);
  
-@@ -642,9 +618,9 @@ no_80w:
+@@ -642,9 +616,9 @@ no_80w:
  
  int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
  {
@@ -388630,7 +403942,7 @@
  		if (eighty_ninty_three(drive) == 0) {
  			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
  					    "be set\n", drive->name);
-@@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+@@ -662,9 +636,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
   */
  int set_transfer (ide_drive_t *drive, ide_task_t *args)
  {
@@ -388643,7 +403955,7 @@
  	    (drive->id->dma_ultra ||
  	     drive->id->dma_mword ||
  	     drive->id->dma_1word))
-@@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive)
+@@ -712,8 +686,7 @@ int ide_driveid_update(ide_drive_t *drive)
  	 */
  
  	SELECT_MASK(drive, 1);
@@ -388653,7 +403965,7 @@
  	msleep(50);
  	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
  	timeout = jiffies + WAIT_WORSTCASE;
-@@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+@@ -766,8 +739,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
  //		msleep(50);
  
  #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -388664,7 +403976,7 @@
  #endif
  
  	/* Skip setting PIO flow-control modes on pre-EIDE drives */
-@@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+@@ -796,13 +769,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
  	SELECT_DRIVE(drive);
  	SELECT_MASK(drive, 0);
  	udelay(1);
@@ -388681,7 +403993,7 @@
  
  	error = __ide_wait_stat(drive, drive->ready_stat,
  				BUSY_STAT|DRQ_STAT|ERR_STAT,
-@@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+@@ -823,10 +795,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
  
   skip:
  #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -388697,7 +404009,7 @@
  #endif
  
  	switch(speed) {
-@@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler);
+@@ -902,8 +875,9 @@ EXPORT_SYMBOL(ide_set_handler);
   *	handler and IRQ setup do not race. All IDE command kick off
   *	should go via this function or do equivalent locking.
   */
@@ -388709,7 +404021,7 @@
  {
  	unsigned long flags;
  	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-@@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive)
+@@ -1035,10 +1009,10 @@ static void check_dma_crc(ide_drive_t *drive)
  {
  #ifdef CONFIG_BLK_DEV_IDEDMA
  	if (drive->crc_count) {
@@ -388722,7 +404034,7 @@
  	} else
  		ide_dma_off(drive);
  #endif
-@@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
+@@ -1051,8 +1025,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
  	drive->special.all = 0;
  	drive->special.b.set_geometry = legacy;
  	drive->special.b.recalibrate  = legacy;
@@ -388732,7 +404044,7 @@
  	if (!drive->keep_settings && !drive->using_dma)
  		drive->mult_req = 0;
  	if (drive->mult_req != drive->mult_count)
-@@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+@@ -1137,7 +1110,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
  	for (unit = 0; unit < MAX_DRIVES; ++unit)
  		pre_reset(&hwif->drives[unit]);
  
@@ -388740,7 +404052,7 @@
  	if (!IDE_CONTROL_REG) {
  		spin_unlock_irqrestore(&ide_lock, flags);
  		return ide_stopped;
-@@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+@@ -1174,11 +1146,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
  	 * state when the disks are reset this way. At least, the Winbond
  	 * 553 documentation says that
  	 */
@@ -388753,11 +404065,33 @@
  
  	spin_unlock_irqrestore(&ide_lock, flags);
  	return ide_started;
+@@ -1197,7 +1166,7 @@ EXPORT_SYMBOL(ide_do_reset);
+ 
+ /*
+  * ide_wait_not_busy() waits for the currently selected device on the hwif
+- * to report a non-busy status, see comments in probe_hwif().
++ * to report a non-busy status, see comments in ide_probe_port().
+  */
+ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
+ {
 diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
-index 062d3bc..9b44fbd 100644
+index 062d3bc..b42940d 100644
 --- a/drivers/ide/ide-lib.c
 +++ b/drivers/ide/ide-lib.c
-@@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+@@ -358,8 +358,10 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
+ 	if (!PCI_DMA_BUS_IS_PHYS) {
+ 		addr = BLK_BOUNCE_ANY;
+ 	} else if (on && drive->media == ide_disk) {
+-		if (HWIF(drive)->pci_dev)
+-			addr = HWIF(drive)->pci_dev->dma_mask;
++		struct device *dev = drive->hwif->dev;
++
++		if (dev && dev->dma_mask)
++			addr = *dev->dma_mask;
+ 	}
+ 
+ 	if (drive->queue)
+@@ -441,6 +443,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
  	 * case could happen iff the transfer mode has already been set on
  	 * the device by ide-proc.c::set_xfer_rate()).
  	 */
@@ -388770,7 +404104,7 @@
  
  	return ide_set_dma_mode(drive, rate);
  }
-@@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+@@ -448,8 +456,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
  static void ide_dump_opcode(ide_drive_t *drive)
  {
  	struct request *rq;
@@ -388780,7 +404114,7 @@
  
  	spin_lock(&ide_lock);
  	rq = NULL;
-@@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
+@@ -458,164 +465,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
  	spin_unlock(&ide_lock);
  	if (!rq)
  		return;
@@ -389038,10 +404372,17 @@
  
  EXPORT_SYMBOL(ide_dump_status);
 diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
-index e245521..cbbb0f7 100644
+index e245521..4bda5cf 100644
 --- a/drivers/ide/ide-pnp.c
 +++ b/drivers/ide/ide-pnp.c
-@@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/ide-pnp.c
+- *
+  * This file provides autodetection for ISA PnP IDE interfaces.
+  * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
+  *
+@@ -31,7 +29,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
  {
  	hw_regs_t hw;
  	ide_hwif_t *hwif;
@@ -389049,7 +404390,7 @@
  
  	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
  		return -1;
-@@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
+@@ -41,11 +38,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
  				pnp_port_start(dev, 1));
  	hw.irq = pnp_irq(dev, 0);
  
@@ -389072,7 +404413,7 @@
  		return 0;
  	}
  
-@@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = {
+@@ -68,12 +73,15 @@ static struct pnp_driver idepnp_driver = {
  	.remove		= idepnp_remove,
  };
  
@@ -389092,10 +404433,20 @@
 +module_init(pnpide_init);
 +module_exit(pnpide_exit);
 diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
-index 2994523..edf650b 100644
+index 2994523..98a8af4 100644
 --- a/drivers/ide/ide-probe.c
 +++ b/drivers/ide/ide-probe.c
-@@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
+@@ -1,7 +1,6 @@
+ /*
+- *  linux/drivers/ide/ide-probe.c	Version 1.11	Mar 05, 2003
+- *
+- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
++ *  Copyright (C) 1994-1998   Linus Torvalds & authors (see below)
++ *  Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
+  */
+ 
+ /*
+@@ -95,10 +94,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
  #ifdef CONFIG_IDEDISK_MULTI_MODE
  		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
  		id->multsect_valid = id->multsect ? 1 : 0;
@@ -389108,7 +404459,18 @@
  		if (drive->mult_req > id->max_multsect)
  			drive->mult_req = id->max_multsect;
  		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
-@@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
+@@ -129,6 +128,10 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
+ 
+ 	drive->id_read = 1;
+ 	local_irq_enable();
++#ifdef DEBUG
++	printk(KERN_INFO "%s: dumping identify data\n", drive->name);
++	ide_dump_identify((u8 *)id);
++#endif
+ 	ide_fix_driveid(id);
+ 
+ #if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
+@@ -234,7 +237,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
  
  	drive->media = ide_disk;
  	printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
@@ -389117,7 +404479,7 @@
  	return;
  
  err_misc:
-@@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
+@@ -350,22 +353,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
  	 * the irq handler isn't expecting.
  	 */
  	if (IDE_CONTROL_REG) {
@@ -389143,7 +404505,7 @@
  		/* clear drive IRQ */
  		(void) hwif->INB(IDE_STATUS_REG);
  		udelay(5);
-@@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
+@@ -385,6 +385,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
  	return retval;
  }
  
@@ -389164,7 +404526,7 @@
  
  /**
   *	do_probe		-	probe an IDE device
-@@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+@@ -453,7 +467,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
  		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
  			((drive->autotune == IDE_TUNE_DEFAULT) ||
  			(drive->autotune == IDE_TUNE_AUTO))) {
@@ -389172,7 +404534,7 @@
  			printk("%s: no response (status = 0x%02x), "
  				"resetting drive\n", drive->name,
  				hwif->INB(IDE_STATUS_REG));
-@@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+@@ -461,10 +474,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
  			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
  			msleep(50);
  			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
@@ -389184,7 +404546,7 @@
  			rc = try_to_identify(drive, cmd);
  		}
  		if (rc == 1)
-@@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
+@@ -492,20 +502,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
  static void enable_nest (ide_drive_t *drive)
  {
  	ide_hwif_t *hwif = HWIF(drive);
@@ -389210,7 +404572,62 @@
  
  	msleep(50);
  
-@@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
+@@ -607,7 +613,7 @@ static void hwif_release_dev (struct device *dev)
+ 	complete(&hwif->gendev_rel_comp);
+ }
+ 
+-static void hwif_register (ide_hwif_t *hwif)
++static void ide_register_port(ide_hwif_t *hwif)
+ {
+ 	int ret;
+ 
+@@ -615,8 +621,8 @@ static void hwif_register (ide_hwif_t *hwif)
+ 	strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
+ 	hwif->gendev.driver_data = hwif;
+ 	if (hwif->gendev.parent == NULL) {
+-		if (hwif->pci_dev)
+-			hwif->gendev.parent = &hwif->pci_dev->dev;
++		if (hwif->dev)
++			hwif->gendev.parent = hwif->dev;
+ 		else
+ 			/* Would like to do = &device_legacy */
+ 			hwif->gendev.parent = NULL;
+@@ -628,7 +634,33 @@ static void hwif_register (ide_hwif_t *hwif)
+ 			__FUNCTION__, ret);
+ }
+ 
+-static int wait_hwif_ready(ide_hwif_t *hwif)
++/**
++ *	ide_port_wait_ready	-	wait for port to become ready
++ *	@hwif: IDE port
++ *
++ *	This is needed on some PPCs and a bunch of BIOS-less embedded
++ *	platforms.  Typical cases are:
++ *
++ *	- The firmware hard reset the disk before booting the kernel,
++ *	  the drive is still doing it's poweron-reset sequence, that
++ *	  can take up to 30 seconds.
++ *
++ *	- The firmware does nothing (or no firmware), the device is
++ *	  still in POST state (same as above actually).
++ *
++ *	- Some CD/DVD/Writer combo drives tend to drive the bus during
++ *	  their reset sequence even when they are non-selected slave
++ *	  devices, thus preventing discovery of the main HD.
++ *
++ *	Doing this wait-for-non-busy should not harm any existing
++ *	configuration and fix some issues like the above.
++ *
++ *	BenH.
++ *
++ *	Returns 0 on success, error code (< 0) otherwise.
++ */
++
++static int ide_port_wait_ready(ide_hwif_t *hwif)
+ {
+ 	int unit, rc;
+ 
+@@ -653,8 +685,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
  		/* Ignore disks that we will not probe for later. */
  		if (!drive->noprobe || drive->present) {
  			SELECT_DRIVE(drive);
@@ -389220,7 +404637,7 @@
  			mdelay(2);
  			rc = ide_wait_not_busy(hwif, 35000);
  			if (rc)
-@@ -673,19 +675,18 @@ out:
+@@ -673,19 +704,18 @@ out:
  
  /**
   *	ide_undecoded_slave	-	look for bad CF adapters
@@ -389244,8 +404661,90 @@
  		return;
  
  	/* If the models don't match they are not the same product */
-@@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif)
- 		}
+@@ -708,36 +738,16 @@ void ide_undecoded_slave(ide_hwif_t *hwif)
+ 
+ EXPORT_SYMBOL_GPL(ide_undecoded_slave);
+ 
+-/*
+- * This routine only knows how to look for drive units 0 and 1
+- * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
+- */
+-static void probe_hwif(ide_hwif_t *hwif)
++static int ide_probe_port(ide_hwif_t *hwif)
+ {
+ 	unsigned long flags;
+ 	unsigned int irqd;
+-	int unit;
++	int unit, rc = -ENODEV;
+ 
+-	if (hwif->noprobe)
+-		return;
++	BUG_ON(hwif->present);
+ 
+-	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
+-	    (ide_hwif_request_regions(hwif))) {
+-		u16 msgout = 0;
+-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+-			ide_drive_t *drive = &hwif->drives[unit];
+-			if (drive->present) {
+-				drive->present = 0;
+-				printk(KERN_ERR "%s: ERROR, PORTS ALREADY IN USE\n",
+-					drive->name);
+-				msgout = 1;
+-			}
+-		}
+-		if (!msgout)
+-			printk(KERN_ERR "%s: ports already in use, skipping probe\n",
+-				hwif->name);
+-		return;	
+-	}
++	if (hwif->noprobe)
++		return -EACCES;
+ 
+ 	/*
+ 	 * We must always disable IRQ, as probe_for_drive will assert IRQ, but
+@@ -749,26 +759,7 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 
+ 	local_irq_set(flags);
+ 
+-	/* This is needed on some PPCs and a bunch of BIOS-less embedded
+-	 * platforms. Typical cases are:
+-	 * 
+-	 *  - The firmware hard reset the disk before booting the kernel,
+-	 *    the drive is still doing it's poweron-reset sequence, that
+-	 *    can take up to 30 seconds
+-	 *  - The firmware does nothing (or no firmware), the device is
+-	 *    still in POST state (same as above actually).
+-	 *  - Some CD/DVD/Writer combo drives tend to drive the bus during
+-	 *    their reset sequence even when they are non-selected slave
+-	 *    devices, thus preventing discovery of the main HD
+-	 *    
+-	 *  Doing this wait-for-busy should not harm any existing configuration
+-	 *  (at least things won't be worse than what current code does, that
+-	 *  is blindly go & talk to the drive) and fix some issues like the
+-	 *  above.
+-	 *  
+-	 *  BenH.
+-	 */
+-	if (wait_hwif_ready(hwif) == -EBUSY)
++	if (ide_port_wait_ready(hwif) == -EBUSY)
+ 		printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
+ 
+ 	/*
+@@ -778,28 +769,15 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 		ide_drive_t *drive = &hwif->drives[unit];
+ 		drive->dn = (hwif->channel ? 2 : 0) + unit;
+ 		(void) probe_for_drive(drive);
+-		if (drive->present && !hwif->present) {
+-			hwif->present = 1;
+-			if (hwif->chipset != ide_4drives ||
+-			    !hwif->mate || 
+-			    !hwif->mate->present) {
+-				hwif_register(hwif);
+-			}
+-		}
++		if (drive->present)
++			rc = 0;
  	}
  	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 -		unsigned long timeout = jiffies + WAIT_WORSTCASE;
@@ -389264,12 +404763,23 @@
  	}
  	local_irq_restore(flags);
  	/*
-@@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif)
- 		return;
- 	}
+@@ -809,13 +787,19 @@ static void probe_hwif(ide_hwif_t *hwif)
+ 	if (irqd)
+ 		enable_irq(irqd);
+ 
+-	if (!hwif->present) {
+-		ide_hwif_release_regions(hwif);
+-		return;
+-	}
++	return rc;
++}
  
 -	if (hwif->fixup)
 -		hwif->fixup(hwif);
++static void ide_port_tune_devices(ide_hwif_t *hwif)
++{
++	int unit;
++
 +	for (unit = 0; unit < MAX_DRIVES; unit++) {
 +		ide_drive_t *drive = &hwif->drives[unit];
 +
@@ -389279,7 +404789,7 @@
  
  	for (unit = 0; unit < MAX_DRIVES; ++unit) {
  		ide_drive_t *drive = &hwif->drives[unit];
-@@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif)
+@@ -830,16 +814,8 @@ static void probe_hwif(ide_hwif_t *hwif)
  
  			drive->nice1 = 1;
  
@@ -389297,7 +404807,7 @@
  		}
  	}
  
-@@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif)
+@@ -853,25 +829,6 @@ static void probe_hwif(ide_hwif_t *hwif)
  	}
  }
  
@@ -389323,7 +404833,7 @@
  #if MAX_HWIFS > 1
  /*
   * save_match() is used to simplify logic in init_irq() below.
-@@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive)
+@@ -968,11 +925,6 @@ static int ide_init_queue(ide_drive_t *drive)
   * Much of the code is for correctly detecting/handling irq sharing
   * and irq serialization situations.  This is somewhat complex because
   * it handles static as well as dynamic (PCMCIA) IDE interfaces.
@@ -389335,7 +404845,35 @@
   */
  static int init_irq (ide_hwif_t *hwif)
  {
-@@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif)
+@@ -1031,21 +983,17 @@ static int init_irq (ide_hwif_t *hwif)
+ 		spin_lock_irq(&ide_lock);
+ 		hwif->next = hwgroup->hwif->next;
+ 		hwgroup->hwif->next = hwif;
++		BUG_ON(hwif->next == hwif);
+ 		spin_unlock_irq(&ide_lock);
+ 	} else {
+-		hwgroup = kmalloc_node(sizeof(ide_hwgroup_t),
+-					GFP_KERNEL | __GFP_ZERO,
+-					hwif_to_node(hwif->drives[0].hwif));
+-		if (!hwgroup)
+-	       		goto out_up;
++		hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
++				       hwif_to_node(hwif));
++		if (hwgroup == NULL)
++			goto out_up;
+ 
+ 		hwif->hwgroup = hwgroup;
++		hwgroup->hwif = hwif->next = hwif;
+ 
+-		hwgroup->hwif     = hwif->next = hwif;
+-		hwgroup->rq       = NULL;
+-		hwgroup->handler  = NULL;
+-		hwgroup->drive    = NULL;
+-		hwgroup->busy     = 0;
+ 		init_timer(&hwgroup->timer);
+ 		hwgroup->timer.function = &ide_timer_expiry;
+ 		hwgroup->timer.data = (unsigned long) hwgroup;
+@@ -1055,17 +1003,13 @@ static int init_irq (ide_hwif_t *hwif)
  	 * Allocate the irq, if not already obtained for another hwif
  	 */
  	if (!match || match->irq != hwif->irq) {
@@ -389355,7 +404893,34 @@
  
  		if (hwif->io_ports[IDE_CONTROL_OFFSET])
  			/* clear nIEN */
-@@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
+@@ -1117,25 +1061,7 @@ static int init_irq (ide_hwif_t *hwif)
+ 	mutex_unlock(&ide_cfg_mtx);
+ 	return 0;
+ out_unlink:
+-	spin_lock_irq(&ide_lock);
+-	if (hwif->next == hwif) {
+-		BUG_ON(match);
+-		BUG_ON(hwgroup->hwif != hwif);
+-		kfree(hwgroup);
+-	} else {
+-		ide_hwif_t *g;
+-		g = hwgroup->hwif;
+-		while (g->next != hwif)
+-			g = g->next;
+-		g->next = hwif->next;
+-		if (hwgroup->hwif == hwif) {
+-			/* Impossible. */
+-			printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n");
+-			hwgroup->hwif = g;
+-		}
+-		BUG_ON(hwgroup->hwif == hwif);
+-	}
+-	spin_unlock_irq(&ide_lock);
++	ide_remove_port_from_hwgroup(hwif);
+ out_up:
+ 	mutex_unlock(&ide_cfg_mtx);
+ 	return 1;
+@@ -1173,7 +1099,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
  {
  	struct gendisk *p = data;
  	*part &= (1 << PARTN_BITS) - 1;
@@ -389364,7 +404929,49 @@
  }
  
  static int exact_lock(dev_t dev, void *data)
-@@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif)
+@@ -1284,28 +1210,21 @@ static int hwif_init(ide_hwif_t *hwif)
+ {
+ 	int old_irq;
+ 
+-	/* Return success if no device is connected */
+-	if (!hwif->present)
+-		return 1;
+-
+ 	if (!hwif->irq) {
+ 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
+ 		{
+ 			printk("%s: DISABLED, NO IRQ\n", hwif->name);
+-			return (hwif->present = 0);
++			return 0;
+ 		}
+ 	}
+ #ifdef CONFIG_BLK_DEV_HD
+ 	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+ 		printk("%s: CANNOT SHARE IRQ WITH OLD "
+ 			"HARDDISK DRIVER (hd.c)\n", hwif->name);
+-		return (hwif->present = 0);
++		return 0;
+ 	}
+ #endif /* CONFIG_BLK_DEV_HD */
+ 
+-	/* we set it back to 1 if all is ok below */	
+-	hwif->present = 0;
+-
+ 	if (register_blkdev(hwif->major, hwif->name))
+ 		return 0;
+ 
+@@ -1344,10 +1263,7 @@ static int hwif_init(ide_hwif_t *hwif)
+ 
+ done:
+ 	init_gendisk(hwif);
+-
+ 	ide_acpi_init(hwif);
+-
+-	hwif->present = 1;	/* success */
+ 	return 1;
+ 
+ out:
+@@ -1373,54 +1289,87 @@ static void hwif_register_devices(ide_hwif_t *hwif)
  	}
  }
  
@@ -389399,21 +405006,27 @@
 +		if (idx[i] == 0xff)
 +			continue;
 +
-+		probe_hwif(&ide_hwifs[idx[i]]);
-+	}
++		hwif = &ide_hwifs[idx[i]];
 +
-+	for (i = 0; i < MAX_HWIFS; i++) {
-+		if (idx[i] == 0xff)
++		if ((hwif->chipset != ide_4drives || !hwif->mate ||
++		     !hwif->mate->present) && ide_hwif_request_regions(hwif)) {
++			printk(KERN_ERR "%s: ports already in use, "
++					"skipping probe\n", hwif->name);
 +			continue;
++		}
 +
-+		hwif = &ide_hwifs[idx[i]];
-+
-+		if (hwif_init(hwif) == 0) {
-+			printk(KERN_INFO "%s: failed to initialize IDE "
-+					 "interface\n", hwif->name);
-+			rc = -1;
++		if (ide_probe_port(hwif) < 0) {
++			ide_hwif_release_regions(hwif);
 +			continue;
  		}
++
++		hwif->present = 1;
++
++		if (hwif->chipset != ide_4drives || !hwif->mate ||
++		    !hwif->mate->present)
++			ide_register_port(hwif);
++
++		ide_port_tune_devices(hwif);
  	}
 -	for (index = 0; index < MAX_HWIFS; ++index)
 -		if (probe[index])
@@ -389434,15 +405047,33 @@
 -	for (i = 0; i < 4; i++) {
 -		if (idx[i] != 0xff)
 -			rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
++		if (!hwif->present)
++			continue;
++
++		if (hwif_init(hwif) == 0) {
++			printk(KERN_INFO "%s: failed to initialize IDE "
++					 "interface\n", hwif->name);
++			hwif->present = 0;
++			rc = -1;
++			continue;
++		}
+ 	}
+ 
+-	for (i = 0; i < 4; i++) {
++	for (i = 0; i < MAX_HWIFS; i++) {
++		if (idx[i] == 0xff)
++			continue;
++
++		hwif = &ide_hwifs[idx[i]];
++
 +		if (hwif->present) {
 +			if (hwif->chipset == ide_unknown ||
 +			    hwif->chipset == ide_forced)
 +				hwif->chipset = ide_generic;
 +			hwif_register_devices(hwif);
 +		}
- 	}
- 
--	for (i = 0; i < 4; i++) {
++	}
++
 +	for (i = 0; i < MAX_HWIFS; i++) {
  		if (idx[i] != 0xff)
  			ide_proc_register_port(&ide_hwifs[idx[i]]);
@@ -389451,12 +405082,12 @@
  	return rc;
  }
 +EXPORT_SYMBOL_GPL(ide_device_add_all);
-+
+ 
 +int ide_device_add(u8 idx[4])
 +{
 +	u8 idx_all[MAX_HWIFS];
 +	int i;
- 
++
 +	for (i = 0; i < MAX_HWIFS; i++)
 +		idx_all[i] = (i < 4) ? idx[i] : 0xff;
 +
@@ -389464,10 +405095,17 @@
 +}
  EXPORT_SYMBOL_GPL(ide_device_add);
 diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
-index a4007d3..aa663e7 100644
+index a4007d3..00c249c 100644
 --- a/drivers/ide/ide-proc.c
 +++ b/drivers/ide/ide-proc.c
-@@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/ide-proc.c	Version 1.05	Mar 05, 2003
+- *
+  *  Copyright (C) 1997-1998	Mark Lord
+  *  Copyright (C) 2003		Red Hat <alan at redhat.com>
+  *
+@@ -346,14 +344,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
  
  static int set_xfer_rate (ide_drive_t *drive, int arg)
  {
@@ -389493,10 +405131,10 @@
  		ide_set_xfer_rate(drive, (u8) arg);
 diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
 new file mode 100644
-index 0000000..7ffa332
+index 0000000..93d2e41
 --- /dev/null
 +++ b/drivers/ide/ide-scan-pci.c
-@@ -0,0 +1,121 @@
+@@ -0,0 +1,116 @@
 +/*
 + * support for probing IDE PCI devices in the PCI bus order
 + *
@@ -389580,7 +405218,7 @@
 + *	module ordering not traditionally ordered.
 + */
 +
-+int __init ide_scan_pcibus(void)
++static int __init ide_scan_pcibus(void)
 +{
 +	struct pci_dev *dev = NULL;
 +	struct pci_driver *d;
@@ -389612,17 +405250,22 @@
 +	return 0;
 +}
 +
-+static int __init ide_scan_pci(void)
-+{
-+	return ide_scan_pcibus();
-+}
-+
-+module_init(ide_scan_pci);
++module_init(ide_scan_pcibus);
 diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
-index 7b9181b..d71a584 100644
+index 7b9181b..5aef63a 100644
 --- a/drivers/ide/ide-tape.c
 +++ b/drivers/ide/ide-tape.c
-@@ -615,16 +615,6 @@ typedef struct os_dat_s {
+@@ -1,7 +1,6 @@
+ /*
+- * linux/drivers/ide/ide-tape.c		Version 1.19	Nov, 2003
+- *
+- * Copyright (C) 1995 - 1999 Gadi Oxman <gadio at netvision.net.il>
++ * Copyright (C) 1995-1999  Gadi Oxman <gadio at netvision.net.il>
++ * Copyright (C) 2003-2005  Bartlomiej Zolnierkiewicz
+  *
+  * $Header$
+  *
+@@ -615,16 +614,6 @@ typedef struct os_dat_s {
  /*************************** End of tunable parameters ***********************/
  
  /*
@@ -389639,7 +405282,7 @@
   *	Read/Write error simulation
   */
  #define SIMULATE_ERRORS			0
-@@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
+@@ -1700,6 +1689,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
  	if (error)
  		tape->failed_pc = NULL;
  
@@ -389651,7 +405294,7 @@
  	spin_lock_irqsave(&tape->spinlock, flags);
  
  	/* The request was a pipelined data transfer request */
-@@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
+@@ -1818,9 +1812,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
  	idetape_tape_t *tape = drive->driver_data;
  	idetape_pc_t *pc;
  	struct request *rq;
@@ -389662,7 +405305,7 @@
  	pc = idetape_next_pc_storage(drive);
  	rq = idetape_next_rq_storage(drive);
  	idetape_create_request_sense_cmd(pc);
-@@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1858,15 +1851,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  {
  	ide_hwif_t *hwif = drive->hwif;
  	idetape_tape_t *tape = drive->driver_data;
@@ -389680,7 +405323,7 @@
  
  #if IDETAPE_DEBUG_LOG
  	if (tape->debug_level >= 4)
-@@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1875,10 +1866,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  #endif /* IDETAPE_DEBUG_LOG */	
  
  	/* Clear the interrupt */
@@ -389693,7 +405336,7 @@
  			/*
  			 * A DMA error is sometimes expected. For example,
  			 * if the tape is crossing a filemark during a
-@@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1912,7 +1903,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  	}
  
  	/* No more interrupts */
@@ -389702,7 +405345,7 @@
  #if IDETAPE_DEBUG_LOG
  		if (tape->debug_level >= 2)
  			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-@@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1927,12 +1918,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  		    (++error_sim_count % 100) == 0) {
  			printk(KERN_INFO "ide-tape: %s: simulating error\n",
  				tape->name);
@@ -389720,7 +405363,7 @@
  #if IDETAPE_DEBUG_LOG
  			if (tape->debug_level >= 1)
  				printk(KERN_INFO "ide-tape: %s: I/O error\n",
-@@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1951,7 +1943,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  		}
  		pc->error = 0;
  		if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
@@ -389729,7 +405372,7 @@
  			/* Media access command */
  			tape->dsc_polling_start = jiffies;
  			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
-@@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -1973,30 +1965,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  		return ide_do_reset(drive);
  	}
  	/* Get the number of bytes to transfer on this interrupt. */
@@ -389769,7 +405412,7 @@
  				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
  				return ide_started;
  			}
-@@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+@@ -2008,23 +2000,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
  	}
  	if (test_bit(PC_WRITING, &pc->flags)) {
  		if (pc->bh != NULL)
@@ -389803,7 +405446,7 @@
  #endif
  	/* And set the interrupt handler again */
  	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
-@@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
+@@ -2078,28 +2073,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
  	ide_hwif_t *hwif = drive->hwif;
  	idetape_tape_t *tape = drive->driver_data;
  	idetape_pc_t *pc = tape->pc;
@@ -389839,7 +405482,7 @@
  		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
  				"a packet command\n");
  		return ide_do_reset(drive);
-@@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+@@ -2120,8 +2115,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
  {
  	ide_hwif_t *hwif = drive->hwif;
  	idetape_tape_t *tape = drive->driver_data;
@@ -389849,7 +405492,7 @@
  
  #if IDETAPE_DEBUG_BUGS
  	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
-@@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+@@ -2170,7 +2165,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
  	pc->actually_transferred = 0;
  	pc->current_position = pc->buffer;
  	/* Request to transfer the entire buffer at once */
@@ -389858,7 +405501,7 @@
  
  	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
  		printk(KERN_WARNING "ide-tape: DMA disabled, "
-@@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
+@@ -2180,12 +2175,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
  	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
  		dma_ok = !hwif->dma_setup(drive);
  
@@ -389874,7 +405517,7 @@
  	if (dma_ok)			/* Will begin DMA later */
  		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
  	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-@@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+@@ -2295,11 +2287,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
  {
  	idetape_tape_t *tape = drive->driver_data;
  	idetape_pc_t *pc = tape->pc;
@@ -389890,7 +405533,7 @@
  			/* Error detected */
  			if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
  				printk(KERN_ERR "ide-tape: %s: I/O error, ",
-@@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+@@ -2417,7 +2409,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  	idetape_tape_t *tape = drive->driver_data;
  	idetape_pc_t *pc = NULL;
  	struct request *postponed_rq = tape->postponed_rq;
@@ -389899,7 +405542,7 @@
  
  #if IDETAPE_DEBUG_LOG
  #if 0
-@@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+@@ -2465,7 +2457,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  	 * If the tape is still busy, postpone our request and service
  	 * the other device meanwhile.
  	 */
@@ -389908,7 +405551,7 @@
  
  	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
  		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
-@@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+@@ -2481,7 +2473,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
  	calculate_speeds(drive);
  	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
@@ -389917,7 +405560,7 @@
  		if (postponed_rq == NULL) {
  			tape->dsc_polling_start = jiffies;
  			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
-@@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+@@ -2502,9 +2494,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  	}
  	if (rq->cmd[0] & REQ_IDETAPE_READ) {
  		tape->buffer_head++;
@@ -389927,7 +405570,7 @@
  		tape->postpone_cnt = 0;
  		pc = idetape_next_pc_storage(drive);
  		idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
-@@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+@@ -2512,9 +2501,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
  	}
  	if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
  		tape->buffer_head++;
@@ -389937,7 +405580,7 @@
  		tape->postpone_cnt = 0;
  		pc = idetape_next_pc_storage(drive);
  		idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
-@@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+@@ -3241,9 +3227,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
  	idetape_switch_buffers(tape, new_stage);
  	idetape_add_stage_tail(drive, new_stage);
  	tape->pipeline_head++;
@@ -389947,7 +405590,7 @@
  	calculate_speeds(drive);
  
  	/*
-@@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+@@ -3493,9 +3476,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
  		idetape_remove_stage_head(drive);
  		spin_unlock_irqrestore(&tape->spinlock, flags);
  		tape->pipeline_head++;
@@ -389957,7 +405600,104 @@
  		calculate_speeds(drive);
  	}
  #if IDETAPE_DEBUG_BUGS
-@@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref)
+@@ -4310,9 +4290,6 @@ static int idetape_identify_device (ide_drive_t *drive)
+ {
+ 	struct idetape_id_gcw gcw;
+ 	struct hd_driveid *id = drive->id;
+-#if IDETAPE_DEBUG_INFO
+-	unsigned short mask,i;
+-#endif /* IDETAPE_DEBUG_INFO */
+ 
+ 	if (drive->id_read == 0)
+ 		return 1;
+@@ -4352,62 +4329,6 @@ static int idetape_identify_device (ide_drive_t *drive)
+ 		case 1: printk("16 bytes\n");break;
+ 		default: printk("Reserved\n");break;
+ 	}
+-	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+-	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+-	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+-	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+-	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+-	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+-	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+-	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+-	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+-		if (id->dma_1word & mask)
+-			printk("%d ",i);
+-		if (id->dma_1word & (mask << 8))
+-			printk("(active) ");
+-	}
+-	printk("\n");
+-	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+-	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+-		if (id->dma_mword & mask)
+-			printk("%d ",i);
+-		if (id->dma_mword & (mask << 8))
+-			printk("(active) ");
+-	}
+-	printk("\n");
+-	if (id->field_valid & 0x0002) {
+-		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
+-			id->eide_pio_modes & 1 ? "Mode 3":"None");
+-		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+-		if (id->eide_dma_min == 0)
+-			printk("Not supported\n");
+-		else
+-			printk("%d ns\n",id->eide_dma_min);
+-
+-		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+-		if (id->eide_dma_time == 0)
+-			printk("Not supported\n");
+-		else
+-			printk("%d ns\n",id->eide_dma_time);
+-
+-		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+-		if (id->eide_pio == 0)
+-			printk("Not supported\n");
+-		else
+-			printk("%d ns\n",id->eide_pio);
+-
+-		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+-		if (id->eide_pio_iordy == 0)
+-			printk("Not supported\n");
+-		else
+-			printk("%d ns\n",id->eide_pio_iordy);
+-		
+-	} else
+-		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+ #endif /* IDETAPE_DEBUG_INFO */
+ 
+ 	/* Check that we can support this device */
+@@ -4610,19 +4531,11 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
+ 
+ 	spin_lock_init(&tape->spinlock);
+ 	drive->dsc_overlap = 1;
+-#ifdef CONFIG_BLK_DEV_IDEPCI
+-	if (HWIF(drive)->pci_dev != NULL) {
+-		/*
+-		 * These two ide-pci host adapters appear to need DSC overlap disabled.
+-		 * This probably needs further analysis.
+-		 */
+-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+-			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
+-		    	drive->dsc_overlap = 0;
+-		}
++	if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
++		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
++				 tape->name);
++		drive->dsc_overlap = 0;
+ 	}
+-#endif /* CONFIG_BLK_DEV_IDEPCI */
+ 	/* Seagate Travan drives do not support DSC overlap. */
+ 	if (strstr(drive->id->model, "Seagate STT3401"))
+ 		drive->dsc_overlap = 0;
+@@ -4724,10 +4637,8 @@ static void ide_tape_release(struct kref *kref)
  
  	drive->dsc_overlap = 0;
  	drive->driver_data = NULL;
@@ -389970,7 +405710,7 @@
  	idetape_devs[tape->minor] = NULL;
  	g->private_data = NULL;
  	put_disk(g);
-@@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive)
+@@ -4884,10 +4795,10 @@ static int ide_tape_probe(ide_drive_t *drive)
  
  	idetape_setup(drive, tape, minor);
  
@@ -389986,16 +405726,31 @@
  	g->fops = &idetape_block_ops;
  	ide_register_region(g);
 diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
-index 2b60f1b..5eb6fa1 100644
+index 2b60f1b..16a9a58 100644
 --- a/drivers/ide/ide-taskfile.c
 +++ b/drivers/ide/ide-taskfile.c
-@@ -35,93 +35,81 @@
+@@ -1,11 +1,9 @@
+ /*
+- * linux/drivers/ide/ide-taskfile.c	Version 0.38	March 05, 2003
+- *
+- *  Copyright (C) 2000-2002	Michael Cornwell <cornwell at acm.org>
+- *  Copyright (C) 2000-2002	Andre Hedrick <andre at linux-ide.org>
+- *  Copyright (C) 2001-2002	Klaus Smolin
++ *  Copyright (C) 2000-2002	   Michael Cornwell <cornwell at acm.org>
++ *  Copyright (C) 2000-2002	   Andre Hedrick <andre at linux-ide.org>
++ *  Copyright (C) 2001-2002	   Klaus Smolin
+  *					IBM Storage Technology Division
+- *  Copyright (C) 2003-2004	Bartlomiej Zolnierkiewicz
++ *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
+  *
+  *  The big the bad and the ugly.
+  */
+@@ -35,93 +33,81 @@
  #include <asm/uaccess.h>
  #include <asm/io.h>
  
 -static void ata_bswap_data (void *buffer, int wcount)
-+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
- {
+-{
 -	u16 *p = buffer;
 -
 -	while (wcount--) {
@@ -390005,7 +405760,8 @@
 -}
 -
 -static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
--{
++void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+ {
 -	HWIF(drive)->ata_input_data(drive, buffer, wcount);
 -	if (drive->bswap)
 -		ata_bswap_data(buffer, wcount);
@@ -390133,18 +405889,18 @@
 -		ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
 -		return ide_started;
 -	}
+-
+-	if (!drive->using_dma)
+-		return ide_stopped;
 +	if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED))
 +		return 1;
  
--	if (!drive->using_dma)
--		return ide_stopped;
--
 -	switch (taskfile->command) {
 +	switch (task->tf.command) {
  		case WIN_WRITEDMA_ONCE:
  		case WIN_WRITEDMA:
  		case WIN_WRITEDMA_EXT:
-@@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+@@ -129,24 +115,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
  		case WIN_READDMA:
  		case WIN_READDMA_EXT:
  		case WIN_IDENTIFY_DMA:
@@ -390162,8 +405918,8 @@
  
 -	return ide_stopped;
 +	return 0;
- }
- 
++}
++
 +static ide_startstop_t task_no_data_intr(ide_drive_t *);
 +static ide_startstop_t set_geometry_intr(ide_drive_t *);
 +static ide_startstop_t recal_intr(ide_drive_t *);
@@ -390224,9 +405980,9 @@
 +		hwif->dma_start(drive);
 +		return ide_started;
 +	}
-+}
+ }
 +EXPORT_SYMBOL_GPL(do_rw_taskfile);
-+
+ 
  /*
   * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
   */
@@ -390235,7 +405991,7 @@
  {
  	ide_hwif_t *hwif = HWIF(drive);
  	u8 stat;
-@@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+@@ -164,7 +205,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
  /*
   * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
   */
@@ -390244,7 +406000,7 @@
  {
  	ide_hwif_t *hwif = HWIF(drive);
  	int retries = 5;
-@@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+@@ -187,7 +228,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
  /*
   * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
   */
@@ -390253,7 +406009,7 @@
  {
  	ide_hwif_t *hwif = HWIF(drive);
  	u8 stat;
-@@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
+@@ -200,7 +241,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
  /*
   * Handler for commands without a data phase
   */
@@ -390262,18 +406018,16 @@
  {
  	ide_task_t *args	= HWGROUP(drive)->rq->special;
  	ide_hwif_t *hwif	= HWIF(drive);
-@@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+@@ -217,8 +258,6 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
  	return ide_stopped;
  }
  
 -EXPORT_SYMBOL(task_no_data_intr);
 -
--static u8 wait_drive_not_busy(ide_drive_t *drive)
-+u8 wait_drive_not_busy(ide_drive_t *drive)
+ static u8 wait_drive_not_busy(ide_drive_t *drive)
  {
  	ide_hwif_t *hwif = HWIF(drive);
- 	int retries;
-@@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
+@@ -227,8 +266,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
  
  	/*
  	 * Last sector was transfered, wait until drive is ready.
@@ -390283,7 +406037,7 @@
  	 */
  	for (retries = 0; retries < 100; retries++) {
  		if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
-@@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
+@@ -283,9 +321,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
  
  	/* do the actual data transfer */
  	if (write)
@@ -390295,7 +406049,7 @@
  
  	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
  #ifdef CONFIG_HIGHMEM
-@@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
+@@ -305,9 +343,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
  static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
  				     unsigned int write)
  {
@@ -390314,7 +406068,7 @@
  	touch_softlockup_watchdog();
  
  	switch (drive->hwif->data_phase) {
-@@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+@@ -319,6 +366,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
  		ide_pio_sector(drive, write);
  		break;
  	}
@@ -390323,7 +406077,7 @@
  }
  
  static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
-@@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
+@@ -356,40 +405,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
  	return ide_error(drive, s, stat);
  }
  
@@ -390372,7 +406126,7 @@
  		if (stat & (ERR_STAT | DRQ_STAT))
  			return task_error(drive, rq, __FUNCTION__, stat);
  		/* No data yet, so wait for another IRQ. */
-@@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
+@@ -402,7 +446,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
  	/* If it was the last datablock check status and finish transfer. */
  	if (!hwif->nleft) {
  		stat = wait_drive_not_busy(drive);
@@ -390381,7 +406135,7 @@
  			return task_error(drive, rq, __FUNCTION__, stat);
  		task_end_request(drive, rq, stat);
  		return ide_stopped;
-@@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
+@@ -413,7 +457,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
  
  	return ide_started;
  }
@@ -390389,7 +406143,7 @@
  
  /*
   * Handler for command with PIO data-out phase (Write/Write Multiple).
-@@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
+@@ -443,11 +486,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
  	return ide_started;
  }
  
@@ -390403,7 +406157,7 @@
  			  drive->bad_wstat, WAIT_DRQ)) {
  		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
  				drive->name,
-@@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+@@ -464,9 +507,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
  
  	return ide_started;
  }
@@ -390414,7 +406168,7 @@
  {
  	struct request rq;
  
-@@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
+@@ -481,36 +523,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
  	 * if we would find a solution to transfer any size.
  	 * To support special commands like READ LONG.
  	 */
@@ -390464,7 +406218,7 @@
  
  #ifdef CONFIG_IDE_TASK_IOCTL
  int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
-@@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -519,13 +552,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  	ide_task_t		args;
  	u8 *outbuf		= NULL;
  	u8 *inbuf		= NULL;
@@ -390480,7 +406234,7 @@
  	char __user *buf = (char __user *)arg;
  
  //	printk("IDE Taskfile ...\n");
-@@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -572,24 +604,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  	}
  
  	memset(&args, 0, sizeof(ide_task_t));
@@ -390548,7 +406302,7 @@
  		case TASKFILE_MULTI_OUT:
  			if (!drive->mult_count) {
  				/* (hs): give up if multcount is not set */
-@@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -601,9 +661,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  			}
  			/* fall through */
  		case TASKFILE_OUT:
@@ -390563,7 +406317,7 @@
  			break;
  		case TASKFILE_MULTI_IN:
  			if (!drive->mult_count) {
-@@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -616,22 +678,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  			}
  			/* fall through */
  		case TASKFILE_IN:
@@ -390618,7 +406372,7 @@
  
  	if (copy_to_user(buf, req_task, tasksize)) {
  		err = -EFAULT;
-@@ -658,40 +746,24 @@ abort:
+@@ -658,40 +744,24 @@ abort:
  
  //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
  
@@ -390666,7 +406420,7 @@
  		return ide_do_drive_cmd(drive, &rq, ide_wait);
  	}
  
-@@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -699,27 +769,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  		return -EFAULT;
  
  	memset(&tfargs, 0, sizeof(ide_task_t));
@@ -390718,7 +406472,7 @@
  
  	if (!err && xfer_rate) {
  		/* active-retuning-calls future */
-@@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+@@ -727,142 +810,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
  		ide_driveid_update(drive);
  	}
  abort:
@@ -390879,11 +406633,42 @@
 -	return ide_stopped;
 +	return err;
  }
+diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
+index daffbb9..adeda76 100644
+--- a/drivers/ide/ide-timing.h
++++ b/drivers/ide/ide-timing.h
+@@ -2,8 +2,6 @@
+ #define _IDE_TIMING_H
+ 
+ /*
+- * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
+- *
+  *  Copyright (c) 1999-2001 Vojtech Pavlik
+  */
+ 
 diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
-index 54943da..97894ab 100644
+index 54943da..ab9ca2b 100644
 --- a/drivers/ide/ide.c
 +++ b/drivers/ide/ide.c
-@@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
+@@ -1,7 +1,6 @@
+ /*
+- *  linux/drivers/ide/ide.c		Version 7.00beta2	Mar 05 2003
+- *
+- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
++ *  Copyright (C) 1994-1998	    Linus Torvalds & authors (see below)
++ *  Copyrifht (C) 2003-2005, 2007   Bartlomiej Zolnierkiewicz
+  */
+ 
+ /*
+@@ -46,7 +45,6 @@
+  */
+ 
+ #define	REVISION	"Revision: 7.00alpha2"
+-#define	VERSION		"Id: ide.c 7.00a2 20020906"
+ 
+ #define _IDE_C			/* Tell ide.h it's really us */
+ 
+@@ -95,7 +93,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
   __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
  
  #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
@@ -390892,7 +406677,7 @@
  #endif
  
  int noautodma = 0;
-@@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs);
+@@ -116,7 +114,7 @@ EXPORT_SYMBOL(ide_hwifs);
  /*
   * Do not even *think* about calling this!
   */
@@ -390901,7 +406686,7 @@
  {
  	unsigned int unit;
  
-@@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+@@ -159,6 +157,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
  		init_completion(&drive->gendev_rel_comp);
  	}
  }
@@ -390909,7 +406694,7 @@
  
  static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
  {
-@@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
+@@ -177,8 +176,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
  #endif
  }
  
@@ -390918,7 +406703,7 @@
  /*
   * init_ide_data() sets reasonable default values into all fields
   * of all instances of the hwifs and drives, but only on the first call.
-@@ -210,16 +209,13 @@ static void __init init_ide_data (void)
+@@ -210,16 +207,13 @@ static void __init init_ide_data (void)
  	/* Initialise all interface structures */
  	for (index = 0; index < MAX_HWIFS; ++index) {
  		hwif = &ide_hwifs[index];
@@ -390936,7 +406721,43 @@
  }
  
  /**
-@@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+@@ -246,22 +240,12 @@ static int ide_system_bus_speed(void)
+ #define pci_default 0
+ #endif /* CONFIG_PCI */
+ 
+-	if (!system_bus_speed) {
+-		if (idebus_parameter) {
+-			/* user supplied value */
+-			system_bus_speed = idebus_parameter;
+-		} else if (pci_dev_present(pci_default)) {
+-			/* safe default value for PCI */
+-			system_bus_speed = 33;
+-		} else {
+-			/* safe default value for VESA and PCI */
+-			system_bus_speed = 50;
+-		}
+-		printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+-			"for PIO modes%s\n", system_bus_speed,
+-			idebus_parameter ? "" : "; override with idebus=xx");
+-	}
+-	return system_bus_speed;
++	/* user supplied value */
++	if (idebus_parameter)
++		return idebus_parameter;
++
++	/* safe default value for PCI or VESA and PCI*/
++	return pci_dev_present(pci_default) ? 33 : 50;
+ }
+ 
+ ide_hwif_t * ide_find_port(unsigned long base)
+@@ -409,13 +393,12 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ 	hwif->chipset			= tmp_hwif->chipset;
+ 	hwif->hold			= tmp_hwif->hold;
+ 
++	hwif->dev			= tmp_hwif->dev;
++
+ #ifdef CONFIG_BLK_DEV_IDEPCI
+-	hwif->pci_dev			= tmp_hwif->pci_dev;
  	hwif->cds			= tmp_hwif->cds;
  #endif
  
@@ -390945,7 +406766,7 @@
  	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
  	hwif->set_dma_mode		= tmp_hwif->set_dma_mode;
  	hwif->mdma_filter		= tmp_hwif->mdma_filter;
-@@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+@@ -424,7 +407,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
  	hwif->reset_poll		= tmp_hwif->reset_poll;
  	hwif->pre_reset			= tmp_hwif->pre_reset;
  	hwif->resetproc			= tmp_hwif->resetproc;
@@ -390953,7 +406774,7 @@
  	hwif->maskproc			= tmp_hwif->maskproc;
  	hwif->quirkproc			= tmp_hwif->quirkproc;
  	hwif->busproc			= tmp_hwif->busproc;
-@@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+@@ -434,16 +416,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
  	hwif->atapi_input_bytes		= tmp_hwif->atapi_input_bytes;
  	hwif->atapi_output_bytes	= tmp_hwif->atapi_output_bytes;
  
@@ -390971,7 +406792,7 @@
  	hwif->dma_lost_irq		= tmp_hwif->dma_lost_irq;
  	hwif->dma_timeout		= tmp_hwif->dma_timeout;
  
-@@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+@@ -468,7 +447,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
  #endif
  
  	hwif->dma_base			= tmp_hwif->dma_base;
@@ -390979,7 +406800,94 @@
  	hwif->dma_command		= tmp_hwif->dma_command;
  	hwif->dma_vendor1		= tmp_hwif->dma_vendor1;
  	hwif->dma_status		= tmp_hwif->dma_status;
-@@ -602,7 +591,6 @@ void ide_unregister(unsigned int index)
+@@ -483,6 +461,41 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+ 	hwif->hwif_data			= tmp_hwif->hwif_data;
+ }
+ 
++void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
++{
++	ide_hwgroup_t *hwgroup = hwif->hwgroup;
++
++	spin_lock_irq(&ide_lock);
++	/*
++	 * Remove us from the hwgroup, and free
++	 * the hwgroup if we were the only member
++	 */
++	if (hwif->next == hwif) {
++		BUG_ON(hwgroup->hwif != hwif);
++		kfree(hwgroup);
++	} else {
++		/* There is another interface in hwgroup.
++		 * Unlink us, and set hwgroup->drive and ->hwif to
++		 * something sane.
++		 */
++		ide_hwif_t *g = hwgroup->hwif;
++
++		while (g->next != hwif)
++			g = g->next;
++		g->next = hwif->next;
++		if (hwgroup->hwif == hwif) {
++			/* Chose a random hwif for hwgroup->hwif.
++			 * It's guaranteed that there are no drives
++			 * left in the hwgroup.
++			 */
++			BUG_ON(hwgroup->drive != NULL);
++			hwgroup->hwif = g;
++		}
++		BUG_ON(hwgroup->hwif == hwif);
++	}
++	spin_unlock_irq(&ide_lock);
++}
++
+ /**
+  *	ide_unregister		-	free an IDE interface
+  *	@index: index of interface (will change soon to a pointer)
+@@ -550,43 +563,8 @@ void ide_unregister(unsigned int index)
+ 	if (irq_count == 1)
+ 		free_irq(hwif->irq, hwgroup);
+ 
+-	spin_lock_irq(&ide_lock);
+-	/*
+-	 * Note that we only release the standard ports,
+-	 * and do not even try to handle any extra ports
+-	 * allocated for weird IDE interface chipsets.
+-	 */
+-	ide_hwif_release_regions(hwif);
++	ide_remove_port_from_hwgroup(hwif);
+ 
+-	/*
+-	 * Remove us from the hwgroup, and free
+-	 * the hwgroup if we were the only member
+-	 */
+-	if (hwif->next == hwif) {
+-		BUG_ON(hwgroup->hwif != hwif);
+-		kfree(hwgroup);
+-	} else {
+-		/* There is another interface in hwgroup.
+-		 * Unlink us, and set hwgroup->drive and ->hwif to
+-		 * something sane.
+-		 */
+-		g = hwgroup->hwif;
+-		while (g->next != hwif)
+-			g = g->next;
+-		g->next = hwif->next;
+-		if (hwgroup->hwif == hwif) {
+-			/* Chose a random hwif for hwgroup->hwif.
+-			 * It's guaranteed that there are no drives
+-			 * left in the hwgroup.
+-			 */
+-			BUG_ON(hwgroup->drive != NULL);
+-			hwgroup->hwif = g;
+-		}
+-		BUG_ON(hwgroup->hwif == hwif);
+-	}
+-
+-	/* More messed up locking ... */
+-	spin_unlock_irq(&ide_lock);
+ 	device_unregister(&hwif->gendev);
+ 	wait_for_completion(&hwif->gendev_rel_comp);
+ 
+@@ -602,7 +580,6 @@ void ide_unregister(unsigned int index)
  		(void) ide_release_dma(hwif);
  
  		hwif->dma_base = 0;
@@ -390987,7 +406895,18 @@
  		hwif->dma_command = 0;
  		hwif->dma_vendor1 = 0;
  		hwif->dma_status = 0;
-@@ -617,7 +605,7 @@ void ide_unregister(unsigned int index)
+@@ -613,11 +590,18 @@ void ide_unregister(unsigned int index)
+ 		hwif->extra_ports = 0;
+ 	}
+ 
++	/*
++	 * Note that we only release the standard ports,
++	 * and do not even try to handle any extra ports
++	 * allocated for weird IDE interface chipsets.
++	 */
++	ide_hwif_release_regions(hwif);
++
+ 	/* copy original settings */
  	tmp_hwif = *hwif;
  
  	/* restore hwif data to pristine status */
@@ -390996,7 +406915,7 @@
  	init_hwif_default(hwif, index);
  
  	ide_hwif_restore(hwif, &tmp_hwif);
-@@ -683,24 +671,34 @@ void ide_setup_ports (	hw_regs_t *hw,
+@@ -683,24 +667,34 @@ void ide_setup_ports (	hw_regs_t *hw,
   */
  }
  
@@ -391036,7 +406955,7 @@
  
  	do {
  		for (index = 0; index < MAX_HWIFS; ++index) {
-@@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
+@@ -712,8 +706,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
  			hwif = &ide_hwifs[index];
  			if (hwif->hold)
  				continue;
@@ -391046,7 +406965,7 @@
  				goto found;
  		}
  		for (index = 0; index < MAX_HWIFS; index++)
-@@ -724,29 +721,23 @@ found:
+@@ -724,29 +717,23 @@ found:
  	if (hwif->present)
  		ide_unregister(index);
  	else if (!hwif->hold) {
@@ -391083,7 +407002,7 @@
  }
  
  EXPORT_SYMBOL(ide_register_hw);
-@@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
+@@ -839,7 +826,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
  	if (!drive->id || !(drive->id->capability & 1))
  		goto out;
  
@@ -391092,7 +407011,7 @@
  		goto out;
  
  	err = -EBUSY;
-@@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
+@@ -854,8 +841,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
  	err = 0;
  
  	if (arg) {
@@ -391102,7 +407021,7 @@
  			err = -EIO;
  	} else
  		ide_dma_off(drive);
-@@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
+@@ -888,7 +874,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
  
  	if (drive->special.b.set_tune)
  		return -EBUSY;
@@ -391113,7 +407032,16 @@
  	drive->tune_req = (u8) arg;
  	drive->special.b.set_tune = 1;
  	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
-@@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
+@@ -920,7 +909,7 @@ static int set_unmaskirq(ide_drive_t *drive, int arg)
+ 
+ int system_bus_clock (void)
+ {
+-	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
++	return system_bus_speed;
+ }
+ 
+ EXPORT_SYMBOL(system_bus_clock);
+@@ -1070,7 +1059,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
  			ide_init_hwif_ports(&hw, (unsigned long) args[0],
  					    (unsigned long) args[1], NULL);
  			hw.irq = args[2];
@@ -391122,7 +407050,7 @@
  				return -EIO;
  			return 0;
  		}
-@@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
+@@ -1231,26 +1220,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
  	return 0;	/* zero = nothing matched */
  }
  
@@ -391150,7 +407078,7 @@
  
  static int __initdata is_chipset_set[MAX_HWIFS];
  
-@@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s)
+@@ -1327,7 +1302,7 @@ static int __init ide_setup(char *s)
  	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
  		const char *hd_words[] = {
  			"none", "noprobe", "nowerr", "cdrom", "nodma",
@@ -391159,7 +407087,7 @@
  			"noflush", "remap", "remap63", "scsi", NULL };
  		unit = s[2] - 'a';
  		hw   = unit / MAX_DRIVES;
-@@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s)
+@@ -1363,10 +1338,6 @@ static int __init ide_setup(char *s)
  			case -7: /* "noautotune" */
  				drive->autotune = IDE_TUNE_NOAUTO;
  				goto obsolete_option;
@@ -391170,7 +407098,7 @@
  			case -11: /* noflush */
  				drive->noflush = 1;
  				goto done;
-@@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s)
+@@ -1466,11 +1437,8 @@ static int __init ide_setup(char *s)
  #endif
  #ifdef CONFIG_BLK_DEV_CMD640
  			case -14: /* "cmd640_vlb" */
@@ -391182,7 +407110,7 @@
  #endif
  #ifdef CONFIG_BLK_DEV_HT6560B
  			case -13: /* "ht6560b" */
-@@ -1560,79 +1532,6 @@ done:
+@@ -1560,79 +1528,6 @@ done:
  	return 1;
  }
  
@@ -391262,6 +407190,17 @@
  EXPORT_SYMBOL(ide_lock);
  
  static int ide_bus_match(struct device *dev, struct device_driver *drv)
+@@ -1769,6 +1664,10 @@ static int __init ide_init(void)
+ 	printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+ 	system_bus_speed = ide_system_bus_speed();
+ 
++	printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
++			 "for PIO modes%s\n", system_bus_speed,
++			idebus_parameter ? "" : "; override with idebus=xx");
++
+ 	ret = bus_register(&ide_bus_type);
+ 	if (ret < 0) {
+ 		printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
 @@ -1779,30 +1678,6 @@ static int __init ide_init(void)
  
  	proc_ide_create();
@@ -391339,10 +407278,17 @@
  
  EXTRA_CFLAGS	:= -Idrivers/ide
 diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
-index 38c3a6d..5ec0be4 100644
+index 38c3a6d..e3ea209 100644
 --- a/drivers/ide/legacy/ali14xx.c
 +++ b/drivers/ide/legacy/ali14xx.c
-@@ -231,8 +231,7 @@ int probe_ali14xx = 0;
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/legacy/ali14xx.c		Version 0.03	Feb 09, 1996
+- *
+  *  Copyright (C) 1996  Linus Torvalds & author (see below)
+  */
+ 
+@@ -231,8 +229,7 @@ int probe_ali14xx = 0;
  module_param_named(probe, probe_ali14xx, bool, 0);
  MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
  
@@ -391352,7 +407298,7 @@
  {
  	if (probe_ali14xx == 0)
  		goto out;
-@@ -248,9 +247,7 @@ out:
+@@ -248,9 +245,7 @@ out:
  	return -ENODEV;
  }
  
@@ -391363,9 +407309,16 @@
  MODULE_AUTHOR("see local file");
  MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
 diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
-index 4a0be25..74d28e0 100644
+index 4a0be25..dd3d198 100644
 --- a/drivers/ide/legacy/buddha.c
 +++ b/drivers/ide/legacy/buddha.c
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
++ *  Amiga Buddha, Catweasel and X-Surf IDE Driver
+  *
+  *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+  *
 @@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum {
      BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
  } BuddhaType;
@@ -391450,10 +407403,17 @@
 +
 +module_init(buddha_init);
 diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
-index 24a845d..13eee6d 100644
+index 24a845d..611c970 100644
 --- a/drivers/ide/legacy/dtc2278.c
 +++ b/drivers/ide/legacy/dtc2278.c
-@@ -150,8 +150,7 @@ int probe_dtc2278 = 0;
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/legacy/dtc2278.c		Version 0.02	Feb 10, 1996
+- *
+  *  Copyright (C) 1996  Linus Torvalds & author (see below)
+  */
+ 
+@@ -150,8 +148,7 @@ int probe_dtc2278 = 0;
  module_param_named(probe, probe_dtc2278, bool, 0);
  MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
  
@@ -391463,7 +407423,7 @@
  {
  	if (probe_dtc2278 == 0)
  		return -ENODEV;
-@@ -163,9 +162,7 @@ int __init dtc2278_init(void)
+@@ -163,9 +160,7 @@ int __init dtc2278_init(void)
  	return 0;
  }
  
@@ -391474,10 +407434,17 @@
  MODULE_AUTHOR("See Local File");
  MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
 diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
-index 7d7936f..2860956 100644
+index 7d7936f..c9bd6bf 100644
 --- a/drivers/ide/legacy/falconide.c
 +++ b/drivers/ide/legacy/falconide.c
-@@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock);
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver
++ *  Atari Falcon IDE Driver
+  *
+  *     Created 12 Jul 1997 by Geert Uytterhoeven
+  *
+@@ -62,19 +62,32 @@ EXPORT_SYMBOL(falconide_intr_lock);
       *  Probe for a Falcon IDE interface
       */
  
@@ -391487,6 +407454,7 @@
      if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
  	hw_regs_t hw;
 -	int index;
++	ide_hwif_t *hwif;
 +
 +	printk(KERN_INFO "ide: Falcon IDE controller\n");
  
@@ -391515,9 +407483,16 @@
 +
 +module_init(falconide_init);
 diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
-index 53331ee..492fa04 100644
+index 53331ee..f67c51a 100644
 --- a/drivers/ide/legacy/gayle.c
 +++ b/drivers/ide/legacy/gayle.c
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver
++ *  Amiga Gayle IDE Driver
+  *
+  *     Created 9 Jul 1997 by Geert Uytterhoeven
+  *
 @@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
       *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
       */
@@ -391596,10 +407571,17 @@
 +
 +module_init(gayle_init);
 diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
-index a4245d1..8da5031 100644
+index a4245d1..57bc15c 100644
 --- a/drivers/ide/legacy/ht6560b.c
 +++ b/drivers/ide/legacy/ht6560b.c
-@@ -307,8 +307,7 @@ int probe_ht6560b = 0;
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/legacy/ht6560b.c		Version 0.07	Feb  1, 2000
+- *
+  *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+  */
+ 
+@@ -307,8 +305,7 @@ int probe_ht6560b = 0;
  module_param_named(probe, probe_ht6560b, bool, 0);
  MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
  
@@ -391609,7 +407591,7 @@
  {
  	ide_hwif_t *hwif, *mate;
  	static u8 idx[4] = { 0, 1, 0xff, 0xff };
-@@ -369,9 +368,7 @@ release_region:
+@@ -369,9 +366,7 @@ release_region:
  	return -ENODEV;
  }
  
@@ -391620,10 +407602,19 @@
  MODULE_AUTHOR("See Local File");
  MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
 diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
-index 03715c0..f4ea15b 100644
+index 03715c0..3bd2967 100644
 --- a/drivers/ide/legacy/ide-cs.c
 +++ b/drivers/ide/legacy/ide-cs.c
-@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
+@@ -2,8 +2,6 @@
+ 
+     A driver for PCMCIA IDE/ATA disk cards
+ 
+-    ide-cs.c 1.3 2002/10/26 05:45:31
+-
+     The contents of this file are subject to the Mozilla Public
+     License Version 1.1 (the "License"); you may not use this file
+     except in compliance with the License. You may obtain a copy of
+@@ -153,7 +151,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
      hw.irq = irq;
      hw.chipset = ide_pci;
      hw.dev = &handle->dev;
@@ -391633,13 +407624,20 @@
  
  /*======================================================================
 diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
-index 7bb79f5..69a0fb0 100644
+index 7bb79f5..7c3231a 100644
 --- a/drivers/ide/legacy/ide_platform.c
 +++ b/drivers/ide/legacy/ide_platform.c
-@@ -28,39 +28,27 @@ static struct {
- 	int index;
- } hwif_prop;
+@@ -21,56 +21,39 @@
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
  
+-static struct {
+-	void __iomem *plat_ide_mapbase;
+-	void __iomem *plat_ide_alt_mapbase;
+-	ide_hwif_t *hwif;
+-	int index;
+-} hwif_prop;
+-
 -static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
 -	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
 -	    int mmio)
@@ -391686,7 +407684,11 @@
  }
  
  static int __devinit plat_ide_probe(struct platform_device *pdev)
-@@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
+ {
+ 	struct resource *res_base, *res_alt, *res_irq;
++	void __iomem *base, *alt_base;
+ 	ide_hwif_t *hwif;
+ 	struct pata_platform_info *pdata;
  	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
  	int ret = 0;
  	int mmio = 0;
@@ -391694,14 +407696,29 @@
  
  	pdata = pdev->dev.platform_data;
  
-@@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
+@@ -95,26 +78,33 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	if (mmio) {
+-		hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev,
++		base = devm_ioremap(&pdev->dev,
+ 			res_base->start, res_base->end - res_base->start + 1);
+-		hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev,
++		alt_base = devm_ioremap(&pdev->dev,
+ 			res_alt->start, res_alt->end - res_alt->start + 1);
+ 	} else {
+-		hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev,
++		base = devm_ioport_map(&pdev->dev,
+ 			res_base->start, res_base->end - res_base->start + 1);
+-		hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev,
++		alt_base = devm_ioport_map(&pdev->dev,
  			res_alt->start, res_alt->end - res_alt->start + 1);
  	}
  
 -	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
 -	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
 -
-+	hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
++	hwif = ide_find_port((unsigned long)base);
  	if (!hwif) {
  		ret = -ENODEV;
  		goto out;
@@ -391710,9 +407727,7 @@
 -	hwif->noprobe = 0;
 +
 +	memset(&hw, 0, sizeof(hw));
-+	plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
-+			     hwif_prop.plat_ide_alt_mapbase,
-+			     pdata, res_irq->start);
++	plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
 +	hw.dev = &pdev->dev;
 +
 +	ide_init_port_hw(hwif, &hw);
@@ -391721,16 +407736,36 @@
 +		hwif->mmio = 1;
 +		default_hwif_mmiops(hwif);
 +	}
-+
-+	hwif_prop.hwif = hwif;
-+	hwif_prop.index = hwif->index;
  
  	idx[0] = hwif->index;
  
+@@ -132,14 +122,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev)
+ {
+ 	ide_hwif_t *hwif = pdev->dev.driver_data;
+ 
+-	if (hwif != hwif_prop.hwif) {
+-		dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error",
+-		           pdev->name);
+-	} else {
+-		ide_unregister(hwif_prop.index);
+-		hwif_prop.index = 0;
+-		hwif_prop.hwif = NULL;
+-	}
++	ide_unregister(hwif->index);
+ 
+ 	return 0;
+ }
 diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
-index 5c6aa77..782d4c7 100644
+index 5c6aa77..c54d07f 100644
 --- a/drivers/ide/legacy/macide.c
 +++ b/drivers/ide/legacy/macide.c
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver
++ *  Macintosh IDE Driver
+  *
+  *     Copyright (C) 1998 by Michael Schmitz
+  *
 @@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif)
  	return 0;
  }
@@ -391825,9 +407860,16 @@
 +
 +module_init(macide_init);
 diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
-index 6ea46a6..f532973 100644
+index 6ea46a6..a9c6b06 100644
 --- a/drivers/ide/legacy/q40ide.c
 +++ b/drivers/ide/legacy/q40ide.c
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver
++ *  Q40 I/O port IDE Driver
+  *
+  *     (c) Richard Zidlicky
+  *
 @@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
   *  Probe for Q40 IDE interfaces
   */
@@ -391874,10 +407916,17 @@
  
 +module_init(q40ide_init);
 diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
-index 912e738..2bac4c1 100644
+index 912e738..37534bb 100644
 --- a/drivers/ide/legacy/qd65xx.c
 +++ b/drivers/ide/legacy/qd65xx.c
-@@ -478,8 +478,7 @@ int probe_qd65xx = 0;
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/legacy/qd65xx.c		Version 0.07	Sep 30, 2001
+- *
+  *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+  */
+ 
+@@ -478,8 +476,7 @@ int probe_qd65xx = 0;
  module_param_named(probe, probe_qd65xx, bool, 0);
  MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
  
@@ -391887,7 +407936,7 @@
  {
  	if (probe_qd65xx == 0)
  		return -ENODEV;
-@@ -492,9 +491,7 @@ int __init qd65xx_init(void)
+@@ -492,9 +489,7 @@ int __init qd65xx_init(void)
  	return 0;
  }
  
@@ -391897,11 +407946,29 @@
  
  MODULE_AUTHOR("Samuel Thibault");
  MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h
+index 633a424..28dd50a 100644
+--- a/drivers/ide/legacy/qd65xx.h
++++ b/drivers/ide/legacy/qd65xx.h
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/legacy/qd65xx.h
+- *
+  * Copyright (c) 2000	Linus Torvalds & authors
+  */
+ 
 diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
-index 79577b9..a1ae1ae 100644
+index 79577b9..26f38ce 100644
 --- a/drivers/ide/legacy/umc8672.c
 +++ b/drivers/ide/legacy/umc8672.c
-@@ -169,8 +169,7 @@ int probe_umc8672 = 0;
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/legacy/umc8672.c		Version 0.05	Jul 31, 1996
+- *
+  *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+  */
+ 
+@@ -169,8 +167,7 @@ int probe_umc8672 = 0;
  module_param_named(probe, probe_umc8672, bool, 0);
  MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
  
@@ -391911,7 +407978,7 @@
  {
  	if (probe_umc8672 == 0)
  		goto out;
-@@ -181,9 +180,7 @@ out:
+@@ -181,9 +178,7 @@ out:
  	return -ENODEV;;
  }
  
@@ -391922,10 +407989,25 @@
  MODULE_AUTHOR("Wolfram Podien");
  MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
 diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
-index a4ce3ba..2d3e511 100644
+index a4ce3ba..cd42b30 100644
 --- a/drivers/ide/mips/au1xxx-ide.c
 +++ b/drivers/ide/mips/au1xxx-ide.c
-@@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/mips/au1xxx-ide.c  version 01.30.00        Aug. 02 2005
+- *
+  * BRIEF MODULE DESCRIPTION
+  * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
+  *
+@@ -50,7 +48,6 @@
+ #include <asm/mach-au1x00/au1xxx_ide.h>
+ 
+ #define DRV_NAME	"au1200-ide"
+-#define DRV_VERSION	"1.0"
+ #define DRV_AUTHOR	"Enrico Walther <enrico.walther at amd.com> / Pete Popov <ppopov at embeddedalley.com>"
+ 
+ /* enable the burstmode in the dbdma */
+@@ -198,8 +195,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
  
  		break;
  #endif
@@ -391934,14 +408016,75 @@
  	}
  
  	au_writel(mem_sttime,MEM_STTIME2);
-@@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
- 	return 0;
- }
+@@ -211,24 +206,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+  */
  
--static void auide_dma_host_on(ide_drive_t *drive)
+ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+-
+-static int auide_build_sglist(ide_drive_t *drive,  struct request *rq)
 -{
+-	ide_hwif_t *hwif = drive->hwif;
+-	_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
+-	struct scatterlist *sg = hwif->sg_table;
+-
+-	ide_map_sg(drive, rq);
+-
+-	if (rq_data_dir(rq) == READ)
+-		hwif->sg_dma_direction = DMA_FROM_DEVICE;
+-	else
+-		hwif->sg_dma_direction = DMA_TO_DEVICE;
+-
+-	return dma_map_sg(ahwif->dev, sg, hwif->sg_nents,
+-			  hwif->sg_dma_direction);
 -}
 -
+ static int auide_build_dmatable(ide_drive_t *drive)
+ {
+ 	int i, iswrite, count = 0;
+@@ -243,8 +220,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
+ 	/* Save for interrupt context */
+ 	ahwif->drive = drive;
+ 
+-	/* Build sglist */
+-	hwif->sg_nents = i = auide_build_sglist(drive, rq);
++	hwif->sg_nents = i = ide_build_sglist(drive, rq);
+ 
+ 	if (!i)
+ 		return 0;
+@@ -302,10 +278,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
+ 		return 1;
+ 
+  use_pio_instead:
+-	dma_unmap_sg(ahwif->dev,
+-		     hwif->sg_table,
+-		     hwif->sg_nents,
+-		     hwif->sg_dma_direction);
++	ide_destroy_dmatable(drive);
+ 
+ 	return 0; /* revert to PIO for this request */
+ }
+@@ -313,11 +286,9 @@ static int auide_build_dmatable(ide_drive_t *drive)
+ static int auide_dma_end(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
+ 
+ 	if (hwif->sg_nents) {
+-		dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents,
+-			     hwif->sg_dma_direction);
++		ide_destroy_dmatable(drive);
+ 		hwif->sg_nents = 0;
+ 	}
+ 
+@@ -397,26 +368,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
+ 	return 0;
+ }
+ 
+-static void auide_dma_host_on(ide_drive_t *drive)
++static void auide_dma_host_set(ide_drive_t *drive, int on)
+ {
+ }
+ 
 -static int auide_dma_on(ide_drive_t *drive)
 -{
 -	drive->using_dma = 1;
@@ -391950,10 +408093,9 @@
 -}
 -
 -static void auide_dma_host_off(ide_drive_t *drive)
-+static void auide_dma_host_set(ide_drive_t *drive, int on)
- {
- }
- 
+-{
+-}
+-
 -static void auide_dma_off_quietly(ide_drive_t *drive)
 -{
 -	drive->using_dma = 0;
@@ -391962,7 +408104,26 @@
  static void auide_dma_lost_irq(ide_drive_t *drive)
  {
  	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
-@@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev)
+@@ -522,7 +477,7 @@ static int auide_ddma_init(_auide_hwif *auide) {
+ 	auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
+ 							     NUM_DESCRIPTORS);
+  
+-	hwif->dmatable_cpu = dma_alloc_coherent(auide->dev,
++	hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev,
+ 						PRD_ENTRIES * PRD_BYTES,        /* 1 Page */
+ 						&hwif->dmatable_dma, GFP_KERNEL);
+ 	
+@@ -610,9 +565,6 @@ static int au_ide_probe(struct device *dev)
+ #endif
+ 
+ 	memset(&auide_hwif, 0, sizeof(_auide_hwif));
+-	auide_hwif.dev                  = 0;
+-
+-	ahwif->dev = dev;
+ 	ahwif->irq = platform_get_irq(pdev, 0);
+ 
+ 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -643,12 +595,16 @@ static int au_ide_probe(struct device *dev)
  	/* FIXME:  This might possibly break PCMCIA IDE devices */
  
  	hwif                            = &ide_hwifs[pdev->id];
@@ -391973,13 +408134,16 @@
  	auide_setup_ports(&hw, ahwif);
 -	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
 +	hw.irq = ahwif->irq;
++	hw.dev = dev;
 +	hw.chipset = ide_au1xxx;
 +
 +	ide_init_port_hw(hwif, &hw);
++
++	hwif->dev = dev;
  
  	hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
  #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-@@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev)
+@@ -662,7 +618,6 @@ static int au_ide_probe(struct device *dev)
  	hwif->pio_mask = ATA_PIO4;
  	hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
  
@@ -391987,7 +408151,7 @@
  	hwif->drives[0].unmask          = 1;
  	hwif->drives[1].unmask          = 1;
  
-@@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev)
+@@ -684,29 +639,25 @@ static int au_ide_probe(struct device *dev)
  	hwif->set_dma_mode		= &auide_set_dma_mode;
  
  #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -392020,6 +408184,15 @@
  	hwif->drives[0].no_io_32bit	= 1;
  	hwif->drives[1].no_io_32bit	= 1;
  
+@@ -737,7 +688,7 @@ static int au_ide_remove(struct device *dev)
+ 	ide_hwif_t *hwif = dev_get_drvdata(dev);
+ 	_auide_hwif *ahwif = &auide_hwif;
+ 
+-	ide_unregister(hwif - ide_hwifs);
++	ide_unregister(hwif->index);
+ 
+ 	iounmap((void *)ahwif->regbase);
+ 
 diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
 index 521edd4..8b3959d 100644
 --- a/drivers/ide/mips/swarm.c
@@ -392046,18 +408219,62 @@
 +
  EXTRA_CFLAGS	:= -Idrivers/ide
 diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
-index 4426850..7f4d185 100644
+index 4426850..824df78 100644
 --- a/drivers/ide/pci/aec62xx.c
 +++ b/drivers/ide/pci/aec62xx.c
-@@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/aec62xx.c		Version 0.27	Sep 16, 2007
+- *
+  * Copyright (C) 1999-2002	Andre Hedrick <andre at linux-ide.org>
+  * Copyright (C) 2007		MontaVista Software, Inc. <source at mvista.com>
+  *
+@@ -90,7 +88,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
+ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u16 d_conf		= 0;
+ 	u8 ultra = 0, ultra_conf = 0;
+ 	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+@@ -116,7 +114,7 @@ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
+ static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 unit		= (drive->select.b.unit & 0x01);
+ 	u8 tmp1 = 0, tmp2 = 0;
+ 	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+@@ -170,7 +168,7 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
+ 
+ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 
+ 	hwif->set_pio_mode = &aec_set_pio_mode;
+ 
+@@ -188,7 +186,7 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
+ 	if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
+ 		u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
+ 
+-		pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
++		pci_read_config_byte(dev, 0x49, &ata66);
+ 
+ 		hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+ 	}
+@@ -202,6 +200,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
  		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
  		.host_flags	= IDE_HFLAG_SERIALIZE |
  				  IDE_HFLAG_NO_ATAPI_DMA |
++				  IDE_HFLAG_NO_DSC |
 +				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
  				  IDE_HFLAG_OFF_BOARD,
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
-@@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+@@ -211,6 +211,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
  		.init_chipset	= init_chipset_aec62xx,
  		.init_hwif	= init_hwif_aec62xx,
  		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
@@ -392065,7 +408282,7 @@
  				  IDE_HFLAG_OFF_BOARD,
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
-@@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+@@ -220,7 +221,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
  		.init_chipset	= init_chipset_aec62xx,
  		.init_hwif	= init_hwif_aec62xx,
  		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
@@ -392075,7 +408292,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA4,
-@@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+@@ -228,7 +230,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
  		.name		= "AEC6280",
  		.init_chipset	= init_chipset_aec62xx,
  		.init_hwif	= init_hwif_aec62xx,
@@ -392086,7 +408303,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
-@@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+@@ -237,7 +241,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
  		.init_chipset	= init_chipset_aec62xx,
  		.init_hwif	= init_hwif_aec62xx,
  		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
@@ -392098,10 +408315,33 @@
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
 diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
-index ce29393..49aa82e 100644
+index ce29393..130cc6e 100644
 --- a/drivers/ide/pci/alim15x3.c
 +++ b/drivers/ide/pci/alim15x3.c
-@@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/alim15x3.c		Version 0.29	Sep 16 2007
+- *
+  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+  *  Copyright (C) 1999-2000 CJ, cjtsai at ali.com.tw, Maintainer
+@@ -293,7 +291,7 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+ static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	int s_time, a_time, c_time;
+ 	u8 s_clc, a_clc, r_clc;
+ 	unsigned long flags;
+@@ -396,15 +394,12 @@ static u8 ali_udma_filter(ide_drive_t *drive)
+ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 speed1		= speed;
+ 	u8 unit			= (drive->select.b.unit & 0x01);
  	u8 tmpbyte		= 0x00;
  	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
  
@@ -392111,11 +408351,371 @@
  	if (speed == XFER_UDMA_6)
  		speed1 = 0x47;
  
+@@ -628,7 +623,7 @@ static int ali_cable_override(struct pci_dev *pdev)
+ 
+ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned long flags;
+ 	u8 cbl = ATA_CBL_PATA40, tmpbyte;
+ 
+@@ -691,12 +686,13 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+ 
+ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u8 ideic, inmir;
+ 	s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+ 				      1, 11, 0, 12, 0, 14, 0, 15 };
+ 	int irq = -1;
+ 
+-	if (hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229)
++	if (dev->device == PCI_DEVICE_ID_AL_M5229)
+ 		hwif->irq = hwif->channel ? 15 : 14;
+ 
+ 	if (isa_dev) {
+@@ -748,7 +744,7 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+ 		return;
+ 	if (!hwif->channel)
+ 		outb(inb(dmabase + 2) & 0x60, dmabase + 2);
+-	ide_setup_dma(hwif, dmabase, 8);
++	ide_setup_dma(hwif, dmabase);
+ }
+ 
+ static const struct ide_port_info ali15x3_chipset __devinitdata = {
+@@ -778,7 +774,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
+ 	};
+ 
+ 	struct ide_port_info d = ali15x3_chipset;
+-	u8 rev = dev->revision;
++	u8 rev = dev->revision, idx = id->driver_data;
+ 
+ 	if (pci_dev_present(ati_rs100))
+ 		printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+@@ -801,6 +797,9 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
+ 			d.udma_mask = ATA_UDMA6;
+ 	}
+ 
++	if (idx == 0)
++		d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
++
+ #if defined(CONFIG_SPARC64)
+ 	d.init_hwif = init_hwif_common_ali15x3;
+ #endif /* CONFIG_SPARC64 */
+@@ -810,7 +809,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
+ 
+ static const struct pci_device_id alim15x3_pci_tbl[] = {
+ 	{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
+-	{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 0 },
++	{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 },
+ 	{ 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
 diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
-index 8d4125e..cee51fd 100644
+index 8d4125e..8c52bc9 100644
 --- a/drivers/ide/pci/amd74xx.c
 +++ b/drivers/ide/pci/amd74xx.c
-@@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+@@ -1,6 +1,4 @@
+ /*
+- * Version 2.24
+- *
+  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
+  * IDE driver for Linux.
+  *
+@@ -28,81 +26,46 @@
+ 
+ #include "ide-timing.h"
+ 
+-#define AMD_IDE_CONFIG		(0x01 + amd_config->base)
+-#define AMD_CABLE_DETECT	(0x02 + amd_config->base)
+-#define AMD_DRIVE_TIMING	(0x08 + amd_config->base)
+-#define AMD_8BIT_TIMING		(0x0e + amd_config->base)
+-#define AMD_ADDRESS_SETUP	(0x0c + amd_config->base)
+-#define AMD_UDMA_TIMING		(0x10 + amd_config->base)
+-
+-#define AMD_CHECK_SWDMA		0x08
+-#define AMD_BAD_SWDMA		0x10
+-#define AMD_BAD_FIFO		0x20
+-#define AMD_CHECK_SERENADE	0x40
+-
+-/*
+- * AMD SouthBridge chips.
+- */
+-
+-static struct amd_ide_chip {
+-	unsigned short id;
+-	u8 base;
+-	u8 udma_mask;
+-	u8 flags;
+-} amd_ide_chips[] = {
+-	{ PCI_DEVICE_ID_AMD_COBRA_7401,		 0x40, ATA_UDMA2, AMD_BAD_SWDMA },
+-	{ PCI_DEVICE_ID_AMD_VIPER_7409,		 0x40, ATA_UDMA4, AMD_CHECK_SWDMA },
+-	{ PCI_DEVICE_ID_AMD_VIPER_7411,		 0x40, ATA_UDMA5, AMD_BAD_FIFO },
+-	{ PCI_DEVICE_ID_AMD_OPUS_7441,		 0x40, ATA_UDMA5, },
+-	{ PCI_DEVICE_ID_AMD_8111_IDE,		 0x40, ATA_UDMA6, AMD_CHECK_SERENADE },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,	 0x50, ATA_UDMA5, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE, 0x50, ATA_UDMA6, },
+-	{ PCI_DEVICE_ID_AMD_CS5536_IDE,		 0x40, ATA_UDMA5, },
+-	{ 0 }
++enum {
++	AMD_IDE_CONFIG		= 0x41,
++	AMD_CABLE_DETECT	= 0x42,
++	AMD_DRIVE_TIMING	= 0x48,
++	AMD_8BIT_TIMING		= 0x4e,
++	AMD_ADDRESS_SETUP	= 0x4c,
++	AMD_UDMA_TIMING		= 0x50,
+ };
+ 
+-static struct amd_ide_chip *amd_config;
+-static const struct ide_port_info *amd_chipset;
+ static unsigned int amd_80w;
+ static unsigned int amd_clock;
+ 
+ static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
+ static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
+ 
++static inline u8 amd_offset(struct pci_dev *dev)
++{
++	return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
++}
++
+ /*
+  * amd_set_speed() writes timing values to the chipset registers
+  */
+ 
+-static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
++static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
++			  struct ide_timing *timing)
+ {
+-	unsigned char t;
++	u8 t = 0, offset = amd_offset(dev);
+ 
+-	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
++	pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
+ 	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+-	pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
++	pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
+ 
+-	pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
++	pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
+ 		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+ 
+-	pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
++	pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
+ 		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+ 
+-	switch (amd_config->udma_mask) {
++	switch (udma_mask) {
+ 	case ATA_UDMA2: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+ 	case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
+ 	case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
+@@ -110,7 +73,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
+ 	default: return;
+ 	}
+ 
+-	pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
++	pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + (3 - dn), t);
+ }
+ 
+ /*
+@@ -120,12 +83,15 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
+ 
+ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
+ {
+-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
++	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++	ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
+ 	struct ide_timing t, p;
+ 	int T, UT;
++	u8 udma_mask = hwif->ultra_mask;
+ 
+ 	T = 1000000000 / amd_clock;
+-	UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
++	UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
+ 
+ 	ide_timing_compute(drive, speed, &t, T, UT);
+ 
+@@ -137,7 +103,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
+ 	if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
+ 	if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
+ 
+-	amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
++	amd_set_speed(dev, drive->dn, udma_mask, &t);
+ }
+ 
+ /*
+@@ -149,67 +115,68 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	amd_set_drive(drive, XFER_PIO_0 + pio);
+ }
+ 
+-/*
+- * The initialization callback. Here we determine the IDE chip type
+- * and initialize its drive independent registers.
+- */
++static void __devinit amd7409_cable_detect(struct pci_dev *dev,
++					   const char *name)
++{
++	/* no host side cable detection */
++	amd_80w = 0x03;
++}
+ 
+-static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name)
++static void __devinit amd7411_cable_detect(struct pci_dev *dev,
++					   const char *name)
+ {
+-	unsigned char t;
+-	unsigned int u;
+ 	int i;
++	u32 u = 0;
++	u8 t = 0, offset = amd_offset(dev);
++
++	pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
++	pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
++	amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
++	for (i = 24; i >= 0; i -= 8)
++		if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
++			printk(KERN_WARNING "%s: BIOS didn't set cable bits "
++					    "correctly. Enabling workaround.\n",
++					    name);
++			amd_80w |= (1 << (1 - (i >> 4)));
++		}
++}
+ 
+ /*
+- * Check for bad SWDMA.
++ * The initialization callback.  Initialize drive independent registers.
+  */
+ 
+-	if (amd_config->flags & AMD_CHECK_SWDMA) {
+-		if (dev->revision <= 7)
+-			amd_config->flags |= AMD_BAD_SWDMA;
+-	}
++static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev,
++						   const char *name)
++{
++	u8 t = 0, offset = amd_offset(dev);
+ 
+ /*
+  * Check 80-wire cable presence.
+  */
+ 
+-	switch (amd_config->udma_mask) {
+-
+-		case ATA_UDMA6:
+-		case ATA_UDMA5:
+-			pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
+-			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+-			amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
+-			for (i = 24; i >= 0; i -= 8)
+-				if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
+-					printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n",
+-						amd_chipset->name);
+-					amd_80w |= (1 << (1 - (i >> 4)));
+-				}
+-			break;
+-
+-		case ATA_UDMA4:
+-			/* no host side cable detection */
+-			amd_80w = 0x03;
+-			break;
+-	}
++	if (dev->vendor == PCI_VENDOR_ID_AMD &&
++	    dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
++		; /* no UDMA > 2 */
++	else if (dev->vendor == PCI_VENDOR_ID_AMD &&
++		 dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
++		amd7409_cable_detect(dev, name);
++	else
++		amd7411_cable_detect(dev, name);
+ 
+ /*
+  * Take care of prefetch & postwrite.
+  */
+ 
+-	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+-	pci_write_config_byte(dev, AMD_IDE_CONFIG,
+-		(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
+-
+-/*
+- * Take care of incorrectly wired Serenade mainboards.
+- */
+-
+-	if ((amd_config->flags & AMD_CHECK_SERENADE) &&
+-		dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+-		dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+-			amd_config->udma_mask = ATA_UDMA5;
++	pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
++	/*
++	 * Check for broken FIFO support.
++	 */
++	if (dev->vendor == PCI_VENDOR_ID_AMD &&
++	    dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411)
++		t &= 0x0f;
++	else
++		t |= 0xf0;
++	pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
+ 
+ /*
+  * Determine the system bus clock.
+@@ -225,25 +192,19 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
+ 
+ 	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);
++				    name, amd_clock);
+ 		amd_clock = 33333;
+ 	}
+ 
+-/*
+- * Print the boot message.
+- */
+-
+-	printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
+-		amd_chipset->name, pci_name(dev), dev->revision,
+-		amd_dma[fls(amd_config->udma_mask) - 1]);
+-
+ 	return dev->irq;
+ }
+ 
+ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	if (hwif->irq == 0) /* 0 is bogus but will do for now */
+-		hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel);
++		hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
+ 
+ 	hwif->set_pio_mode = &amd_set_pio_mode;
+ 	hwif->set_dma_mode = &amd_set_drive;
+@@ -251,10 +212,6 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+ 	if (!hwif->dma_base)
+ 		return;
+ 
+-	hwif->ultra_mask = amd_config->udma_mask;
+-	if (amd_config->flags & AMD_BAD_SWDMA)
+-		hwif->swdma_mask = 0x00;
+-
+ 	if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
+ 		if ((amd_80w >> hwif->channel) & 1)
+ 			hwif->cbl = ATA_CBL_PATA80;
+@@ -266,12 +223,13 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
  #define IDE_HFLAGS_AMD \
  	(IDE_HFLAG_PIO_NO_BLACKLIST | \
  	 IDE_HFLAG_PIO_NO_DOWNGRADE | \
@@ -392123,18 +408723,134 @@
  	 IDE_HFLAG_POST_SET_MODE | \
  	 IDE_HFLAG_IO_32BIT | \
  	 IDE_HFLAG_UNMASK_IRQS | \
+ 	 IDE_HFLAG_BOOTABLE)
+ 
+-#define DECLARE_AMD_DEV(name_str)					\
++#define DECLARE_AMD_DEV(name_str, swdma, udma)				\
+ 	{								\
+ 		.name		= name_str,				\
+ 		.init_chipset	= init_chipset_amd74xx,			\
+@@ -279,11 +237,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+ 		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},	\
+ 		.host_flags	= IDE_HFLAGS_AMD,			\
+ 		.pio_mask	= ATA_PIO5,				\
+-		.swdma_mask	= ATA_SWDMA2,				\
++		.swdma_mask	= swdma,				\
+ 		.mwdma_mask	= ATA_MWDMA2,				\
++		.udma_mask	= udma,					\
+ 	}
+ 
+-#define DECLARE_NV_DEV(name_str)					\
++#define DECLARE_NV_DEV(name_str, udma)					\
+ 	{								\
+ 		.name		= name_str,				\
+ 		.init_chipset	= init_chipset_amd74xx,			\
+@@ -293,45 +252,62 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+ 		.pio_mask	= ATA_PIO5,				\
+ 		.swdma_mask	= ATA_SWDMA2,				\
+ 		.mwdma_mask	= ATA_MWDMA2,				\
++		.udma_mask	= udma,					\
+ 	}
+ 
+ static const struct ide_port_info amd74xx_chipsets[] __devinitdata = {
+-	/*  0 */ DECLARE_AMD_DEV("AMD7401"),
+-	/*  1 */ DECLARE_AMD_DEV("AMD7409"),
+-	/*  2 */ DECLARE_AMD_DEV("AMD7411"),
+-	/*  3 */ DECLARE_AMD_DEV("AMD7441"),
+-	/*  4 */ DECLARE_AMD_DEV("AMD8111"),
+-
+-	/*  5 */ DECLARE_NV_DEV("NFORCE"),
+-	/*  6 */ DECLARE_NV_DEV("NFORCE2"),
+-	/*  7 */ DECLARE_NV_DEV("NFORCE2-U400R"),
+-	/*  8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"),
+-	/*  9 */ DECLARE_NV_DEV("NFORCE3-150"),
+-	/* 10 */ DECLARE_NV_DEV("NFORCE3-250"),
+-	/* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"),
+-	/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
+-	/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
+-	/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
+-	/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
+-	/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
+-	/* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
+-	/* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
+-	/* 19 */ DECLARE_NV_DEV("NFORCE-MCP67"),
+-	/* 20 */ DECLARE_NV_DEV("NFORCE-MCP73"),
+-	/* 21 */ DECLARE_NV_DEV("NFORCE-MCP77"),
+-	/* 22 */ DECLARE_AMD_DEV("AMD5536"),
++	/*  0 */ DECLARE_AMD_DEV("AMD7401",	  0x00, ATA_UDMA2),
++	/*  1 */ DECLARE_AMD_DEV("AMD7409", ATA_SWDMA2, ATA_UDMA4),
++	/*  2 */ DECLARE_AMD_DEV("AMD7411", ATA_SWDMA2, ATA_UDMA5),
++	/*  3 */ DECLARE_AMD_DEV("AMD7441", ATA_SWDMA2, ATA_UDMA5),
++	/*  4 */ DECLARE_AMD_DEV("AMD8111", ATA_SWDMA2, ATA_UDMA6),
++
++	/*  5 */ DECLARE_NV_DEV("NFORCE",		ATA_UDMA5),
++	/*  6 */ DECLARE_NV_DEV("NFORCE2",		ATA_UDMA6),
++	/*  7 */ DECLARE_NV_DEV("NFORCE2-U400R",	ATA_UDMA6),
++	/*  8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA",	ATA_UDMA6),
++	/*  9 */ DECLARE_NV_DEV("NFORCE3-150",		ATA_UDMA6),
++	/* 10 */ DECLARE_NV_DEV("NFORCE3-250",		ATA_UDMA6),
++	/* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA",	ATA_UDMA6),
++	/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2",	ATA_UDMA6),
++	/* 13 */ DECLARE_NV_DEV("NFORCE-CK804",		ATA_UDMA6),
++	/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04",		ATA_UDMA6),
++	/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51",		ATA_UDMA6),
++	/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55",		ATA_UDMA6),
++	/* 17 */ DECLARE_NV_DEV("NFORCE-MCP61",		ATA_UDMA6),
++	/* 18 */ DECLARE_NV_DEV("NFORCE-MCP65",		ATA_UDMA6),
++	/* 19 */ DECLARE_NV_DEV("NFORCE-MCP67",		ATA_UDMA6),
++	/* 20 */ DECLARE_NV_DEV("NFORCE-MCP73",		ATA_UDMA6),
++	/* 21 */ DECLARE_NV_DEV("NFORCE-MCP77",		ATA_UDMA6),
++
++	/* 22 */ DECLARE_AMD_DEV("AMD5536", ATA_SWDMA2, ATA_UDMA5),
+ };
+ 
+ static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ {
+-	amd_chipset = amd74xx_chipsets + id->driver_data;
+-	amd_config = amd_ide_chips + id->driver_data;
+-	if (dev->device != amd_config->id) {
+-		printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n",
+-		       pci_name(dev), dev->device, amd_config->id);
+-		return -ENODEV;
++	struct ide_port_info d;
++	u8 idx = id->driver_data;
++
++	d = amd74xx_chipsets[idx];
++
++	/*
++	 * Check for bad SWDMA and incorrectly wired Serenade mainboards.
++	 */
++	if (idx == 1) {
++		if (dev->revision <= 7)
++			d.swdma_mask = 0;
++		d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
++	} else if (idx == 4) {
++		if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
++		    dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
++			d.udma_mask = ATA_UDMA5;
+ 	}
+-	return ide_setup_pci_device(dev, amd_chipset);
++
++	printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
++			 d.name, pci_name(dev), dev->revision,
++			 amd_dma[fls(d.udma_mask) - 1]);
++
++	return ide_setup_pci_device(dev, &d);
+ }
+ 
+ static const struct pci_device_id amd74xx_pci_tbl[] = {
 diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
-index ef8e016..4918719 100644
+index ef8e016..b56274a 100644
 --- a/drivers/ide/pci/atiixp.c
 +++ b/drivers/ide/pci/atiixp.c
-@@ -1,5 +1,5 @@
+@@ -1,6 +1,4 @@
  /*
 - *  linux/drivers/ide/pci/atiixp.c	Version 0.03	Aug 3 2007
-+ *  linux/drivers/ide/pci/atiixp.c	Version 0.05	Nov 9 2007
-  *
+- *
   *  Copyright (C) 2003 ATI Inc. <hyu at ati.com>
   *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
-@@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = {
+  */
+@@ -43,47 +41,8 @@ static atiixp_ide_timing mdma_timing[] = {
  	{ 0x02, 0x00 },
  };
  
@@ -392182,7 +408898,22 @@
  /**
   *	atiixp_set_pio_mode	-	set host controller for PIO mode
   *	@drive: drive
-@@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -94,7 +53,7 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
+ 
+ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	unsigned long flags;
+ 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ 	u32 pio_timing_data;
+@@ -127,34 +86,38 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 
+ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	unsigned long flags;
  	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
  	u32 tmp32;
  	u16 tmp16;
@@ -392229,7 +408960,19 @@
  	spin_unlock_irqrestore(&atiixp_lock, flags);
  }
  
-@@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
+@@ -168,9 +131,8 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 
+ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
+ {
+-	u8 udma_mode = 0;
+-	u8 ch = hwif->channel;
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
++	u8 udma_mode = 0, ch = hwif->channel;
+ 
+ 	hwif->set_pio_mode = &atiixp_set_pio_mode;
+ 	hwif->set_dma_mode = &atiixp_set_dma_mode;
+@@ -184,9 +146,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
  		hwif->cbl = ATA_CBL_PATA80;
  	else
  		hwif->cbl = ATA_CBL_PATA40;
@@ -392240,10 +408983,17 @@
  
  static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
 diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
-index 4aa4810..da3565e 100644
+index 4aa4810..7240c20 100644
 --- a/drivers/ide/pci/cmd640.c
 +++ b/drivers/ide/pci/cmd640.c
-@@ -706,9 +706,9 @@ static int pci_conf2(void)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/cmd640.c		Version 1.02  Sep 01, 1996
+- *
+  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
+  */
+ 
+@@ -706,9 +704,9 @@ static int pci_conf2(void)
  }
  
  /*
@@ -392255,7 +409005,7 @@
  {
  #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
  	int second_port_toggled = 0;
-@@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void)
+@@ -717,6 +715,7 @@ int __init ide_probe_for_cmd640x (void)
  	const char *bus_type, *port2;
  	unsigned int index;
  	u8 b, cfr;
@@ -392263,7 +409013,7 @@
  
  	if (cmd640_vlb && probe_for_cmd640_vlb()) {
  		bus_type = "VLB";
-@@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void)
+@@ -769,6 +768,8 @@ int __init ide_probe_for_cmd640x (void)
  	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
  
@@ -392272,7 +409022,7 @@
  	/*
  	 * Ensure compatibility by always using the slowest timings
  	 * for access to the drive's command register block,
-@@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void)
+@@ -826,6 +827,8 @@ int __init ide_probe_for_cmd640x (void)
  		cmd_hwif1->pio_mask = ATA_PIO5;
  		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
  #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -392281,7 +409031,7 @@
  	}
  	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
  		cmd_hwif0->serialized ? "" : "not ", port2);
-@@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void)
+@@ -872,6 +875,13 @@ int __init ide_probe_for_cmd640x (void)
  #ifdef CMD640_DUMP_REGS
  	cmd640_dump_regs();
  #endif
@@ -392296,17 +409046,17 @@
 +
 +module_init(cmd640x_init);
 diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
-index bc55333..cd4eb9d 100644
+index bc55333..04aa9e5 100644
 --- a/drivers/ide/pci/cmd64x.c
 +++ b/drivers/ide/pci/cmd64x.c
-@@ -1,5 +1,5 @@
+@@ -1,6 +1,4 @@
  /*
 - * linux/drivers/ide/pci/cmd64x.c		Version 1.52	Dec 24, 2007
-+ * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
-  *
+- *
   * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
   *           Due to massive hardware bugs, UltraDMA is only supported
-@@ -22,8 +22,6 @@
+  *           on the 646U2 and not on the 646U.
+@@ -22,8 +20,6 @@
  
  #include <asm/io.h>
  
@@ -392315,7 +409065,7 @@
  #define CMD_DEBUG 0
  
  #if CMD_DEBUG
-@@ -37,11 +35,6 @@
+@@ -37,11 +33,6 @@
   */
  #define CFR		0x50
  #define   CFR_INTR_CH0		0x04
@@ -392327,7 +409077,7 @@
  
  #define	CMDTIM		0x52
  #define	ARTTIM0		0x53
-@@ -60,108 +53,13 @@
+@@ -60,108 +51,13 @@
  #define MRDMODE		0x71
  #define   MRDMODE_INTR_CH0	0x04
  #define   MRDMODE_INTR_CH1	0x08
@@ -392436,7 +409186,34 @@
  static u8 quantize_timing(int timing, int quant)
  {
  	return (timing + quant - 1) / quant;
-@@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -173,7 +69,7 @@ static u8 quantize_timing(int timing, int quant)
+  */
+ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
+ {
+-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(drive->hwif->dev);
+ 	int clock_time		= 1000 / system_bus_clock();
+ 	u8  cycle_count, active_count, recovery_count, drwtim;
+ 	static const u8 recovery_values[] =
+@@ -220,7 +116,7 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
+ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	unsigned int cycle_time;
+ 	u8 setup_count, arttim = 0;
+ 
+@@ -285,7 +181,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 unit			= drive->dn & 0x01;
+ 	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
+ 
+@@ -322,8 +218,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	case XFER_MW_DMA_0:
  		program_cycle_times(drive, 480, 215);
  		break;
@@ -392445,7 +409222,7 @@
  	}
  
  	if (speed >= XFER_SW_DMA_0)
-@@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -333,14 +227,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
  static int cmd648_ide_dma_end (ide_drive_t *drive)
  {
  	ide_hwif_t *hwif	= HWIF(drive);
@@ -392463,7 +409240,16 @@
  
  	return err;
  }
-@@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
+@@ -348,7 +243,7 @@ static int cmd648_ide_dma_end (ide_drive_t *drive)
+ static int cmd64x_ide_dma_end (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
+ 	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
+ 						  CFR_INTR_CH0;
+@@ -365,10 +260,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
  static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
  {
  	ide_hwif_t *hwif	= HWIF(drive);
@@ -392476,7 +409262,16 @@
  
  #ifdef DEBUG
  	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
-@@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
+@@ -387,7 +283,7 @@ static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+ static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
+ 	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
+ 						  CFR_INTR_CH0;
+@@ -472,22 +368,12 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
  	mrdmode &= ~0x30;
  	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
  
@@ -392493,13 +409288,43 @@
  	return 0;
  }
  
+ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
+ {
+-	struct pci_dev  *dev	= hwif->pci_dev;
++	struct pci_dev  *dev	= to_pci_dev(hwif->dev);
+ 	u8 bmidecsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
+ 
+ 	switch (dev->device) {
+@@ -502,7 +388,7 @@ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
+ 
+ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 
+ 	hwif->set_pio_mode = &cmd64x_set_pio_mode;
+ 	hwif->set_dma_mode = &cmd64x_set_dma_mode;
+@@ -555,7 +441,9 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
+ 		.init_chipset	= init_chipset_cmd64x,
+ 		.init_hwif	= init_hwif_cmd64x,
+ 		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
+-		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
++		.host_flags	= IDE_HFLAG_CLEAR_SIMPLEX |
++				  IDE_HFLAG_ABUSE_PREFETCH |
++				  IDE_HFLAG_BOOTABLE,
+ 		.pio_mask	= ATA_PIO5,
+ 		.mwdma_mask	= ATA_MWDMA2,
+ 		.udma_mask	= 0x00, /* no udma */
 diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
-index 0466462..6ec00b8 100644
+index 0466462..eb68a9a 100644
 --- a/drivers/ide/pci/cs5520.c
 +++ b/drivers/ide/pci/cs5520.c
-@@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -69,9 +69,8 @@ static struct pio_clocks cs5520_pio_clocks[]={
+ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
  	ide_hwif_t *hwif = HWIF(drive);
- 	struct pci_dev *pdev = hwif->pci_dev;
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
  	int controller = drive->dn > 1 ? 1 : 0;
 -	u8 reg;
  
@@ -392554,11 +409379,35 @@
  				  IDE_HFLAG_BOOTABLE,		\
  		.pio_mask	= ATA_PIO4,			\
  	}
+@@ -160,8 +156,14 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
+ 	ide_setup_pci_noise(dev, d);
+ 
+ 	/* We must not grab the entire device, it has 'ISA' space in its
+-	   BARS too and we will freak out other bits of the kernel */
+-	if (pci_enable_device_bars(dev, 1<<2)) {
++	 * BARS too and we will freak out other bits of the kernel
++	 *
++	 * pci_enable_device_bars() is going away. I replaced it with
++	 * IO only enable for now but I'll need confirmation this is
++	 * allright for that device. If not, it will need some kind of
++	 * quirk. --BenH.
++	 */
++	if (pci_enable_device_io(dev)) {
+ 		printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
+ 		return -ENODEV;
+ 	}
 diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
-index 5476903..df5966b 100644
+index 5476903..765aac3 100644
 --- a/drivers/ide/pci/cs5530.c
 +++ b/drivers/ide/pci/cs5530.c
-@@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/cs5530.c		Version 0.77	Sep 24 2007
+- *
+  * Copyright (C) 2000			Andre Hedrick <andre at linux-ide.org>
+  * Copyright (C) 2000			Mark Lord <mlord at pobox.com>
+  * Copyright (C) 2007			Bartlomiej Zolnierkiewicz
+@@ -116,8 +114,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
  		case XFER_MW_DMA_0:	timings = 0x00077771; break;
  		case XFER_MW_DMA_1:	timings = 0x00012121; break;
  		case XFER_MW_DMA_2:	timings = 0x00002020; break;
@@ -392568,10 +409417,33 @@
  	basereg = CS5530_BASEREG(drive->hwif);
  	reg = inl(basereg + 4);			/* get drive0 config register */
 diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
-index ddcbeba..50b3d77 100644
+index ddcbeba..66433aa 100644
 --- a/drivers/ide/pci/cs5535.c
 +++ b/drivers/ide/pci/cs5535.c
-@@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = {
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/cs5535.c
+- *
+  * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+  * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
+  *
+@@ -177,20 +175,22 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
+  */
+ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	hwif->set_pio_mode = &cs5535_set_pio_mode;
+ 	hwif->set_dma_mode = &cs5535_set_dma_mode;
+ 
+ 	if (hwif->dma_base == 0)
+ 		return;
+ 
+-	hwif->cbl = cs5535_cable_detect(hwif->pci_dev);
++	hwif->cbl = cs5535_cable_detect(dev);
+ }
+ 
+ static const struct ide_port_info cs5535_chipset __devinitdata = {
  	.name		= "CS5535",
  	.init_hwif	= init_hwif_cs5535,
  	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
@@ -392581,17 +409453,17 @@
  	.mwdma_mask	= ATA_MWDMA2,
  	.udma_mask	= ATA_UDMA4,
 diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
-index 1cd4e9c..3ec4c65 100644
+index 1cd4e9c..50100ac 100644
 --- a/drivers/ide/pci/cy82c693.c
 +++ b/drivers/ide/pci/cy82c693.c
-@@ -1,5 +1,5 @@
+@@ -1,6 +1,4 @@
  /*
 - * linux/drivers/ide/pci/cy82c693.c		Version 0.42	Oct 23, 2007
-+ * linux/drivers/ide/pci/cy82c693.c		Version 0.44	Nov 8, 2007
-  *
+- *
   *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs at altavista.net), Maintainer
   *  Copyright (C) 1998-2002 Andre Hedrick <andre at linux-ide.org>, Integrator
-@@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+  *
+@@ -176,17 +174,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
   * set DMA mode a specific channel for CY82C693
   */
  
@@ -392613,7 +409485,7 @@
  
  #if CY82C693_DEBUG_LOGS
  	/* for debug let's show the previous values */
-@@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+@@ -199,7 +192,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
  		(data&0x3), ((data>>2)&1));
  #endif /* CY82C693_DEBUG_LOGS */
  
@@ -392622,7 +409494,7 @@
  
  	outb(index, CY82_INDEX_PORT);
  	outb(data, CY82_DATA_PORT);
-@@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+@@ -207,7 +200,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
  #if CY82C693_DEBUG_INFO
  	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
  		drive->name, HWIF(drive)->channel, drive->select.b.unit,
@@ -392631,7 +409503,7 @@
  #endif /* CY82C693_DEBUG_INFO */
  
  	/* 
-@@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+@@ -230,43 +223,10 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
  #endif /* CY82C693_DEBUG_INFO */
  }
  
@@ -392671,7 +409543,12 @@
  static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
  {
  	ide_hwif_t *hwif = HWIF(drive);
-@@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	pio_clocks_t pclk;
+ 	unsigned int addrCtrl;
+ 
+@@ -429,18 +389,15 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
  static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
  {
  	hwif->set_pio_mode = &cy82c693_set_pio_mode;
@@ -392684,7 +409561,16 @@
  }
  
  static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
-@@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
+ {
+ 	static ide_hwif_t *primary;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 
+-	if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
++	if (PCI_FUNC(dev->devfn) == 1)
+ 		primary = hwif;
+ 	else {
+ 		hwif->mate = primary;
+@@ -454,11 +411,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
  	.init_iops	= init_iops_cy82c693,
  	.init_hwif	= init_hwif_cy82c693,
  	.chipset	= ide_cy82c693,
@@ -392700,10 +409586,17 @@
  
  static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
-index 8382908..26aa492 100644
+index 8382908..27e47fc 100644
 --- a/drivers/ide/pci/delkin_cb.c
 +++ b/drivers/ide/pci/delkin_cb.c
-@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/delkin_cb.c
+- *
+  *  Created 20 Oct 2004 by Mark Lord
+  *
+  *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+@@ -80,14 +78,14 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
  	hw.irq = dev->irq;
  	hw.chipset = ide_pci;		/* this enables IRQ sharing */
  
@@ -392712,16 +409605,64 @@
  	if (rc < 0) {
  		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
  		pci_disable_device(dev);
+ 		return -ENODEV;
+ 	}
+ 	pci_set_drvdata(dev, hwif);
+-	hwif->pci_dev = dev;
++	hwif->dev = &dev->dev;
+ 	drive = &hwif->drives[0];
+ 	if (drive->present) {
+ 		drive->io_32bit = 1;
+diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
+index 0688569..59ebe84 100644
+--- a/drivers/ide/pci/generic.c
++++ b/drivers/ide/pci/generic.c
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/generic.c	Version 0.11	December 30, 2002
+- *
+  *  Copyright (C) 2001-2002	Andre Hedrick <andre at linux-ide.org>
+  *  Portions (C) Copyright 2002  Red Hat Inc <alan at redhat.com>
+  *
+@@ -104,7 +102,8 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = {
+ 
+ 	{	/* 14 */
+ 		.name		= "Revolution",
+-		.host_flags	= IDE_HFLAG_TRUST_BIOS_FOR_DMA |
++		.host_flags	= IDE_HFLAG_CLEAR_SIMPLEX |
++				  IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ 				  IDE_HFLAG_OFF_BOARD,
+ 		.swdma_mask	= ATA_SWDMA2,
+ 		.mwdma_mask	= ATA_MWDMA2,
 diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
-index ae6307f..dfba0d1 100644
+index ae6307f..25dbb81 100644
 --- a/drivers/ide/pci/hpt34x.c
 +++ b/drivers/ide/pci/hpt34x.c
-@@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
+@@ -1,7 +1,6 @@
+ /*
+- * linux/drivers/ide/pci/hpt34x.c		Version 0.40	Sept 10, 2002
+- *
+  * Copyright (C) 1998-2000	Andre Hedrick <andre at linux-ide.org>
++ *
+  * May be copied or modified under the terms of the GNU General Public License
+  *
+  *
+@@ -45,7 +44,7 @@
+ 
+ static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
+ {
+-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+ 	u8			hi_speed, lo_speed;
+ 
+@@ -129,14 +128,19 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
  	hwif->set_dma_mode = &hpt34x_set_mode;
  }
  
 +#define IDE_HFLAGS_HPT34X \
 +	(IDE_HFLAG_NO_ATAPI_DMA | \
++	 IDE_HFLAG_NO_DSC | \
 +	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
 +	 IDE_HFLAG_NO_AUTODMA)
 +
@@ -392749,17 +409690,17 @@
  #ifdef CONFIG_HPT34X_AUTODMA
  		.swdma_mask	= ATA_SWDMA2,
 diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
-index 9fce25b..1268593 100644
+index 9fce25b..5623cad 100644
 --- a/drivers/ide/pci/hpt366.c
 +++ b/drivers/ide/pci/hpt366.c
-@@ -1,5 +1,5 @@
+@@ -1,6 +1,4 @@
  /*
 - * linux/drivers/ide/pci/hpt366.c		Version 1.22	Dec 4, 2007
-+ * linux/drivers/ide/pci/hpt366.c		Version 1.30	Dec 12, 2007
-  *
+- *
   * Copyright (C) 1999-2003		Andre Hedrick <andre at linux-ide.org>
   * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
-@@ -88,7 +88,7 @@
+  * Portions Copyright (C) 2003		Red Hat Inc
+@@ -88,7 +86,7 @@
   * - rename all the register related variables consistently
   * - move all the interrupt twiddling code from the speedproc handlers into
   *   init_hwif_hpt366(), also grouping all the DMA related code together there
@@ -392768,7 +409709,7 @@
   *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
   *   when setting an UltraDMA mode
   * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
-@@ -458,6 +458,13 @@ enum ata_clock {
+@@ -458,6 +456,13 @@ enum ata_clock {
  	NUM_ATA_CLOCKS
  };
  
@@ -392782,7 +409723,7 @@
  /*
   *	Hold all the HighPoint chip information in one place.
   */
-@@ -468,7 +475,8 @@ struct hpt_info {
+@@ -468,7 +473,8 @@ struct hpt_info {
  	u8 udma_mask;		/* Allowed UltraDMA modes mask. */
  	u8 dpll_clk;		/* DPLL clock in MHz */
  	u8 pci_clk;		/* PCI  clock in MHz */
@@ -392792,7 +409733,7 @@
  };
  
  /* Supported HighPoint chips */
-@@ -486,20 +494,30 @@ enum {
+@@ -486,20 +492,30 @@ enum {
  	HPT371N
  };
  
@@ -392835,7 +409776,7 @@
  };
  
  static const struct hpt_info hpt36x __devinitdata = {
-@@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = {
+@@ -507,7 +523,7 @@ static const struct hpt_info hpt36x __devinitdata = {
  	.chip_type	= HPT36x,
  	.udma_mask	= HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
  	.dpll_clk	= 0,	/* no DPLL */
@@ -392844,7 +409785,7 @@
  };
  
  static const struct hpt_info hpt370 __devinitdata = {
-@@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = {
+@@ -515,7 +531,7 @@ static const struct hpt_info hpt370 __devinitdata = {
  	.chip_type	= HPT370,
  	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
  	.dpll_clk	= 48,
@@ -392853,7 +409794,7 @@
  };
  
  static const struct hpt_info hpt370a __devinitdata = {
-@@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = {
+@@ -523,7 +539,7 @@ static const struct hpt_info hpt370a __devinitdata = {
  	.chip_type	= HPT370A,
  	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
  	.dpll_clk	= 48,
@@ -392862,7 +409803,7 @@
  };
  
  static const struct hpt_info hpt374 __devinitdata = {
-@@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = {
+@@ -531,7 +547,7 @@ static const struct hpt_info hpt374 __devinitdata = {
  	.chip_type	= HPT374,
  	.udma_mask	= ATA_UDMA5,
  	.dpll_clk	= 48,
@@ -392871,7 +409812,7 @@
  };
  
  static const struct hpt_info hpt372 __devinitdata = {
-@@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = {
+@@ -539,7 +555,7 @@ static const struct hpt_info hpt372 __devinitdata = {
  	.chip_type	= HPT372,
  	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 55,
@@ -392880,7 +409821,7 @@
  };
  
  static const struct hpt_info hpt372a __devinitdata = {
-@@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = {
+@@ -547,7 +563,7 @@ static const struct hpt_info hpt372a __devinitdata = {
  	.chip_type	= HPT372A,
  	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 66,
@@ -392889,7 +409830,7 @@
  };
  
  static const struct hpt_info hpt302 __devinitdata = {
-@@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = {
+@@ -555,7 +571,7 @@ static const struct hpt_info hpt302 __devinitdata = {
  	.chip_type	= HPT302,
  	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 66,
@@ -392898,7 +409839,7 @@
  };
  
  static const struct hpt_info hpt371 __devinitdata = {
-@@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = {
+@@ -563,7 +579,7 @@ static const struct hpt_info hpt371 __devinitdata = {
  	.chip_type	= HPT371,
  	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 66,
@@ -392907,7 +409848,7 @@
  };
  
  static const struct hpt_info hpt372n __devinitdata = {
-@@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = {
+@@ -571,7 +587,7 @@ static const struct hpt_info hpt372n __devinitdata = {
  	.chip_type	= HPT372N,
  	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 77,
@@ -392916,7 +409857,7 @@
  };
  
  static const struct hpt_info hpt302n __devinitdata = {
-@@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = {
+@@ -579,7 +595,7 @@ static const struct hpt_info hpt302n __devinitdata = {
  	.chip_type	= HPT302N,
  	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 77,
@@ -392925,7 +409866,7 @@
  };
  
  static const struct hpt_info hpt371n __devinitdata = {
-@@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = {
+@@ -587,7 +603,7 @@ static const struct hpt_info hpt371n __devinitdata = {
  	.chip_type	= HPT371N,
  	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
  	.dpll_clk	= 77,
@@ -392934,7 +409875,27 @@
  };
  
  static int check_in_drive_list(ide_drive_t *drive, const char **list)
-@@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
+@@ -608,7 +624,8 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
+ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct hpt_info *info	= pci_get_drvdata(hwif->pci_dev);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
++	struct hpt_info *info	= pci_get_drvdata(dev);
+ 	u8 mask 		= hwif->ultra_mask;
+ 
+ 	switch (info->chip_type) {
+@@ -647,7 +664,8 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
+ static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct hpt_info *info	= pci_get_drvdata(hwif->pci_dev);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
++	struct hpt_info *info	= pci_get_drvdata(dev);
+ 
+ 	switch (info->chip_type) {
+ 	case HPT372 :
+@@ -675,100 +693,56 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
  	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
  		if (xfer_speeds[i] == speed)
  			break;
@@ -392952,7 +409913,7 @@
  {
 -	ide_hwif_t *hwif	= HWIF(drive);
 -	struct pci_dev  *dev	= hwif->pci_dev;
-+	struct pci_dev  *dev	= HWIF(drive)->pci_dev;
++	struct pci_dev  *dev	= to_pci_dev(drive->hwif->dev);
  	struct hpt_info	*info	= pci_get_drvdata(dev);
 -	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
 +	struct hpt_timings *t	= info->timings;
@@ -393047,7 +410008,68 @@
  }
  
  static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
-@@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev	*dev	= hwif->pci_dev;
++	struct pci_dev	*dev	= to_pci_dev(hwif->dev);
+ 	struct hpt_info *info	= pci_get_drvdata(dev);
+ 
+ 	if (drive->quirk_list) {
+@@ -800,7 +774,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
+  */
+ static void hpt366_dma_lost_irq(ide_drive_t *drive)
+ {
+-	struct pci_dev *dev = HWIF(drive)->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+ 
+ 	pci_read_config_byte(dev, 0x50, &mcr1);
+@@ -816,18 +790,20 @@ static void hpt366_dma_lost_irq(ide_drive_t *drive)
+ static void hpt370_clear_engine(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 
+-	pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
++	pci_write_config_byte(dev, hwif->select_data, 0x37);
+ 	udelay(10);
+ }
+ 
+ static void hpt370_irq_timeout(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u16 bfifo		= 0;
+ 	u8  dma_cmd;
+ 
+-	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
++	pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
+ 	printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+ 
+ 	/* get DMA command mode */
+@@ -870,10 +846,11 @@ static void hpt370_dma_timeout(ide_drive_t *drive)
+ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u16 bfifo		= 0;
+ 	u8  dma_stat;
+ 
+-	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
++	pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
+ 	if (bfifo & 0x1FF) {
+ //		printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ 		return 0;
+@@ -893,7 +870,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
+ static int hpt374_ide_dma_end(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev	*dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 mcr	= 0, mcr_addr	= hwif->select_data;
+ 	u8 bwsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
+ 
+@@ -914,32 +891,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
  
  static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
  {
@@ -393091,7 +410113,16 @@
  }
  
  /**
-@@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+@@ -967,7 +945,7 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
+ static int hpt3xx_busproc(ide_drive_t *drive, int state)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8  mcr_addr		= hwif->select_data + 2;
+ 	u8  resetmask		= hwif->channel ? 0x80 : 0x40;
+ 	u8  bsr2		= 0;
+@@ -1210,7 +1188,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
  	 * We also  don't like using  the DPLL because this causes glitches
  	 * on PRST-/SRST- when the state engine gets reset...
  	 */
@@ -393100,7 +410131,7 @@
  		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
  		int adjust;
  
-@@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+@@ -1226,7 +1204,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
  			clock = ATA_CLOCK_50MHZ;
  		}
  
@@ -393109,7 +410140,7 @@
  			printk(KERN_ERR "%s: unknown bus timing!\n", name);
  			kfree(info);
  			return -EIO;
-@@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+@@ -1267,15 +1245,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
  		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
  	}
  
@@ -393126,7 +410157,16 @@
  
  	/* Point to this chip's own instance of the hpt_info structure. */
  	pci_set_drvdata(dev, info);
-@@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+@@ -1308,7 +1281,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
+ 
+ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+ {
+-	struct pci_dev	*dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	struct hpt_info *info	= pci_get_drvdata(dev);
+ 	int serialize		= HPT_SERIALIZE_IO;
+ 	u8  scr1 = 0, ata66	= hwif->channel ? 0x01 : 0x02;
+@@ -1320,8 +1293,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
  
  	hwif->set_pio_mode	= &hpt3xx_set_pio_mode;
  	hwif->set_dma_mode	= &hpt3xx_set_mode;
@@ -393136,7 +410176,25 @@
  	hwif->maskproc		= &hpt3xx_maskproc;
  	hwif->busproc		= &hpt3xx_busproc;
  
-@@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
+@@ -1423,7 +1396,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+ 
+ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
+ {
+-	struct pci_dev	*dev		= hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u8 masterdma	= 0, slavedma	= 0;
+ 	u8 dma_new	= 0, dma_old	= 0;
+ 	unsigned long flags;
+@@ -1443,7 +1416,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
+ 
+ 	local_irq_restore(flags);
+ 
+-	ide_setup_dma(hwif, dmabase, 8);
++	ide_setup_dma(hwif, dmabase);
+ }
+ 
+ static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
+@@ -1494,6 +1467,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
  	return 0;
  }
  
@@ -393148,7 +410206,7 @@
  static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  	{	/* 0 */
  		.name		= "HPT36x",
-@@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1508,9 +1486,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		 */
  		.enablebits	= {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
  		.extra		= 240,
@@ -393159,7 +410217,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  	},{	/* 1 */
-@@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1520,7 +1496,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		.init_dma	= init_dma_hpt366,
  		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
  		.extra		= 240,
@@ -393168,7 +410226,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  	},{	/* 2 */
-@@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1530,7 +1506,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		.init_dma	= init_dma_hpt366,
  		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
  		.extra		= 240,
@@ -393177,7 +410235,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  	},{	/* 3 */
-@@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1540,7 +1516,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		.init_dma	= init_dma_hpt366,
  		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
  		.extra		= 240,
@@ -393186,7 +410244,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  	},{	/* 4 */
-@@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1551,7 +1527,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
  		.udma_mask	= ATA_UDMA5,
  		.extra		= 240,
@@ -393195,7 +410253,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  	},{	/* 5 */
-@@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+@@ -1561,7 +1537,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
  		.init_dma	= init_dma_hpt366,
  		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
  		.extra		= 240,
@@ -393205,9 +410263,27 @@
  		.mwdma_mask	= ATA_MWDMA2,
  	}
 diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
-index 90b52ed..2a0f45c 100644
+index 90b52ed..df74e58 100644
 --- a/drivers/ide/pci/it8213.c
 +++ b/drivers/ide/pci/it8213.c
+@@ -28,7 +28,7 @@
+ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	int is_slave		= drive->dn & 1;
+ 	int master_port		= 0x40;
+ 	int slave_port		= 0x44;
+@@ -85,7 +85,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 maslave		= 0x40;
+ 	int a_speed		= 3 << (drive->dn * 4);
+ 	int u_flag		= 1 << drive->dn;
 @@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	pci_read_config_byte(dev, 0x54, &reg54);
  	pci_read_config_byte(dev, 0x55, &reg55);
@@ -393237,11 +410313,157 @@
  		if (!(reg48 & u_flag))
  			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
  		if (speed >= XFER_UDMA_5) {
+@@ -165,6 +152,7 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 
+ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u8 reg42h = 0;
+ 
+ 	hwif->set_dma_mode = &it8213_set_dma_mode;
+@@ -173,7 +161,7 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+ 	if (!hwif->dma_base)
+ 		return;
+ 
+-	pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
++	pci_read_config_byte(dev, 0x42, &reg42h);
+ 
+ 	if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ 		hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
-index 99b7d76..e610a53 100644
+index 99b7d76..938d35f 100644
 --- a/drivers/ide/pci/it821x.c
 +++ b/drivers/ide/pci/it821x.c
-@@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
+@@ -1,7 +1,4 @@
+-
+ /*
+- * linux/drivers/ide/pci/it821x.c		Version 0.16	Jul 3 2007
+- *
+  * Copyright (C) 2004		Red Hat <alan at redhat.com>
+  * Copyright (C) 2007		Bartlomiej Zolnierkiewicz
+  *
+@@ -113,7 +110,8 @@ static int it8212_noraid;
+ 
+ static void it821x_program(ide_drive_t *drive, u16 timing)
+ {
+-	ide_hwif_t *hwif	= drive->hwif;
++	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ 	int channel = hwif->channel;
+ 	u8 conf;
+@@ -123,7 +121,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
+ 		conf = timing >> 8;
+ 	else
+ 		conf = timing & 0xFF;
+-	pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
++
++	pci_write_config_byte(dev, 0x54 + 4 * channel, conf);
+ }
+ 
+ /**
+@@ -137,7 +136,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
+ 
+ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+ {
+-	ide_hwif_t *hwif	= drive->hwif;
++	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ 	int channel = hwif->channel;
+ 	int unit = drive->select.b.unit;
+@@ -148,11 +148,12 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+ 		conf = timing >> 8;
+ 	else
+ 		conf = timing & 0xFF;
+-	if(itdev->timing10 == 0)
+-		pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf);
++
++	if (itdev->timing10 == 0)
++		pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf);
+ 	else {
+-		pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf);
+-		pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf);
++		pci_write_config_byte(dev, 0x56 + 4 * channel, conf);
++		pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf);
+ 	}
+ }
+ 
+@@ -167,6 +168,7 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+ static void it821x_clock_strategy(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ 
+ 	u8 unit = drive->select.b.unit;
+@@ -205,10 +207,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
+ 		itdev->clock_mode = ATA_50;
+ 		sel = 1;
+ 	}
+-	pci_read_config_byte(hwif->pci_dev, 0x50, &v);
++
++	pci_read_config_byte(dev, 0x50, &v);
+ 	v &= ~(1 << (1 + hwif->channel));
+ 	v |= sel << (1 + hwif->channel);
+-	pci_write_config_byte(hwif->pci_dev, 0x50, v);
++	pci_write_config_byte(dev, 0x50, v);
+ 
+ 	/*
+ 	 *	Reprogram the UDMA/PIO of the pair drive for the switch
+@@ -282,7 +285,8 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 
+ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+ {
+-	ide_hwif_t *hwif	= drive->hwif;
++	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+ 	int unit = drive->select.b.unit;
+ 	int channel = hwif->channel;
+@@ -297,12 +301,12 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+ 	itdev->udma[unit] = UDMA_OFF;
+ 
+ 	/* UDMA bits off - Revision 0x10 do them in pairs */
+-	pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+-	if(itdev->timing10)
++	pci_read_config_byte(dev, 0x50, &conf);
++	if (itdev->timing10)
+ 		conf |= channel ? 0x60: 0x18;
+ 	else
+ 		conf |= 1 << (3 + 2 * channel + unit);
+-	pci_write_config_byte(hwif->pci_dev, 0x50, conf);
++	pci_write_config_byte(dev, 0x50, conf);
+ 
+ 	it821x_clock_strategy(drive);
+ 	/* FIXME: do we need to program this ? */
+@@ -320,7 +324,8 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+ 
+ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+ {
+-	ide_hwif_t *hwif	= drive->hwif;
++	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ 	int unit = drive->select.b.unit;
+ 	int channel = hwif->channel;
+@@ -337,12 +342,12 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+ 		itdev->udma[unit] |= 0x8080;	/* UDMA 5/6 select on */
+ 
+ 	/* UDMA on. Again revision 0x10 must do the pair */
+-	pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+-	if(itdev->timing10)
++	pci_read_config_byte(dev, 0x50, &conf);
++	if (itdev->timing10)
+ 		conf &= channel ? 0x9F: 0xE7;
+ 	else
+ 		conf &= ~ (1 << (3 + 2 * channel + unit));
+-	pci_write_config_byte(hwif->pci_dev, 0x50, conf);
++	pci_write_config_byte(dev, 0x50, conf);
+ 
+ 	it821x_clock_strategy(drive);
+ 	it821x_program_udma(drive, itdev->udma[unit]);
+@@ -431,33 +436,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
  }
  
  /**
@@ -393285,7 +410507,7 @@
  	/*
  	 *	Perform fixups on smart mode. We need to "lose" some
  	 *	capabilities the firmware lacks but does not filter, and
-@@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
+@@ -465,16 +466,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
  	 *	in RAID mode.
  	 */
  
@@ -393302,7 +410524,11 @@
  		/* Check for RAID v native */
  		if(strstr(id->model, "Integrated Technology Express")) {
  			/* In raid mode the ident block is slightly buggy
-@@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+@@ -534,9 +525,12 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
+ 
+ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
  	struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
  	u8 conf;
  
@@ -393311,7 +410537,25 @@
  	if (idev == NULL) {
  		printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
  		return;
-@@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
+@@ -544,7 +538,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+ 
+ 	ide_set_hwifdata(hwif, idev);
+ 
+-	pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
++	pci_read_config_byte(dev, 0x50, &conf);
+ 	if (conf & 1) {
+ 		idev->smart = 1;
+ 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+@@ -567,7 +561,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+ 	 *	this is necessary.
+ 	 */
+ 
+-	pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
++	pci_read_config_byte(dev, 0x08, &conf);
+ 	if (conf == 0x10) {
+ 		idev->timing10 = 1;
+ 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+@@ -633,7 +627,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
  		.name		= name_str,		\
  		.init_chipset	= init_chipset_it821x,	\
  		.init_hwif	= init_hwif_it821x,	\
@@ -393319,11 +410563,103 @@
  		.host_flags	= IDE_HFLAG_BOOTABLE,	\
  		.pio_mask	= ATA_PIO4,		\
  	}
+diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
+index 0083eaf..8b40f64 100644
+--- a/drivers/ide/pci/jmicron.c
++++ b/drivers/ide/pci/jmicron.c
+@@ -30,7 +30,7 @@ typedef enum {
+ 
+ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 
+ 	u32 control;
+ 	u32 control5;
+diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
+index d4df464..fc9eee9 100644
+--- a/drivers/ide/pci/ns87415.c
++++ b/drivers/ide/pci/ns87415.c
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/ns87415.c		Version 2.00  Sep. 10, 2002
+- *
+  * Copyright (C) 1997-1998	Mark Lord <mlord at pobox.com>
+  * Copyright (C) 1998		Eddie C. Dost <ecd at skynet.be>
+  * Copyright (C) 1999-2000	Andre Hedrick <andre at linux-ide.org>
+@@ -71,10 +69,9 @@ static u8 superio_ide_inb (unsigned long port)
+ 
+ static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
+ {
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 	u32 base, dmabase;
+-	u8 tmp;
+-	struct pci_dev *pdev = hwif->pci_dev;
+-	u8 port = hwif->channel;
++	u8 port = hwif->channel, tmp;
+ 
+ 	base = pci_resource_start(pdev, port * 2) & ~3;
+ 	dmabase = pci_resource_start(pdev, 4) & ~3;
+@@ -93,10 +90,11 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
+ 
+ static void __devinit init_iops_ns87415(ide_hwif_t *hwif)
+ {
+-	if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
++	if (PCI_SLOT(dev->devfn) == 0xE)
+ 		/* Built-in - assume it's under superio. */
+ 		superio_ide_init_iops(hwif);
+-	}
+ }
+ #endif
+ 
+@@ -110,8 +108,8 @@ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+-	struct pci_dev *dev = hwif->pci_dev;
+ 	unsigned long flags;
+ 
+ 	local_irq_save(flags);
+@@ -189,7 +187,7 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive)
+ 
+ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned int ctrl, using_inta;
+ 	u8 progif;
+ #ifdef __sparc_v9__
+@@ -231,8 +229,8 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
+ 
+ #ifdef __sparc_v9__
+ 		/*
+-		 * XXX: Reset the device, if we don't it will not respond
+-		 *      to SELECT_DRIVE() properly during first probe_hwif().
++		 * XXX: Reset the device, if we don't it will not respond to
++		 *      SELECT_DRIVE() properly during first ide_probe_port().
+ 		 */
+ 		timeout = 10000;
+ 		outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
+index 8953d9c..0ce92d3 100644
+--- a/drivers/ide/pci/opti621.c
++++ b/drivers/ide/pci/opti621.c
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/opti621.c		Version 0.9	Sep 24, 2007
+- *
+  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
+  */
+ 
 diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
-index 2b4f44e..89d2363 100644
+index 2b4f44e..bb29db0 100644
 --- a/drivers/ide/pci/pdc202xx_new.c
 +++ b/drivers/ide/pci/pdc202xx_new.c
-@@ -146,7 +146,7 @@ static struct udma_timing {
+@@ -146,9 +146,10 @@ static struct udma_timing {
  	{ 0x1a, 0x01, 0xcb },	/* UDMA mode 6 */
  };
  
@@ -393331,9 +410667,16 @@
 +static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
  {
  	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
  	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
-@@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
- 	if (max_dma_rate(hwif->pci_dev) == 4) {
+ 
+ 	/*
+@@ -159,48 +160,21 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+ 	 * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
+ 	 * chips, we must override the default register settings...
+ 	 */
+-	if (max_dma_rate(hwif->pci_dev) == 4) {
++	if (max_dma_rate(dev) == 4) {
  		u8 mode = speed & 0x07;
  
 -		switch (speed) {
@@ -393390,15 +410733,16 @@
  		}
  	} else if (speed == XFER_UDMA_2) {
  		/* Set tHOLD bit to 0 if using UDMA mode 2 */
-@@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+@@ -212,7 +186,15 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
  
  static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
  {
 -	pdcnew_set_mode(drive, XFER_PIO_0 + pio);
 +	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
 +	u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
 +
-+	if (max_dma_rate(hwif->pci_dev) == 4) {
++	if (max_dma_rate(dev) == 4) {
 +		set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
 +		set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
 +		set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
@@ -393406,7 +410750,7 @@
  }
  
  static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
-@@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+@@ -223,14 +205,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
  		return ATA_CBL_PATA80;
  }
  
@@ -393428,7 +410772,7 @@
  }
  
  static void pdcnew_reset(ide_drive_t *drive)
-@@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
+@@ -466,7 +451,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
  static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
  {
  	hwif->set_pio_mode = &pdcnew_set_pio_mode;
@@ -393438,10 +410782,38 @@
  	hwif->quirkproc = &pdcnew_quirkproc;
  	hwif->resetproc = &pdcnew_reset;
 diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
-index e09742e..3a1e081 100644
+index e09742e..31a1308 100644
 --- a/drivers/ide/pci/pdc202xx_old.c
 +++ b/drivers/ide/pci/pdc202xx_old.c
-@@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/pdc202xx_old.c	Version 0.52	Aug 27, 2007
+- *
+  *  Copyright (C) 1998-2002		Andre Hedrick <andre at linux-ide.org>
+  *  Copyright (C) 2006-2007		MontaVista Software, Inc.
+  *  Copyright (C) 2007			Bartlomiej Zolnierkiewicz
+@@ -66,7 +64,7 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
+ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 drive_pci		= 0x60 + (drive->dn << 2);
+ 
+ 	u8			AP = 0, BP = 0, CP = 0;
+@@ -144,9 +142,10 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 
+ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+ 
+-	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
++	pci_read_config_word(dev, 0x50, &CIS);
+ 
+ 	return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+ }
+@@ -162,7 +161,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
   */
  static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
  {
@@ -393450,7 +410822,7 @@
  	u8 clock = inb(clock_reg);
  
  	outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
-@@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
+@@ -170,20 +169,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
  
  static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
  {
@@ -393479,7 +410851,7 @@
  }
  
  static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
-@@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
+@@ -193,7 +195,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
  	if (drive->media != ide_disk || drive->addressing == 1) {
  		struct request *rq	= HWGROUP(drive)->rq;
  		ide_hwif_t *hwif	= HWIF(drive);
@@ -393488,7 +410860,7 @@
  		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
  		u32 word_count	= 0;
  		u8 clock = inb(high_16 + 0x11);
-@@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+@@ -212,7 +214,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
  {
  	if (drive->media != ide_disk || drive->addressing == 1) {
  		ide_hwif_t *hwif	= HWIF(drive);
@@ -393497,7 +410869,7 @@
  		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
  		u8 clock		= 0;
  
-@@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+@@ -228,7 +230,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
  static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
  {
  	ide_hwif_t *hwif	= HWIF(drive);
@@ -393506,7 +410878,7 @@
  	u8 dma_stat		= inb(hwif->dma_status);
  	u8 sc1d			= inb(high_16 + 0x001d);
  
-@@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
+@@ -271,7 +273,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
  
  static void pdc202xx_reset_host (ide_hwif_t *hwif)
  {
@@ -393515,7 +410887,50 @@
  	u8 udma_speed_flag	= inb(high_16 | 0x001f);
  
  	outb(udma_speed_flag | 0x10, high_16 | 0x001f);
-@@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+@@ -302,12 +304,14 @@ static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
+ 
+ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+ 	hwif->set_dma_mode = &pdc202xx_set_mode;
+ 
+ 	hwif->quirkproc = &pdc202xx_quirkproc;
+ 
+-	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
++	if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
+ 		hwif->resetproc = &pdc202xx_reset;
+ 
+ 	if (hwif->dma_base == 0)
+@@ -316,7 +320,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
+ 	hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
+ 	hwif->dma_timeout = &pdc202xx_dma_timeout;
+ 
+-	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
++	if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+ 		if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ 			hwif->cbl = pdc202xx_old_cable_detect(hwif);
+ 
+@@ -331,7 +335,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
+ 	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+ 
+ 	if (hwif->channel) {
+-		ide_setup_dma(hwif, dmabase, 8);
++		ide_setup_dma(hwif, dmabase);
+ 		return;
+ 	}
+ 
+@@ -355,7 +359,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
+ 	}
+ #endif /* CONFIG_PDC202XX_BURST */
+ 
+-	ide_setup_dma(hwif, dmabase, 8);
++	ide_setup_dma(hwif, dmabase);
+ }
+ 
+ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+@@ -375,6 +379,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
  	}
  }
  
@@ -393527,7 +410942,7 @@
  #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
  	{ \
  		.name		= name_str, \
-@@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+@@ -382,9 +391,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
  		.init_hwif	= init_hwif_pdc202xx, \
  		.init_dma	= init_dma_pdc202xx, \
  		.extra		= 48, \
@@ -393538,7 +410953,7 @@
  		.pio_mask	= ATA_PIO4, \
  		.mwdma_mask	= ATA_MWDMA2, \
  		.udma_mask	= udma, \
-@@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
+@@ -397,8 +404,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
  		.init_hwif	= init_hwif_pdc202xx,
  		.init_dma	= init_dma_pdc202xx,
  		.extra		= 16,
@@ -393549,10 +410964,90 @@
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA2,
 diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
-index 27781d2..bd6d3f7 100644
+index 27781d2..c1a6b68 100644
 --- a/drivers/ide/pci/piix.c
 +++ b/drivers/ide/pci/piix.c
-@@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/piix.c	Version 0.54	Sep 5, 2007
+- *
+  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+  *  Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
+  *  Copyright (C) 2003 Red Hat Inc <alan at redhat.com>
+@@ -8,53 +6,8 @@
+  *
+  *  May be copied or modified under the terms of the GNU General Public License
+  *
+- *  PIO mode setting function for Intel chipsets.
+- *  For use instead of BIOS settings.
+- *
+- * 40-41
+- * 42-43
+- * 
+- *                 41
+- *                 43
+- *
+- * | PIO 0       | c0 | 80 | 0 |
+- * | PIO 2 | SW2 | d0 | 90 | 4 |
+- * | PIO 3 | MW1 | e1 | a1 | 9 |
+- * | PIO 4 | MW2 | e3 | a3 | b |
+- *
+- * sitre = word40 & 0x4000; primary
+- * sitre = word42 & 0x4000; secondary
+- *
+- * 44 8421|8421    hdd|hdb
+- *
+- * 48 8421         hdd|hdc|hdb|hda udma enabled
+- *
+- *    0001         hda
+- *    0010         hdb
+- *    0100         hdc
+- *    1000         hdd
+- *
+- * 4a 84|21        hdb|hda
+- * 4b 84|21        hdd|hdc
++ * Documentation:
+  *
+- *    ata-33/82371AB
+- *    ata-33/82371EB
+- *    ata-33/82801AB            ata-66/82801AA
+- *    00|00 udma 0              00|00 reserved
+- *    01|01 udma 1              01|01 udma 3
+- *    10|10 udma 2              10|10 udma 4
+- *    11|11 reserved            11|11 reserved
+- *
+- * 54 8421|8421    ata66 drive|ata66 enable
+- *
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, &reg48);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &reg54);
+- *
+- * Documentation
+  *	Publically available from Intel web site. Errata documentation
+  * is also publically available. As an aide to anyone hacking on this
+  * driver the list of errata that are relevant is below.going back to
+@@ -116,7 +69,7 @@ static int no_piix_dma;
+ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	int is_slave		= drive->dn & 1;
+ 	int master_port		= hwif->channel ? 0x42 : 0x40;
+ 	int slave_port		= 0x44;
+@@ -185,7 +138,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+ 	int a_speed		= 3 << (drive->dn * 4);
+ 	int u_flag		= 1 << drive->dn;
+@@ -203,20 +156,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	pci_read_config_byte(dev, 0x54, &reg54);
  	pci_read_config_byte(dev, 0x55, &reg55);
  
@@ -393577,11 +411072,63 @@
  		if (!(reg48 & u_flag))
  			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
  		if (speed == XFER_UDMA_5) {
+@@ -314,7 +258,7 @@ static const struct ich_laptop ich_laptop[] = {
+ 
+ static u8 __devinit piix_cable_detect(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 	const struct ich_laptop *lap = &ich_laptop[0];
+ 	u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
+ 
+diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
+index 6b10ae2..7ed6625 100644
+--- a/drivers/ide/pci/rz1000.c
++++ b/drivers/ide/pci/rz1000.c
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/rz1000.c	Version 0.06	January 12, 2003
+- *
+  *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
+  */
+ 
+@@ -32,8 +30,8 @@
+ 
+ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u16 reg;
+-	struct pci_dev *dev = hwif->pci_dev;
+ 
+ 	if (!pci_read_config_word (dev, 0x40, &reg) &&
+ 	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
 diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
-index 707d5ff..32fdf53 100644
+index 707d5ff..af499a6 100644
 --- a/drivers/ide/pci/sc1200.c
 +++ b/drivers/ide/pci/sc1200.c
-@@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/sc1200.c		Version 0.97	Aug 3 2007
+- *
+  * Copyright (C) 2000-2002		Mark Lord <mlord at pobox.com>
+  * Copyright (C)      2007		Bartlomiej Zolnierkiewicz
+  *
+@@ -87,7 +85,7 @@ static const unsigned int sc1200_pio_timings[4][5] =
+ static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 	unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0;
+ 
+ 	pci_read_config_dword(pdev, basereg + 4, &format);
+@@ -130,72 +128,42 @@ out:
+ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
+ {
+ 	ide_hwif_t		*hwif = HWIF(drive);
++	struct pci_dev		*dev = to_pci_dev(hwif->dev);
+ 	int			unit = drive->select.b.unit;
+ 	unsigned int		reg, timings;
  	unsigned short		pci_clock;
  	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
  
@@ -393657,8 +411204,20 @@
 +		timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
  
  	if (unit == 0) {			/* are we configuring drive0? */
- 		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
-@@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+-		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
++		pci_read_config_dword(dev, basereg + 4, &reg);
+ 		timings |= reg & 0x80000000;	/* preserve PIO format bit */
+-		pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
+-	} else {
+-		pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
+-	}
++		pci_write_config_dword(dev, basereg + 4, timings);
++	} else
++		pci_write_config_dword(dev, basereg + 12, timings);
+ }
+ 
+ /*  Replacement for the standard ide_dma_end action in
+@@ -250,9 +218,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
  	}
  	if (mode != -1) {
  		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
@@ -393671,7 +411230,7 @@
  		return;
  	}
  
-@@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -260,66 +228,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
  }
  
  #ifdef CONFIG_PM
@@ -393763,7 +411322,7 @@
  
  	pci_disable_device(dev);
  	pci_set_power_state(dev, pci_choose_state(dev, state));
-@@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
+@@ -328,30 +269,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
  
  static int sc1200_resume (struct pci_dev *dev)
  {
@@ -393808,7 +411367,7 @@
  }
  #endif
 diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
-index ebb7132..24a85bb 100644
+index ebb7132..7694969 100644
 --- a/drivers/ide/pci/scc_pata.c
 +++ b/drivers/ide/pci/scc_pata.c
 @@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
@@ -393832,11 +411391,86 @@
  
  	jcactsel = JCACTSELtbl[offset][idx];
  	if (is_slave) {
+@@ -606,7 +594,7 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
+ 
+ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	struct scc_ports *ports = pci_get_drvdata(dev);
+ 	unsigned long dma_base = ports->dma;
+ 
+@@ -632,7 +620,7 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+ 	hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c;
+ 	hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40;
+ 
+-	hwif->irq = hwif->pci_dev->irq;
++	hwif->irq = dev->irq;
+ 	hwif->dma_base = dma_base;
+ 	hwif->config_data = ports->ctl;
+ 	hwif->mmio = 1;
+@@ -648,7 +636,8 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+ 
+ static void __devinit init_iops_scc(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev =  hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	hwif->hwif_data = NULL;
+ 	if (pci_get_drvdata(dev) == NULL)
+ 		return;
+@@ -738,10 +727,8 @@ static void __devexit scc_remove(struct pci_dev *dev)
+ 	unsigned long dma_size = pci_resource_len(dev, 1);
+ 
+ 	if (hwif->dmatable_cpu) {
+-		pci_free_consistent(hwif->pci_dev,
+-				    PRD_ENTRIES * PRD_BYTES,
+-				    hwif->dmatable_cpu,
+-				    hwif->dmatable_dma);
++		pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
++				    hwif->dmatable_cpu, hwif->dmatable_dma);
+ 		hwif->dmatable_cpu = NULL;
+ 	}
+ 
 diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
-index a728031..877c09b 100644
+index a728031..f495253 100644
 --- a/drivers/ide/pci/serverworks.c
 +++ b/drivers/ide/pci/serverworks.c
-@@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/serverworks.c		Version 0.22	Jun 27 2007
+- *
+  * Copyright (C) 1998-2000 Michel Aubry
+  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+  * Copyright (C) 1998-2000 Andre Hedrick <andre at linux-ide.org>
+@@ -67,7 +65,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+ 
+ static u8 svwks_udma_filter(ide_drive_t *drive)
+ {
+-	struct pci_dev *dev     = HWIF(drive)->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u8 mask = 0;
+ 
+ 	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
+@@ -130,7 +128,7 @@ static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ 	static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ 	static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+ 
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 
+ 	pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+ 
+@@ -153,7 +151,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	static const u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
+ 
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 unit			= (drive->select.b.unit & 0x01);
+ 
+ 	u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0;
+@@ -164,25 +162,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	ultra_timing	&= ~(0x0F << (4*unit));
  	ultra_enable	&= ~(0x01 << drive->dn);
  
@@ -393868,17 +411502,62 @@
  
  	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
  	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
-@@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
- 	}
- }
- 
-+#define IDE_HFLAGS_SVWKS \
-+	(IDE_HFLAG_LEGACY_IRQS | \
-+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
-+	 IDE_HFLAG_BOOTABLE)
+@@ -300,7 +285,8 @@ static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif)
+  */
+ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
 +
- static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
- 	{	/* 0 */
+ 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ 	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+ 	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
+@@ -318,7 +304,8 @@ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif)
+  */
+ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+ 	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+ 	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+@@ -329,7 +316,7 @@ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
+ 
+ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 
+ 	/* Server Works */
+ 	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+@@ -353,6 +340,8 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
+ 
+ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	hwif->set_pio_mode = &svwks_set_pio_mode;
+ 	hwif->set_dma_mode = &svwks_set_dma_mode;
+ 	hwif->udma_filter = &svwks_udma_filter;
+@@ -360,18 +349,23 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
+ 	if (!hwif->dma_base)
+ 		return;
+ 
+-	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
++	if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ 		if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ 			hwif->cbl = ata66_svwks(hwif);
+ 	}
+ }
+ 
++#define IDE_HFLAGS_SVWKS \
++	(IDE_HFLAG_LEGACY_IRQS | \
++	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
++	 IDE_HFLAG_BOOTABLE)
++
+ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ 	{	/* 0 */
  		.name		= "SvrWks OSB4",
  		.init_chipset	= init_chipset_svwks,
  		.init_hwif	= init_hwif_svwks,
@@ -393887,7 +411566,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= 0x00, /* UDMA is problematic on OSB4 */
-@@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+@@ -379,7 +373,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
  		.name		= "SvrWks CSB5",
  		.init_chipset	= init_chipset_svwks,
  		.init_hwif	= init_hwif_svwks,
@@ -393896,7 +411575,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
-@@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+@@ -387,7 +381,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
  		.name		= "SvrWks CSB6",
  		.init_chipset	= init_chipset_svwks,
  		.init_hwif	= init_hwif_svwks,
@@ -393905,7 +411584,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
-@@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+@@ -395,8 +389,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
  		.name		= "SvrWks CSB6",
  		.init_chipset	= init_chipset_svwks,
  		.init_hwif	= init_hwif_svwks,
@@ -393915,7 +411594,7 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
-@@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+@@ -404,8 +397,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
  		.name		= "SvrWks HT1000",
  		.init_chipset	= init_chipset_svwks,
  		.init_hwif	= init_hwif_svwks,
@@ -393925,10 +411604,48 @@
  		.pio_mask	= ATA_PIO4,
  		.mwdma_mask	= ATA_MWDMA2,
  		.udma_mask	= ATA_UDMA5,
+@@ -428,7 +420,9 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
+ 
+ 	d = serverworks_chipsets[idx];
+ 
+-	if (idx == 2 || idx == 3) {
++	if (idx == 1)
++		d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
++	else if (idx == 2 || idx == 3) {
+ 		if ((PCI_FUNC(dev->devfn) & 1) == 0) {
+ 			if (pci_resource_start(dev, 0) != 0x01f1)
+ 				d.host_flags &= ~IDE_HFLAG_BOOTABLE;
 diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
-index de820aa..9e0be7d 100644
+index de820aa..8590207 100644
 --- a/drivers/ide/pci/sgiioc4.c
 +++ b/drivers/ide/pci/sgiioc4.c
+@@ -159,6 +159,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
+ 		}
+ 
+ 		if (intr_reg & 0x02) {
++			struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 			/* Error when transferring DMA data on PCI bus */
+ 			u32 pci_err_addr_low, pci_err_addr_high,
+ 			    pci_stat_cmd_reg;
+@@ -167,7 +168,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
+ 				readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]);
+ 			pci_err_addr_high =
+ 				readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4));
+-			pci_read_config_dword(hwif->pci_dev, PCI_COMMAND,
++			pci_read_config_dword(dev, PCI_COMMAND,
+ 					      &pci_stat_cmd_reg);
+ 			printk(KERN_ERR
+ 			       "%s(%s) : PCI Bus Error when doing DMA:"
+@@ -178,8 +179,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
+ 			       __FUNCTION__, drive->name,
+ 			       pci_err_addr_high, pci_err_addr_low);
+ 			/* Clear the PCI Error indicator */
+-			pci_write_config_dword(hwif->pci_dev, PCI_COMMAND,
+-					       0x00000146);
++			pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
+ 		}
+ 
+ 		/* Clear the Interrupt, Error bits on the IOC4 */
 @@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
  	return dma_stat;
  }
@@ -393968,7 +411685,53 @@
  }
  
  static void
-@@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
+@@ -352,6 +334,7 @@ sgiioc4_INB(unsigned long port)
+ static int __devinit
+ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	void __iomem *virt_dma_base;
+ 	int num_ports = sizeof (ioc4_dma_regs_t);
+ 	void *pad;
+@@ -377,7 +360,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+ 	}
+ 	hwif->dma_base = (unsigned long) virt_dma_base;
+ 
+-	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
++	hwif->dmatable_cpu = pci_alloc_consistent(dev,
+ 					  IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+ 					  &hwif->dmatable_dma);
+ 
+@@ -386,7 +369,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+ 
+ 	hwif->sg_max_nents = IOC4_PRD_ENTRIES;
+ 
+-	pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE,
++	pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE,
+ 				   (dma_addr_t *) &(hwif->dma_status));
+ 
+ 	if (pad) {
+@@ -394,8 +377,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+ 		return 0;
+ 	}
+ 
+-	pci_free_consistent(hwif->pci_dev,
+-			    IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
++	pci_free_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+ 			    hwif->dmatable_cpu, hwif->dmatable_dma);
+ 	printk(KERN_INFO
+ 	       "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
+@@ -535,8 +517,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
+ 	}
+ 
+ use_pio_instead:
+-	pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents,
+-		     hwif->sg_dma_direction);
++	ide_destroy_dmatable(drive);
+ 
+ 	return 0;		/* revert to PIO for this request */
+ }
+@@ -582,7 +563,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
  	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
  	hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
  						clear interrupts */
@@ -393976,7 +411739,7 @@
  	hwif->maskproc = &sgiioc4_maskproc;	/* Mask on/off NIEN register */
  	hwif->quirkproc = NULL;
  	hwif->busproc = NULL;
-@@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
+@@ -594,14 +574,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
  
  	hwif->mwdma_mask = ATA_MWDMA2_ONLY;
  
@@ -393992,7 +411755,7 @@
  	hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
  	hwif->dma_timeout = &ide_dma_timeout;
  }
-@@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+@@ -615,6 +592,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
  	ide_hwif_t *hwif;
  	int h;
  	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
@@ -394000,7 +411763,7 @@
  
  	/*
  	 * Find an empty HWIF; if none available, return -ENOMEM.
-@@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+@@ -654,21 +632,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
  		return -ENOMEM;
  	}
  
@@ -394023,17 +411786,101 @@
  
 -	hwif->irq = dev->irq;
 -	hwif->chipset = ide_pci;
- 	hwif->pci_dev = dev;
+-	hwif->pci_dev = dev;
++	hwif->dev = &dev->dev;
  	hwif->channel = 0;	/* Single Channel chip */
 -	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
  
  	/* The IOC4 uses MMIO rather than Port IO. */
  	default_hwif_mmiops(hwif);
 diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
-index 5709c25..908f37b 100644
+index 5709c25..4877bc8 100644
 --- a/drivers/ide/pci/siimage.c
 +++ b/drivers/ide/pci/siimage.c
-@@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/siimage.c		Version 1.19	Nov 16 2007
+- *
+  * Copyright (C) 2001-2002	Andre Hedrick <andre at linux-ide.org>
+  * Copyright (C) 2003		Red Hat <alan at redhat.com>
+  * Copyright (C) 2007		MontaVista Software, Inc.
+@@ -79,7 +77,7 @@ static int pdev_is_sata(struct pci_dev *pdev)
+  
+ static inline int is_sata(ide_hwif_t *hwif)
+ {
+-	return pdev_is_sata(hwif->pci_dev);
++	return pdev_is_sata(to_pci_dev(hwif->dev));
+ }
+ 
+ /**
+@@ -140,13 +138,14 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
+ static u8 sil_pata_udma_filter(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned long base = (unsigned long) hwif->hwif_data;
+ 	u8 mask = 0, scsc = 0;
+ 
+ 	if (hwif->mmio)
+ 		scsc = hwif->INB(base + 0x4A);
+ 	else
+-		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
++		pci_read_config_byte(dev, 0x8A, &scsc);
+ 
+ 	if ((scsc & 0x30) == 0x10)	/* 133 */
+ 		mask = ATA_UDMA6;
+@@ -219,19 +218,21 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
+ 		mode |= (unit ? 0x10 : 0x01);
+ 		hwif->OUTB(mode, base + addr_mask);
+ 	} else {
+-		pci_write_config_word(hwif->pci_dev, addr, speedp);
+-		pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
+-		pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
++		struct pci_dev *dev = to_pci_dev(hwif->dev);
++
++		pci_write_config_word(dev, addr, speedp);
++		pci_write_config_word(dev, tfaddr, speedt);
++		pci_read_config_word(dev, tfaddr - 2, &speedp);
+ 		speedp &= ~0x200;
+ 		/* Set IORDY for mode 3 or 4 */
+ 		if (pio > 2)
+ 			speedp |= 0x200;
+-		pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
++		pci_write_config_word(dev, tfaddr - 2, speedp);
+ 
+-		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
++		pci_read_config_byte(dev, addr_mask, &mode);
+ 		mode &= ~(unit ? 0x30 : 0x03);
+ 		mode |= (unit ? 0x10 : 0x01);
+-		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
++		pci_write_config_byte(dev, addr_mask, mode);
+ 	}
+ }
+ 
+@@ -250,6 +251,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };
+ 
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u16 ultra = 0, multi	= 0;
+ 	u8 mode = 0, unit	= drive->select.b.unit;
+ 	unsigned long base	= (unsigned long)hwif->hwif_data;
+@@ -266,10 +268,10 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 		multi = hwif->INW(ma);
+ 		ultra = hwif->INW(ua);
+ 	} else {
+-		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+-		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+-		pci_read_config_word(hwif->pci_dev, ma, &multi);
+-		pci_read_config_word(hwif->pci_dev, ua, &ultra);
++		pci_read_config_byte(dev, 0x8A, &scsc);
++		pci_read_config_byte(dev, addr_mask, &mode);
++		pci_read_config_word(dev, ma, &multi);
++		pci_read_config_word(dev, ua, &ultra);
+ 	}
+ 
+ 	mode &= ~((unit) ? 0x30 : 0x03);
+@@ -278,27 +280,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
  
  	scsc = is_sata(hwif) ? 1 : scsc;
  
@@ -394069,7 +411916,62 @@
  	}
  
  	if (hwif->mmio) {
-@@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
+@@ -306,9 +295,9 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 		hwif->OUTW(multi, ma);
+ 		hwif->OUTW(ultra, ua);
+ 	} else {
+-		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+-		pci_write_config_word(hwif->pci_dev, ma, multi);
+-		pci_write_config_word(hwif->pci_dev, ua, ultra);
++		pci_write_config_byte(dev, addr_mask, mode);
++		pci_write_config_word(dev, ma, multi);
++		pci_write_config_word(dev, ua, ultra);
+ 	}
+ }
+ 
+@@ -316,6 +305,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 dma_altstat		= 0;
+ 	unsigned long addr	= siimage_selreg(hwif, 1);
+ 
+@@ -324,7 +314,7 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+ 		return 1;
+ 
+ 	/* return 1 if Device INTR asserted */
+-	pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat);
++	pci_read_config_byte(dev, addr, &dma_altstat);
+ 	if (dma_altstat & 8)
+ 		return 0;	//return 1;
+ 	return 0;
+@@ -390,13 +380,14 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+ static int sil_sata_busproc(ide_drive_t * drive, int state)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u32 stat_config		= 0;
+ 	unsigned long addr	= siimage_selreg(hwif, 0);
+ 
+ 	if (hwif->mmio)
+ 		stat_config = readl((void __iomem *)addr);
+ 	else
+-		pci_read_config_dword(hwif->pci_dev, addr, &stat_config);
++		pci_read_config_dword(dev, addr, &stat_config);
+ 
+ 	switch (state) {
+ 		case BUSSTATE_ON:
+@@ -656,7 +647,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
+ 
+ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	void *addr		= pci_get_drvdata(dev);
+ 	u8 ch			= hwif->channel;
+ 	hw_regs_t		hw;
+@@ -726,9 +717,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
  	const char *s = &drive->id->model[0];
  	unsigned len;
  
@@ -394079,7 +411981,7 @@
  	len = strnlen(s, sizeof(drive->id->model));
  
  	if ((len > 4) && (!memcmp(s, "ST", 2))) {
-@@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
+@@ -743,18 +731,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
  }
  
  /**
@@ -394104,7 +412006,38 @@
  		hwif->rqsize = 128;
  }
  
-@@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+@@ -770,12 +760,14 @@ static void __devinit siimage_fixup(ide_hwif_t *hwif)
+ 
+ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	hwif->hwif_data = NULL;
+ 
+ 	/* Pessimal until we finish probing */
+ 	hwif->rqsize = 15;
+ 
+-	if (pci_get_drvdata(hwif->pci_dev) == NULL)
++	if (pci_get_drvdata(dev) == NULL)
+ 		return;
+ 
+ 	init_mmio_iops_siimage(hwif);
+@@ -791,11 +783,12 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
+ 
+ static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned long addr = siimage_selreg(hwif, 0);
+ 	u8 ata66 = 0;
+ 
+-	if (pci_get_drvdata(hwif->pci_dev) == NULL)
+-		pci_read_config_byte(hwif->pci_dev, addr, &ata66);
++	if (pci_get_drvdata(dev) == NULL)
++		pci_read_config_byte(dev, addr, &ata66);
+ 	else
+ 		ata66 = hwif->INB(addr);
+ 
+@@ -817,6 +810,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
  
  	hwif->set_pio_mode = &sil_set_pio_mode;
  	hwif->set_dma_mode = &sil_set_dma_mode;
@@ -394112,7 +412045,7 @@
  
  	if (sata) {
  		static int first = 1;
-@@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+@@ -855,7 +849,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
  		.init_chipset	= init_chipset_siimage,	\
  		.init_iops	= init_iops_siimage,	\
  		.init_hwif	= init_hwif_siimage,	\
@@ -394121,22 +412054,114 @@
  		.pio_mask	= ATA_PIO4,		\
  		.mwdma_mask	= ATA_MWDMA2,		\
 diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
-index d90b429..85d3699 100644
+index d90b429..2a461de 100644
 --- a/drivers/ide/pci/sis5513.c
 +++ b/drivers/ide/pci/sis5513.c
-@@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/sis5513.c	Version 0.31	Aug 9, 2007
+- *
+  * Copyright (C) 1999-2000	Andre Hedrick <andre at linux-ide.org>
+  * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton at inet6.fr>, Maintainer
+  * Copyright (C) 2003		Vojtech Pavlik <vojtech at suse.cz>
+@@ -197,7 +195,7 @@ static char* chipset_capability[] = {
+ 
+ static u8 sis_ata133_get_base(ide_drive_t *drive)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u32 reg54 = 0;
+ 
+ 	pci_read_config_dword(dev, 0x54, &reg54);
+@@ -207,7 +205,7 @@ static u8 sis_ata133_get_base(ide_drive_t *drive)
+ 
+ static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u16 t1 = 0;
+ 	u8 drive_pci = 0x40 + drive->dn * 2;
+ 
+@@ -230,7 +228,7 @@ static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
+ 
+ static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u8 t1, drive_pci = 0x40 + drive->dn * 2;
+ 
+ 	/* timing bits: 7:4 active 3:0 recovery */
+@@ -253,7 +251,7 @@ static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
+ 
+ static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u32 t1 = 0;
+ 	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
+ 
+@@ -286,7 +284,7 @@ static void sis_program_timings(ide_drive_t *drive, const u8 mode)
+ static void config_drive_art_rwp (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 reg4bh		= 0;
+ 	u8 rw_prefetch		= 0;
+ 
+@@ -305,64 +303,61 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
  	sis_program_timings(drive, XFER_PIO_0 + pio);
  }
  
--static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
 +static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
++{
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
++	u32 regdw = 0;
++	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
++
++	pci_read_config_dword(dev, drive_pci, &regdw);
++
++	regdw |= 0x04;
++	regdw &= 0xfffff00f;
++	/* check if ATA133 enable */
++	clk = (regdw & 0x08) ? ATA_133 : ATA_100;
++	idx = mode - XFER_UDMA_0;
++	regdw |= cycle_time_value[clk][idx] << 4;
++	regdw |= cvs_time_value[clk][idx] << 8;
++
++	pci_write_config_dword(dev, drive_pci, regdw);
++}
++
++static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
++{
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
++	u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
++
++	pci_read_config_byte(dev, drive_pci + 1, &reg);
++
++	/* force the UDMA bit on if we want to use UDMA */
++	reg |= 0x80;
++	/* clean reg cycle time bits */
++	reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
++	/* set reg cycle time bits */
++	reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
++
++	pci_write_config_byte(dev, drive_pci + 1, reg);
++}
++
++static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
++{
++	if (chipset_family >= ATA_133)	/* ATA_133 */
++		sis_ata133_program_udma_timings(drive, mode);
++	else				/* ATA_33/66/100a/100/133a */
++		sis_ata33_program_udma_timings(drive, mode);
++}
++
+ static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
  {
 -	ide_hwif_t *hwif	= HWIF(drive);
 -	struct pci_dev *dev	= hwif->pci_dev;
-+	struct pci_dev *dev = drive->hwif->pci_dev;
-+	u32 regdw = 0;
-+	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
- 
+-
 -	/* Config chip for mode */
 -	switch(speed) {
 -		case XFER_UDMA_6:
@@ -394185,46 +412210,6 @@
 -		default:
 -			break;
 -	}
-+	pci_read_config_dword(dev, drive_pci, &regdw);
-+
-+	regdw |= 0x04;
-+	regdw &= 0xfffff00f;
-+	/* check if ATA133 enable */
-+	clk = (regdw & 0x08) ? ATA_133 : ATA_100;
-+	idx = mode - XFER_UDMA_0;
-+	regdw |= cycle_time_value[clk][idx] << 4;
-+	regdw |= cvs_time_value[clk][idx] << 8;
-+
-+	pci_write_config_dword(dev, drive_pci, regdw);
-+}
-+
-+static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
-+{
-+	struct pci_dev *dev = drive->hwif->pci_dev;
-+	u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
-+
-+	pci_read_config_byte(dev, drive_pci + 1, &reg);
-+
-+	/* force the UDMA bit on if we want to use UDMA */
-+	reg |= 0x80;
-+	/* clean reg cycle time bits */
-+	reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
-+	/* set reg cycle time bits */
-+	reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
-+
-+	pci_write_config_byte(dev, drive_pci + 1, reg);
-+}
-+
-+static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
-+{
-+	if (chipset_family >= ATA_133)	/* ATA_133 */
-+		sis_ata133_program_udma_timings(drive, mode);
-+	else				/* ATA_33/66/100a/100/133a */
-+		sis_ata33_program_udma_timings(drive, mode);
-+}
-+
-+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
-+{
 +	if (speed >= XFER_UDMA_0)
 +		sis_program_udma_timings(drive, speed);
 +	else
@@ -394232,11 +412217,48 @@
  }
  
  static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
+ {
+-	struct pci_dev *dev = drive->hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u32 regdw = 0;
+ 	u8 drive_pci = sis_ata133_get_base(drive);
+ 
+@@ -533,7 +528,7 @@ static const struct sis_laptop sis_laptop[] = {
+ 
+ static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 	const struct sis_laptop *lap = &sis_laptop[0];
+ 	u8 ata66 = 0;
+ 
+@@ -548,12 +543,12 @@ static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
+ 	if (chipset_family >= ATA_133) {
+ 		u16 regw = 0;
+ 		u16 reg_addr = hwif->channel ? 0x52: 0x50;
+-		pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
++		pci_read_config_word(pdev, reg_addr, &regw);
+ 		ata66 = (regw & 0x8000) ? 0 : 1;
+ 	} else if (chipset_family >= ATA_66) {
+ 		u8 reg48h = 0;
+ 		u8 mask = hwif->channel ? 0x20 : 0x10;
+-		pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
++		pci_read_config_byte(pdev, 0x48, &reg48h);
+ 		ata66 = (reg48h & mask) ? 0 : 1;
+ 	}
+ 
 diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
-index 147d783..c7a125b 100644
+index 147d783..da13a12 100644
 --- a/drivers/ide/pci/sl82c105.c
 +++ b/drivers/ide/pci/sl82c105.c
-@@ -13,6 +13,7 @@
+@@ -1,6 +1,4 @@
+ /*
+- * linux/drivers/ide/pci/sl82c105.c
+- *
+  * SL82C105/Winbond 553 IDE driver
+  *
+  * Maintainer unknown.
+@@ -13,6 +11,7 @@
   *  -- Benjamin Herrenschmidt (01/11/03) benh at kernel.crashing.org
   *
   * Copyright (C) 2006-2007 MontaVista Software, Inc. <source at mvista.com>
@@ -394244,7 +412266,16 @@
   */
  
  #include <linux/types.h>
-@@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
+@@ -77,7 +76,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
+  */
+ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(drive->hwif->dev);
+ 	int reg			= 0x44 + drive->dn * 4;
+ 	u16 drv_ctrl;
+ 
+@@ -90,14 +89,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
  	drive->drive_data &= 0xffff0000;
  	drive->drive_data |= drv_ctrl;
  
@@ -394261,7 +412292,7 @@
  
  	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
  			  ide_xfer_verbose(pio + XFER_PIO_0),
-@@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -115,33 +108,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
   	DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
  	     drive->name, ide_xfer_verbose(speed)));
  
@@ -394302,10 +412333,21 @@
  }
  
  /*
-@@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive)
+@@ -171,7 +145,7 @@ static inline void sl82c105_reset_host(struct pci_dev *dev)
+ static void sl82c105_dma_lost_irq(ide_drive_t *drive)
  {
  	ide_hwif_t *hwif	= HWIF(drive);
- 	struct pci_dev *dev	= hwif->pci_dev;
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u32 val, mask		= hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+ 	u8 dma_cmd;
+ 
+@@ -208,7 +182,12 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive)
+ static void sl82c105_dma_start(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
 +	int reg 		= 0x44 + drive->dn * 4;
 +
 +	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
@@ -394314,12 +412356,22 @@
  
  	sl82c105_reset_host(dev);
  	ide_dma_start(drive);
-@@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive)
+@@ -216,80 +195,43 @@ static void sl82c105_dma_start(ide_drive_t *drive)
+ 
+ static void sl82c105_dma_timeout(ide_drive_t *drive)
+ {
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
++
+ 	DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
+ 
+-	sl82c105_reset_host(HWIF(drive)->pci_dev);
++	sl82c105_reset_host(dev);
  	ide_dma_timeout(drive);
  }
  
 -static int sl82c105_ide_dma_on(ide_drive_t *drive)
--{
++static int sl82c105_dma_end(ide_drive_t *drive)
+ {
 -	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 -	int rc, reg 		= 0x44 + drive->dn * 4;
 -
@@ -394335,9 +412387,9 @@
 -}
 -
 -static void sl82c105_dma_off_quietly(ide_drive_t *drive)
-+static int sl82c105_dma_end(ide_drive_t *drive)
- {
- 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+-{
+-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(drive->hwif->dev);
  	int reg 		= 0x44 + drive->dn * 4;
 +	int ret;
  
@@ -394386,7 +412438,10 @@
   */
  static void sl82c105_resetproc(ide_drive_t *drive)
  {
-@@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive)
+-	struct pci_dev *dev = HWIF(drive)->pci_dev;
++	struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ 	u32 val;
+ 
  	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
  
  	pci_read_config_dword(dev, 0x40, &val);
@@ -394404,7 +412459,14 @@
  
  	return dev->irq;
  }
-@@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
+@@ -352,19 +293,19 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
+  */
+ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	unsigned int rev;
+ 
+ 	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
  
  	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
  	hwif->set_dma_mode	= &sl82c105_set_dma_mode;
@@ -394412,7 +412474,14 @@
  	hwif->resetproc 	= &sl82c105_resetproc;
  
  	if (!hwif->dma_base)
-@@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
+ 		return;
+ 
+-	rev = sl82c105_bridge_revision(hwif->pci_dev);
++	rev = sl82c105_bridge_revision(dev);
+ 	if (rev <= 5) {
+ 		/*
+ 		 * Never ever EVER under any circumstances enable
+@@ -377,10 +318,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
  
  	hwif->mwdma_mask = ATA_MWDMA2;
  
@@ -394425,10 +412494,35 @@
  
  	if (hwif->mate)
 diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
-index eb4445b..dbbb468 100644
+index eb4445b..a6cf810 100644
 --- a/drivers/ide/pci/slc90e66.c
 +++ b/drivers/ide/pci/slc90e66.c
-@@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/pci/slc90e66.c	Version 0.19	Sep 24, 2007
+- *
+  *  Copyright (C) 2000-2002 Andre Hedrick <andre at linux-ide.org>
+  *  Copyright (C) 2006-2007 MontaVista Software, Inc. <source at mvista.com>
+  *
+@@ -26,7 +24,7 @@ static DEFINE_SPINLOCK(slc90e66_lock);
+ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	int is_slave		= drive->dn & 1;
+ 	int master_port		= hwif->channel ? 0x42 : 0x40;
+ 	int slave_port		= 0x44;
+@@ -79,7 +77,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
+ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif	= HWIF(drive);
+-	struct pci_dev *dev	= hwif->pci_dev;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
+ 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+ 	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
+ 	int u_speed = 0, u_flag = 1 << drive->dn;
+@@ -91,19 +89,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	pci_read_config_word(dev, 0x48, &reg48);
  	pci_read_config_word(dev, 0x4a, &reg4a);
  
@@ -394450,11 +412544,44 @@
  		if (!(reg48 & u_flag))
  			pci_write_config_word(dev, 0x48, reg48|u_flag);
  		/* FIXME: (reg4a & a_speed) ? */
+@@ -132,13 +120,14 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+ 
+ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u8 reg47 = 0;
+ 	u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+ 
+ 	hwif->set_pio_mode = &slc90e66_set_pio_mode;
+ 	hwif->set_dma_mode = &slc90e66_set_dma_mode;
+ 
+-	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
++	pci_read_config_byte(dev, 0x47, &reg47);
+ 
+ 	if (hwif->dma_base == 0)
+ 		return;
 diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
-index a66ebd1..e1faf6c 100644
+index a66ebd1..9fbbb4f 100644
 --- a/drivers/ide/pci/tc86c001.c
 +++ b/drivers/ide/pci/tc86c001.c
-@@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
+@@ -1,6 +1,4 @@
+ /*
+- * drivers/ide/pci/tc86c001.c	Version 1.01	Sep 5, 2007
+- *
+  * Copyright (C) 2002 Toshiba Corporation
+  * Copyright (C) 2005-2006 MontaVista Software, Inc. <source at mvista.com>
+  *
+@@ -164,7 +162,8 @@ static int tc86c001_busproc(ide_drive_t *drive, int state)
+ 
+ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+ {
+-	unsigned long sc_base	= pci_resource_start(hwif->pci_dev, 5);
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
++	unsigned long sc_base	= pci_resource_start(dev, 5);
+ 	u16 scr1		= inw(sc_base + 0x00);
+ 
+ 	/* System Control 1 Register bit 15 (Soft Reset) set */
+@@ -222,7 +221,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
  	.name		= "TC86C001",
  	.init_chipset	= init_chipset_tc86c001,
  	.init_hwif	= init_hwif_tc86c001,
@@ -394465,10 +412592,26 @@
  	.mwdma_mask	= ATA_MWDMA2,
  	.udma_mask	= ATA_UDMA4,
 diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
-index a227c41..ae52a96 100644
+index a227c41..852b726 100644
 --- a/drivers/ide/pci/triflex.c
 +++ b/drivers/ide/pci/triflex.c
-@@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
+@@ -1,6 +1,4 @@
+ /*
+- * triflex.c
+- * 
+  * IDE Chipset driver for the Compaq TriFlex IDE controller.
+  * 
+  * Known to work with the Compaq Workstation 5x00 series.
+@@ -43,7 +41,7 @@
+ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	u8 channel_offset = hwif->channel ? 0x74 : 0x70;
+ 	u16 timing = 0;
+ 	u32 triflex_timings = 0;
+@@ -81,8 +79,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
  		case XFER_PIO_0:
  			timing = 0x0808;
  			break;
@@ -394478,26 +412621,133 @@
  
  	triflex_timings &= ~(0xFFFF << (16 * unit));
 diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
-index 0151d7f..04cd893 100644
+index 0151d7f..d9ebb69 100644
 --- a/drivers/ide/pci/trm290.c
 +++ b/drivers/ide/pci/trm290.c
-@@ -241,11 +241,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
- 	return (status == 0x00ff);
+@@ -1,8 +1,7 @@
+ /*
+- *  linux/drivers/ide/pci/trm290.c		Version 1.05	Dec. 26, 2007
+- *
+  *  Copyright (c) 1997-1998  Mark Lord
+  *  Copyright (c) 2007       MontaVista Software, Inc. <source at mvista.com>
++ *
+  *  May be copied or modified under the terms of the GNU General Public License
+  *
+  *  June 22, 2004 - get rid of check_region
+@@ -209,10 +208,10 @@ static int trm290_dma_setup(ide_drive_t *drive)
+ 	}
+ 	/* select DMA xfer */
+ 	trm290_prepare_drive(drive, 1);
+-	outl(hwif->dmatable_dma | rw, hwif->dma_command);
++	outl(hwif->dmatable_dma | rw, hwif->dma_base);
+ 	drive->waiting_for_dma = 1;
+ 	/* start DMA */
+-	outw((count * 2) - 1, hwif->dma_status);
++	outw(count * 2 - 1, hwif->dma_base + 2);
+ 	return 0;
  }
  
--static void trm290_dma_host_on(ide_drive_t *drive)
--{
+@@ -222,51 +221,61 @@ static void trm290_dma_start(ide_drive_t *drive)
+ 
+ static int trm290_ide_dma_end (ide_drive_t *drive)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+-	u16 status = 0;
++	u16 status;
+ 
+ 	drive->waiting_for_dma = 0;
+ 	/* purge DMA mappings */
+ 	ide_destroy_dmatable(drive);
+-	status = inw(hwif->dma_status);
+-	return (status != 0x00ff);
++	status = inw(HWIF(drive)->dma_base + 2);
++	return status != 0x00ff;
+ }
+ 
+ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+-	u16 status = 0;
++	u16 status;
+ 
+-	status = inw(hwif->dma_status);
+-	return (status == 0x00ff);
 -}
 -
+-static void trm290_dma_host_on(ide_drive_t *drive)
+-{
++	status = inw(HWIF(drive)->dma_base + 2);
++	return status == 0x00ff;
+ }
+ 
 -static void trm290_dma_host_off(ide_drive_t *drive)
 +static void trm290_dma_host_set(ide_drive_t *drive, int on)
  {
  }
  
-@@ -289,8 +285,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+ {
+-	unsigned int cfgbase = 0;
++	struct pci_dev *dev	= to_pci_dev(hwif->dev);
++	unsigned int  cfg_base	= pci_resource_start(dev, 4);
+ 	unsigned long flags;
+ 	u8 reg = 0;
+-	struct pci_dev *dev = hwif->pci_dev;
+-
+-	cfgbase = pci_resource_start(dev, 4);
+-	if ((dev->class & 5) && cfgbase) {
+-		hwif->config_data = cfgbase;
+-		printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+-			hwif->config_data);
+-	} else {
+-		hwif->config_data = 0x3df0;
+-		printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+-			hwif->config_data);
++
++	if ((dev->class & 5) && cfg_base)
++		printk(KERN_INFO "TRM290: chip");
++	else {
++		cfg_base = 0x3df0;
++		printk(KERN_INFO "TRM290: using default");
++	}
++	printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
++	hwif->config_data = cfg_base;
++	hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
++
++	printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
++	       hwif->name, hwif->dma_base, hwif->dma_base + 3);
++
++	if (!request_region(hwif->dma_base, 4, hwif->name)) {
++		printk(KERN_CONT " -- Error, ports in use.\n");
++		return;
+ 	}
+ 
++	hwif->dmatable_cpu = pci_alloc_consistent(dev, PRD_ENTRIES * PRD_BYTES,
++						  &hwif->dmatable_dma);
++	if (!hwif->dmatable_cpu) {
++		printk(KERN_CONT " -- Error, unable to allocate DMA table.\n");
++		release_region(hwif->dma_base, 4);
++		return;
++	}
++	printk(KERN_CONT "\n");
++
+ 	local_irq_save(flags);
+ 	/* put config reg into first byte of hwif->select_data */
+ 	outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
+@@ -280,17 +289,14 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+ 	outb(reg, hwif->config_data + 3);
+ 	local_irq_restore(flags);
  
- 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+-	if ((reg & 0x10))
++	if (reg & 0x10)
+ 		/* legacy mode */
+ 		hwif->irq = hwif->channel ? 15 : 14;
+ 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ 		/* sharing IRQ with mate */
+ 		hwif->irq = hwif->mate->irq;
  
+-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+-
 -	hwif->dma_host_off	= &trm290_dma_host_off;
 -	hwif->dma_host_on	= &trm290_dma_host_on;
 +	hwif->dma_host_set	= &trm290_dma_host_set;
@@ -394505,10 +412755,51 @@
  	hwif->dma_exec_cmd	= &trm290_dma_exec_cmd;
  	hwif->dma_start 	= &trm290_dma_start;
 diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
-index a0d3c16..4b32c90 100644
+index a0d3c16..24cb904 100644
 --- a/drivers/ide/pci/via82cxxx.c
 +++ b/drivers/ide/pci/via82cxxx.c
-@@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
+@@ -1,7 +1,4 @@
+ /*
+- *
+- * Version 3.50
+- *
+  * VIA IDE driver for Linux. Supported southbridges:
+  *
+  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+@@ -121,8 +118,8 @@ struct via82cxxx_dev
+ 
+ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
+-	struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++	struct via82cxxx_dev *vdev = pci_get_drvdata(dev);
+ 	u8 t;
+ 
+ 	if (~vdev->via_config->flags & VIA_BAD_AST) {
+@@ -159,8 +156,10 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
+ 
+ static void via_set_drive(ide_drive_t *drive, const u8 speed)
+ {
+-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+-	struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
++	ide_hwif_t *hwif = drive->hwif;
++	ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++	struct via82cxxx_dev *vdev = pci_get_drvdata(dev);
+ 	struct ide_timing t, p;
+ 	unsigned int T, UT;
+ 
+@@ -408,7 +407,7 @@ static int via_cable_override(struct pci_dev *pdev)
+ 
+ static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *pdev = hwif->pci_dev;
++	struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ 	struct via82cxxx_dev *vdev = pci_get_drvdata(pdev);
+ 
+ 	if (via_cable_override(pdev))
+@@ -439,6 +438,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
  	.enablebits	= { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
  	.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST |
  			  IDE_HFLAG_PIO_NO_DOWNGRADE |
@@ -394526,10 +412817,17 @@
 +obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
 +obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
 diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
-index 5f0da35..3fd5d45 100644
+index 5f0da35..45c1d55 100644
 --- a/drivers/ide/ppc/mpc8xx.c
 +++ b/drivers/ide/ppc/mpc8xx.c
-@@ -838,3 +838,21 @@ void m8xx_ide_init(void)
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/ide/ppc/ide-m8xx.c
+- *
+  *  Copyright (C) 2000, 2001 Wolfgang Denk, wd at denx.de
+  *  Modified for direct IDE interface
+  *	by Thomas Lange, thomas at corelatus.com
+@@ -838,3 +836,21 @@ void m8xx_ide_init(void)
  	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
  	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
  }
@@ -394552,10 +412850,19 @@
 +
 +module_init(mpc8xx_ide_probe);
 diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
-index 7f7a598..736d12c 100644
+index 7f7a598..23112ef 100644
 --- a/drivers/ide/ppc/pmac.c
 +++ b/drivers/ide/ppc/pmac.c
-@@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
+@@ -1,7 +1,6 @@
+ /*
+- * linux/drivers/ide/ppc/pmac.c
+- *
+  * Support for IDE interfaces on PowerMacs.
++ *
+  * These IDE interfaces are memory-mapped and have a DBDMA channel
+  * for doing DMA.
+  *
+@@ -438,13 +437,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
  		if (data_port == pmac_ide[ix].regbase)
  			break;
  
@@ -394571,7 +412878,7 @@
  
  	for (i = 0; i < 8; ++i)
  		hw->io_ports[i] = data_port + i * 0x10;
-@@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+@@ -833,38 +827,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	tl[0] = *timings;
  	tl[1] = *timings2;
  
@@ -394622,11 +412929,13 @@
  	if (ret)
  		return;
  
-@@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
+@@ -1034,13 +1010,12 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
+  * (it is kept in 2.4). This introduce an interface numbering change on some
   * rare machines unfortunately, but it's better this way.
   */
- static int
+-static int
 -pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
++static int __devinit
 +pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
  {
  	struct device_node *np = pmif->node;
@@ -394636,7 +412945,7 @@
  
  	pmif->cable_80 = 0;
  	pmif->broken_dma = pmif->broken_dma_warn = 0;
-@@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+@@ -1126,11 +1101,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
  	/* Tell common code _not_ to mess with resources */
  	hwif->mmio = 1;
  	hwif->hwif_data = pmif;
@@ -394651,7 +412960,7 @@
  	hwif->hold = pmif->mediabay;
  	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
  	hwif->drives[0].unmask = 1;
-@@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+@@ -1159,8 +1132,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
  		hwif->noprobe = 0;
  #endif /* CONFIG_PMAC_MEDIABAY */
  
@@ -394660,7 +412969,7 @@
  #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
  	/* has a DBDMA controller channel */
  	if (pmif->dma_regs)
-@@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+@@ -1186,6 +1157,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
  	ide_hwif_t *hwif;
  	pmac_ide_hwif_t *pmif;
  	int i, rc;
@@ -394668,15 +412977,17 @@
  
  	i = 0;
  	while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
-@@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+@@ -1227,8 +1199,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+ 	base = ioremap(macio_resource_start(mdev, 0), 0x400);
  	regbase = (unsigned long) base;
  
- 	hwif->pci_dev = mdev->bus->pdev;
+-	hwif->pci_dev = mdev->bus->pdev;
 -	hwif->gendev.parent = &mdev->ofdev.dev;
++	hwif->dev = &mdev->bus->pdev->dev;
  
  	pmif->mdev = mdev;
  	pmif->node = mdev->ofdev.node;
-@@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+@@ -1246,17 +1217,22 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
  #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
  	dev_set_drvdata(&mdev->ofdev.dev, hwif);
  
@@ -394690,7 +413001,20 @@
  	if (rc != 0) {
  		/* The inteface is released to the common IDE layer */
  		dev_set_drvdata(&mdev->ofdev.dev, NULL);
-@@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ 		iounmap(base);
+-		if (pmif->dma_regs)
++		if (pmif->dma_regs) {
+ 			iounmap(pmif->dma_regs);
++			macio_release_resource(mdev, 1);
++		}
+ 		memset(pmif, 0, sizeof(*pmif));
+ 		macio_release_resource(mdev, 0);
+-		if (pmif->dma_regs)
+-			macio_release_resource(mdev, 1);
+ 	}
+ 
+ 	return rc;
+@@ -1305,6 +1281,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
  	void __iomem *base;
  	unsigned long rbase, rlen;
  	int i, rc;
@@ -394698,15 +413022,17 @@
  
  	np = pci_device_to_OF_node(pdev);
  	if (np == NULL) {
-@@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+@@ -1337,8 +1314,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+ 		return -ENXIO;
  	}
  
- 	hwif->pci_dev = pdev;
+-	hwif->pci_dev = pdev;
 -	hwif->gendev.parent = &pdev->dev;
++	hwif->dev = &pdev->dev;
  	pmif->mdev = NULL;
  	pmif->node = np;
  
-@@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+@@ -1355,7 +1331,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
  
  	pci_set_drvdata(pdev, hwif);
  
@@ -394720,7 +413046,38 @@
  	if (rc != 0) {
  		/* The inteface is released to the common IDE layer */
  		pci_set_drvdata(pdev, NULL);
-@@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
+@@ -1553,11 +1534,10 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+ 	}
+ 
+ 	printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+- use_pio_instead:
+-	pci_unmap_sg(hwif->pci_dev,
+-		     hwif->sg_table,
+-		     hwif->sg_nents,
+-		     hwif->sg_dma_direction);
++
++use_pio_instead:
++	ide_destroy_dmatable(drive);
++
+ 	return 0; /* revert to PIO for this request */
+ }
+ 
+@@ -1566,12 +1546,9 @@ static void
+ pmac_ide_destroy_dmatable (ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = drive->hwif;
+-	struct pci_dev *dev = HWIF(drive)->pci_dev;
+-	struct scatterlist *sg = hwif->sg_table;
+-	int nents = hwif->sg_nents;
+ 
+-	if (nents) {
+-		pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
++	if (hwif->sg_nents) {
++		ide_destroy_dmatable(drive);
+ 		hwif->sg_nents = 0;
+ 	}
+ }
+@@ -1721,11 +1698,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
  	return 1;
  }
  
@@ -394733,7 +413090,34 @@
  {
  }
  
-@@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+@@ -1748,13 +1721,15 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
+  * Allocate the data structures needed for using DMA with an interface
+  * and fill the proper list of functions pointers
+  */
+-static void __init 
++static void __devinit
+ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ {
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++
+ 	/* We won't need pci_dev if we switch to generic consistent
+ 	 * DMA routines ...
+ 	 */
+-	if (hwif->pci_dev == NULL)
++	if (dev == NULL)
+ 		return;
+ 	/*
+ 	 * Allocate space for the DBDMA commands.
+@@ -1762,7 +1737,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+ 	 * aligning the start address to a multiple of 16 bytes.
+ 	 */
+ 	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+-		hwif->pci_dev,
++		dev,
+ 		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+ 		&hwif->dmatable_dma);
+ 	if (pmif->dma_table_cpu == NULL) {
+@@ -1771,15 +1746,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
  		return;
  	}
  
@@ -394752,17 +413136,59 @@
  	hwif->dma_timeout = &ide_dma_timeout;
  	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
  
-@@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+@@ -1809,3 +1783,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
  }
  
  #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 +
 +module_init(pmac_ide_probe);
 diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
-index d2cd5a3..676c66e 100644
+index d2cd5a3..05db429 100644
 --- a/drivers/ide/setup-pci.c
 +++ b/drivers/ide/setup-pci.c
-@@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
+@@ -1,9 +1,8 @@
+ /*
+- *  linux/drivers/ide/setup-pci.c		Version 1.10	2002/08/19
++ *  Copyright (C) 1998-2000  Andre Hedrick <andre at linux-ide.org>
++ *  Copyright (C) 1995-1998  Mark Lord
++ *  Copyright (C)      2007  Bartlomiej Zolnierkiewicz
+  *
+- *  Copyright (c) 1998-2000  Andre Hedrick <andre at linux-ide.org>
+- *
+- *  Copyright (c) 1995-1998  Mark Lord
+  *  May be copied or modified under the terms of the GNU General Public License
+  */
+ 
+@@ -140,6 +139,16 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+ }
+ 
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
++static void ide_pci_clear_simplex(unsigned long dma_base, const char *name)
++{
++	u8 dma_stat = inb(dma_base + 2);
++
++	outb(dma_stat & 0x60, dma_base + 2);
++	dma_stat = inb(dma_base + 2);
++	if (dma_stat & 0x80)
++		printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
++}
++
+ /**
+  *	ide_get_or_set_dma_base		-	setup BMIBA
+  *	@d: IDE port info
+@@ -152,8 +161,9 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+ 
+ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_hwif_t *hwif)
+ {
+-	unsigned long	dma_base = 0;
+-	struct pci_dev	*dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
++	unsigned long dma_base = 0;
++	u8 dma_stat = 0;
+ 
+ 	if (hwif->mmio)
+ 		return hwif->dma_base;
+@@ -165,57 +175,39 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
  
  		dma_base = pci_resource_start(dev, baridx);
  
@@ -394774,16 +413200,102 @@
  	}
  
 -	if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
+-		u8 simplex_stat = 0;
+-		dma_base += hwif->channel ? 8 : 0;
+-
+-		switch(dev->device) {
+-			case PCI_DEVICE_ID_AL_M5219:
+-			case PCI_DEVICE_ID_AL_M5229:
+-			case PCI_DEVICE_ID_AMD_VIPER_7409:
+-			case PCI_DEVICE_ID_CMD_643:
+-			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+-			case PCI_DEVICE_ID_REVOLUTION:
+-				simplex_stat = inb(dma_base + 2);
+-				outb(simplex_stat & 0x60, dma_base + 2);
+-				simplex_stat = inb(dma_base + 2);
+-				if (simplex_stat & 0x80) {
+-					printk(KERN_INFO "%s: simplex device: "
+-							 "DMA forced\n",
+-							 d->name);
+-				}
+-				break;
+-			default:
+-				/*
+-				 * If the device claims "simplex" DMA,
+-				 * this means only one of the two interfaces
+-				 * can be trusted with DMA at any point in time.
+-				 * So we should enable DMA only on one of the
+-				 * two interfaces.
+-				 */
+-				simplex_stat = hwif->INB(dma_base + 2);
+-				if (simplex_stat & 0x80) {
+-					/* simplex device? */
+-/*
+- *	At this point we haven't probed the drives so we can't make the
+- *	appropriate decision. Really we should defer this problem
+- *	until we tune the drive then try to grab DMA ownership if we want
+- *	to be the DMA end. This has to be become dynamic to handle hot
+- *	plug.
+- */
+-					if (hwif->mate && hwif->mate->dma_base) {
+-						printk(KERN_INFO "%s: simplex device: "
+-								 "DMA disabled\n",
+-								 d->name);
+-						dma_base = 0;
+-					}
+-				}
+-		}
 +	if (hwif->channel)
 +		dma_base += 8;
 +
-+	if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
- 		u8 simplex_stat = 0;
--		dma_base += hwif->channel ? 8 : 0;
++	if (d->host_flags & IDE_HFLAG_CS5520)
++		goto out;
++
++	if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
++		ide_pci_clear_simplex(dma_base, d->name);
++		goto out;
++	}
++
++	/*
++	 * If the device claims "simplex" DMA, this means that only one of
++	 * the two interfaces can be trusted with DMA at any point in time
++	 * (so we should enable DMA only on one of the two interfaces).
++	 *
++	 * FIXME: At this point we haven't probed the drives so we can't make
++	 * the appropriate decision.  Really we should defer this problem until
++	 * we tune the drive then try to grab DMA ownership if we want to be
++	 * the DMA end.  This has to be become dynamic to handle hot-plug.
++	 */
++	dma_stat = hwif->INB(dma_base + 2);
++	if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
++		printk(KERN_INFO "%s: simplex device: DMA disabled\n", d->name);
++		dma_base = 0;
+ 	}
++out:
+ 	return dma_base;
+ }
+ #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+@@ -236,7 +228,9 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
+  *	@d: IDE port info
+  *
+  *	Enable the IDE PCI device. We attempt to enable the device in full
+- *	but if that fails then we only need BAR4 so we will enable that.
++ *	but if that fails then we only need IO space. The PCI code should
++ *	have setup the proper resources for us already for controllers in
++ *	legacy mode.
+  *	
+  *	Returns zero on success or an error code
+  */
+@@ -246,7 +240,7 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
+ 	int ret;
  
- 		switch(dev->device) {
- 			case PCI_DEVICE_ID_AL_M5219:
-@@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
+ 	if (pci_enable_device(dev)) {
+-		ret = pci_enable_device_bars(dev, 1 << 4);
++		ret = pci_enable_device_io(dev);
+ 		if (ret < 0) {
+ 			printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+ 				"Could not enable device.\n", d->name);
+@@ -359,6 +353,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
  	unsigned long ctl = 0, base = 0;
  	ide_hwif_t *hwif;
  	u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
@@ -394792,7 +413304,7 @@
  
  	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
  		/*  Possibly we should fail if these checks report true */
-@@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
+@@ -381,26 +377,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
  	}
  	if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
  		return NULL;	/* no room in ide_hwifs[] */
@@ -394810,6 +413322,7 @@
 -		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
 -	}
 -	hwif->chipset = d->chipset ? d->chipset : ide_pci;
+-	hwif->pci_dev = dev;
 +
 +	memset(&hw, 0, sizeof(hw));
 +	hw.irq = hwif->irq ? hwif->irq : irq;
@@ -394825,7 +413338,7 @@
 +
 +	hwif->noprobe = oldnoprobe;
 +
- 	hwif->pci_dev = dev;
++	hwif->dev = &dev->dev;
  	hwif->cds = d;
  	hwif->channel = port;
  
@@ -394834,7 +413347,16 @@
  	if (mate) {
  		hwif->mate = mate;
  		mate->mate = hwif;
-@@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
+@@ -446,7 +441,7 @@ static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info *
+ 			if (d->init_dma) {
+ 				d->init_dma(hwif, dma_base);
+ 			} else {
+-				ide_setup_dma(hwif, dma_base, 8);
++				ide_setup_dma(hwif, dma_base);
+ 			}
+ 		} else {
+ 			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+@@ -535,12 +530,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
  		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
  			continue;
  
@@ -394847,7 +413369,7 @@
  		if (d->init_iops)
  			d->init_iops(hwif);
  
-@@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
+@@ -551,8 +542,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
  		    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
  			hwif->irq = port ? 15 : 14;
  
@@ -394856,7 +413378,7 @@
  		hwif->host_flags = d->host_flags;
  		hwif->pio_mask = d->pio_mask;
  
-@@ -699,105 +698,3 @@ out:
+@@ -699,105 +688,3 @@ out:
  }
  
  EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
@@ -481221,7 +499743,7 @@
  }
  
 diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
-index 4e7b46e..34aebc6 100644
+index 4e7b46e..8b552c6 100644
 --- a/drivers/net/bnx2.c
 +++ b/drivers/net/bnx2.c
 @@ -1,6 +1,6 @@
@@ -481243,8 +499765,8 @@
  #define PFX DRV_MODULE_NAME	": "
 -#define DRV_MODULE_VERSION	"1.6.9"
 -#define DRV_MODULE_RELDATE	"December 8, 2007"
-+#define DRV_MODULE_VERSION	"1.7.2"
-+#define DRV_MODULE_RELDATE	"January 21, 2008"
++#define DRV_MODULE_VERSION	"1.7.3"
++#define DRV_MODULE_RELDATE	"January 29, 2008"
  
  #define RUN_AT(x) (jiffies + (x))
  
@@ -481266,7 +499788,26 @@
  	if (unlikely(diff >= TX_DESC_CNT)) {
  		diff &= 0xffff;
  		if (diff == TX_DESC_CNT)
-@@ -296,7 +296,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
+@@ -266,6 +266,18 @@ bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
+ }
+ 
+ static void
++bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
++{
++	bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
++}
++
++static u32
++bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
++{
++	return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
++}
++
++static void
+ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
+ {
+ 	offset += cid_addr;
+@@ -296,7 +308,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
  	u32 val1;
  	int i, ret;
  
@@ -481275,7 +499816,7 @@
  		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
  		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
  
-@@ -334,7 +334,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
+@@ -334,7 +346,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
  		ret = 0;
  	}
  
@@ -481284,7 +499825,7 @@
  		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
  		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
  
-@@ -353,7 +353,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
+@@ -353,7 +365,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
  	u32 val1;
  	int i, ret;
  
@@ -481293,7 +499834,7 @@
  		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
  		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
  
-@@ -383,7 +383,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
+@@ -383,7 +395,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
  	else
  		ret = 0;
  
@@ -481302,7 +499843,7 @@
  		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
  		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
  
-@@ -399,30 +399,65 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
+@@ -399,30 +411,65 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
  static void
  bnx2_disable_int(struct bnx2 *bp)
  {
@@ -481376,7 +499917,7 @@
  }
  
  static void
-@@ -430,7 +465,7 @@ bnx2_netif_stop(struct bnx2 *bp)
+@@ -430,7 +477,7 @@ bnx2_netif_stop(struct bnx2 *bp)
  {
  	bnx2_disable_int_sync(bp);
  	if (netif_running(bp->dev)) {
@@ -481385,7 +499926,7 @@
  		netif_tx_disable(bp->dev);
  		bp->dev->trans_start = jiffies;	/* prevent tx timeout */
  	}
-@@ -442,7 +477,7 @@ bnx2_netif_start(struct bnx2 *bp)
+@@ -442,7 +489,7 @@ bnx2_netif_start(struct bnx2 *bp)
  	if (atomic_dec_and_test(&bp->intr_sem)) {
  		if (netif_running(bp->dev)) {
  			netif_wake_queue(bp->dev);
@@ -481394,7 +499935,7 @@
  			bnx2_enable_int(bp);
  		}
  	}
-@@ -468,8 +503,7 @@ bnx2_free_mem(struct bnx2 *bp)
+@@ -468,8 +515,7 @@ bnx2_free_mem(struct bnx2 *bp)
  		bp->stats_blk = NULL;
  	}
  	if (bp->tx_desc_ring) {
@@ -481404,7 +499945,7 @@
  				    bp->tx_desc_ring, bp->tx_desc_mapping);
  		bp->tx_desc_ring = NULL;
  	}
-@@ -477,14 +511,23 @@ bnx2_free_mem(struct bnx2 *bp)
+@@ -477,14 +523,23 @@ bnx2_free_mem(struct bnx2 *bp)
  	bp->tx_buf_ring = NULL;
  	for (i = 0; i < bp->rx_max_ring; i++) {
  		if (bp->rx_desc_ring[i])
@@ -481430,7 +499971,7 @@
  }
  
  static int
-@@ -492,38 +535,54 @@ bnx2_alloc_mem(struct bnx2 *bp)
+@@ -492,38 +547,54 @@ bnx2_alloc_mem(struct bnx2 *bp)
  {
  	int i, status_blk_size;
  
@@ -481496,7 +500037,7 @@
  	bp->status_stats_size = status_blk_size +
  				sizeof(struct statistics_block);
  
-@@ -534,6 +593,18 @@ bnx2_alloc_mem(struct bnx2 *bp)
+@@ -534,6 +605,18 @@ bnx2_alloc_mem(struct bnx2 *bp)
  
  	memset(bp->status_blk, 0, bp->status_stats_size);
  
@@ -481515,7 +500056,7 @@
  	bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
  				  status_blk_size);
  
-@@ -563,7 +634,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
+@@ -563,7 +646,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
  {
  	u32 fw_link_status = 0;
  
@@ -481524,7 +500065,7 @@
  		return;
  
  	if (bp->link_up) {
-@@ -605,7 +676,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
+@@ -605,7 +688,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
  			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
  
  			if (!(bmsr & BMSR_ANEGCOMPLETE) ||
@@ -481533,7 +500074,15 @@
  				fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
  			else
  				fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
-@@ -621,7 +692,7 @@ static char *
+@@ -614,14 +697,14 @@ bnx2_report_fw_link(struct bnx2 *bp)
+ 	else
+ 		fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
+ 
+-	REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
++	bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
+ }
+ 
+ static char *
  bnx2_xceiver_str(struct bnx2 *bp)
  {
  	return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
@@ -481542,7 +500091,7 @@
  		 "Copper"));
  }
  
-@@ -681,7 +752,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
+@@ -681,7 +764,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
  		return;
  	}
  
@@ -481551,7 +500100,7 @@
  	    (CHIP_NUM(bp) == CHIP_NUM_5708)) {
  		u32 val;
  
-@@ -696,7 +767,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
+@@ -696,7 +779,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
  	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
  	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
  
@@ -481560,7 +500109,59 @@
  		u32 new_local_adv = 0;
  		u32 new_remote_adv = 0;
  
-@@ -979,7 +1050,7 @@ bnx2_set_mac_link(struct bnx2 *bp)
+@@ -909,6 +992,42 @@ bnx2_copper_linkup(struct bnx2 *bp)
+ 	return 0;
+ }
+ 
++static void
++bnx2_init_rx_context0(struct bnx2 *bp)
++{
++	u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
++
++	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
++	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
++	val |= 0x02 << 8;
++
++	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
++		u32 lo_water, hi_water;
++
++		if (bp->flow_ctrl & FLOW_CTRL_TX)
++			lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
++		else
++			lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
++		if (lo_water >= bp->rx_ring_size)
++			lo_water = 0;
++
++		hi_water = bp->rx_ring_size / 4;
++
++		if (hi_water <= lo_water)
++			lo_water = 0;
++
++		hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
++		lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
++
++		if (hi_water > 0xf)
++			hi_water = 0xf;
++		else if (hi_water == 0)
++			lo_water = 0;
++		val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
++	}
++	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
++}
++
+ static int
+ bnx2_set_mac_link(struct bnx2 *bp)
+ {
+@@ -973,13 +1092,16 @@ bnx2_set_mac_link(struct bnx2 *bp)
+ 	/* Acknowledge the interrupt. */
+ 	REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
+ 
++	if (CHIP_NUM(bp) == CHIP_NUM_5709)
++		bnx2_init_rx_context0(bp);
++
+ 	return 0;
+ }
+ 
  static void
  bnx2_enable_bmsr1(struct bnx2 *bp)
  {
@@ -481569,7 +500170,7 @@
  	    (CHIP_NUM(bp) == CHIP_NUM_5709))
  		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
  			       MII_BNX2_BLK_ADDR_GP_STATUS);
-@@ -988,7 +1059,7 @@ bnx2_enable_bmsr1(struct bnx2 *bp)
+@@ -988,7 +1110,7 @@ bnx2_enable_bmsr1(struct bnx2 *bp)
  static void
  bnx2_disable_bmsr1(struct bnx2 *bp)
  {
@@ -481578,7 +500179,7 @@
  	    (CHIP_NUM(bp) == CHIP_NUM_5709))
  		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
  			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
-@@ -1000,7 +1071,7 @@ bnx2_test_and_enable_2g5(struct bnx2 *bp)
+@@ -1000,7 +1122,7 @@ bnx2_test_and_enable_2g5(struct bnx2 *bp)
  	u32 up1;
  	int ret = 1;
  
@@ -481587,7 +500188,7 @@
  		return 0;
  
  	if (bp->autoneg & AUTONEG_SPEED)
-@@ -1029,7 +1100,7 @@ bnx2_test_and_disable_2g5(struct bnx2 *bp)
+@@ -1029,7 +1151,7 @@ bnx2_test_and_disable_2g5(struct bnx2 *bp)
  	u32 up1;
  	int ret = 0;
  
@@ -481596,7 +500197,7 @@
  		return 0;
  
  	if (CHIP_NUM(bp) == CHIP_NUM_5709)
-@@ -1054,7 +1125,7 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
+@@ -1054,7 +1176,7 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
  {
  	u32 bmcr;
  
@@ -481605,7 +500206,7 @@
  		return;
  
  	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
-@@ -1089,7 +1160,7 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
+@@ -1089,7 +1211,7 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
  {
  	u32 bmcr;
  
@@ -481614,7 +500215,7 @@
  		return;
  
  	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
-@@ -1115,6 +1186,19 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
+@@ -1115,6 +1237,19 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
  	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
  }
  
@@ -481634,7 +500235,7 @@
  static int
  bnx2_set_link(struct bnx2 *bp)
  {
-@@ -1126,7 +1210,7 @@ bnx2_set_link(struct bnx2 *bp)
+@@ -1126,7 +1261,7 @@ bnx2_set_link(struct bnx2 *bp)
  		return 0;
  	}
  
@@ -481643,7 +500244,7 @@
  		return 0;
  
  	link_up = bp->link_up;
-@@ -1136,10 +1220,14 @@ bnx2_set_link(struct bnx2 *bp)
+@@ -1136,10 +1271,14 @@ bnx2_set_link(struct bnx2 *bp)
  	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
  	bnx2_disable_bmsr1(bp);
  
@@ -481659,7 +500260,7 @@
  		val = REG_RD(bp, BNX2_EMAC_STATUS);
  		if (val & BNX2_EMAC_STATUS_LINK)
  			bmsr |= BMSR_LSTATUS;
-@@ -1150,7 +1238,7 @@ bnx2_set_link(struct bnx2 *bp)
+@@ -1150,7 +1289,7 @@ bnx2_set_link(struct bnx2 *bp)
  	if (bmsr & BMSR_LSTATUS) {
  		bp->link_up = 1;
  
@@ -481668,7 +500269,7 @@
  			if (CHIP_NUM(bp) == CHIP_NUM_5706)
  				bnx2_5706s_linkup(bp);
  			else if (CHIP_NUM(bp) == CHIP_NUM_5708)
-@@ -1164,11 +1252,19 @@ bnx2_set_link(struct bnx2 *bp)
+@@ -1164,11 +1303,19 @@ bnx2_set_link(struct bnx2 *bp)
  		bnx2_resolve_flow_ctrl(bp);
  	}
  	else {
@@ -481690,7 +500291,7 @@
  		bp->link_up = 0;
  	}
  
-@@ -1213,7 +1309,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
+@@ -1213,7 +1360,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
  	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
  		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {
  
@@ -481699,7 +500300,7 @@
  			adv = ADVERTISE_1000XPAUSE;
  		}
  		else {
-@@ -1221,7 +1317,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
+@@ -1221,7 +1368,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
  		}
  	}
  	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
@@ -481708,7 +500309,7 @@
  			adv = ADVERTISE_1000XPSE_ASYM;
  		}
  		else {
-@@ -1229,7 +1325,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
+@@ -1229,7 +1376,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
  		}
  	}
  	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
@@ -481717,7 +500318,24 @@
  			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
  		}
  		else {
-@@ -1304,7 +1400,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
+@@ -1282,14 +1429,14 @@ bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
+ 
+ 	if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
+ 		speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
+-	if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
++	if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
+ 		speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
+ 
+ 	if (port == PORT_TP)
+ 		speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
+ 			     BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
+ 
+-	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
++	bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
+ 
+ 	spin_unlock_bh(&bp->phy_lock);
+ 	bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
+@@ -1304,7 +1451,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
  	u32 adv, bmcr;
  	u32 new_adv = 0;
  
@@ -481726,7 +500344,7 @@
  		return (bnx2_setup_remote_phy(bp, port));
  
  	if (!(bp->autoneg & AUTONEG_SPEED)) {
-@@ -1414,7 +1510,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
+@@ -1414,7 +1561,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
  }
  
  #define ETHTOOL_ALL_FIBRE_SPEED						\
@@ -481735,7 +500353,19 @@
  		(ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
  		(ADVERTISED_1000baseT_Full)
  
-@@ -1478,12 +1574,12 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
+@@ -1434,9 +1581,9 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
+ 	u32 link;
+ 
+ 	if (bp->phy_port == PORT_TP)
+-		link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
++		link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
+ 	else
+-		link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
++		link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
+ 
+ 	if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
+ 		bp->req_line_speed = 0;
+@@ -1478,17 +1625,17 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
  static void
  bnx2_set_default_link(struct bnx2 *bp)
  {
@@ -481750,7 +500380,31 @@
  		u32 reg;
  
  		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
-@@ -1713,7 +1809,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port)
+ 
+-		reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
++		reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
+ 		reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
+ 		if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
+ 			bp->autoneg = 0;
+@@ -1520,7 +1667,7 @@ bnx2_remote_phy_event(struct bnx2 *bp)
+ 	u8 link_up = bp->link_up;
+ 	u8 old_port;
+ 
+-	msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
++	msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
+ 
+ 	if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
+ 		bnx2_send_heart_beat(bp);
+@@ -1597,7 +1744,7 @@ bnx2_set_remote_link(struct bnx2 *bp)
+ {
+ 	u32 evt_code;
+ 
+-	evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
++	evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
+ 	switch (evt_code) {
+ 		case BNX2_FW_EVT_CODE_LINK_EVENT:
+ 			bnx2_remote_phy_event(bp);
+@@ -1713,7 +1860,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port)
  	if (bp->loopback == MAC_LOOPBACK)
  		return 0;
  
@@ -481759,7 +500413,7 @@
  		return (bnx2_setup_serdes_phy(bp, port));
  	}
  	else {
-@@ -1748,7 +1844,7 @@ bnx2_init_5709s_phy(struct bnx2 *bp)
+@@ -1748,7 +1895,7 @@ bnx2_init_5709s_phy(struct bnx2 *bp)
  
  	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
  	bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
@@ -481768,7 +500422,7 @@
  		val |= BCM5708S_UP1_2G5;
  	else
  		val &= ~BCM5708S_UP1_2G5;
-@@ -1791,7 +1887,7 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
+@@ -1791,7 +1938,7 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
  	val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
  	bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
  
@@ -481777,7 +500431,24 @@
  		bnx2_read_phy(bp, BCM5708S_UP1, &val);
  		val |= BCM5708S_UP1_2G5;
  		bnx2_write_phy(bp, BCM5708S_UP1, val);
-@@ -1833,7 +1929,7 @@ bnx2_init_5706s_phy(struct bnx2 *bp)
+@@ -1809,14 +1956,13 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
+ 		bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
+ 	}
+ 
+-	val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
++	val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
+ 	      BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
+ 
+ 	if (val) {
+ 		u32 is_backplane;
+ 
+-		is_backplane = REG_RD_IND(bp, bp->shmem_base +
+-					  BNX2_SHARED_HW_CFG_CONFIG);
++		is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
+ 		if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
+ 			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
+ 				       BCM5708S_BLK_ADDR_TX_MISC);
+@@ -1833,7 +1979,7 @@ bnx2_init_5706s_phy(struct bnx2 *bp)
  {
  	bnx2_reset_phy(bp);
  
@@ -481786,7 +500457,7 @@
  
  	if (CHIP_NUM(bp) == CHIP_NUM_5706)
          	REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
-@@ -1872,7 +1968,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
+@@ -1872,7 +2018,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
  
  	bnx2_reset_phy(bp);
  
@@ -481795,7 +500466,7 @@
  		bnx2_write_phy(bp, 0x18, 0x0c00);
  		bnx2_write_phy(bp, 0x17, 0x000a);
  		bnx2_write_phy(bp, 0x15, 0x310b);
-@@ -1883,7 +1979,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
+@@ -1883,7 +2029,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
  		bnx2_write_phy(bp, 0x18, 0x0400);
  	}
  
@@ -481804,7 +500475,7 @@
  		bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
  			       MII_BNX2_DSP_EXPAND_REG | 0x8);
  		bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
-@@ -1923,8 +2019,8 @@ bnx2_init_phy(struct bnx2 *bp)
+@@ -1923,8 +2069,8 @@ bnx2_init_phy(struct bnx2 *bp)
  	u32 val;
  	int rc = 0;
  
@@ -481815,7 +500486,7 @@
  
  	bp->mii_bmcr = MII_BMCR;
  	bp->mii_bmsr = MII_BMSR;
-@@ -1934,7 +2030,7 @@ bnx2_init_phy(struct bnx2 *bp)
+@@ -1934,7 +2080,7 @@ bnx2_init_phy(struct bnx2 *bp)
  
          REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
  
@@ -481824,7 +500495,7 @@
  		goto setup_phy;
  
  	bnx2_read_phy(bp, MII_PHYSID1, &val);
-@@ -1942,7 +2038,7 @@ bnx2_init_phy(struct bnx2 *bp)
+@@ -1942,7 +2088,7 @@ bnx2_init_phy(struct bnx2 *bp)
  	bnx2_read_phy(bp, MII_PHYSID2, &val);
  	bp->phy_id |= val & 0xffff;
  
@@ -481833,7 +500504,32 @@
  		if (CHIP_NUM(bp) == CHIP_NUM_5706)
  			rc = bnx2_init_5706s_phy(bp);
  		else if (CHIP_NUM(bp) == CHIP_NUM_5708)
-@@ -2125,15 +2221,12 @@ bnx2_init_context(struct bnx2 *bp)
+@@ -2015,13 +2161,13 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
+ 	bp->fw_wr_seq++;
+ 	msg_data |= bp->fw_wr_seq;
+ 
+-	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
++	bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
+ 
+ 	/* wait for an acknowledgement. */
+ 	for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
+ 		msleep(10);
+ 
+-		val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
++		val = bnx2_shmem_rd(bp, BNX2_FW_MB);
+ 
+ 		if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
+ 			break;
+@@ -2038,7 +2184,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
+ 		msg_data &= ~BNX2_DRV_MSG_CODE;
+ 		msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
+ 
+-		REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
++		bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
+ 
+ 		return -EBUSY;
+ 	}
+@@ -2125,15 +2271,12 @@ bnx2_init_context(struct bnx2 *bp)
  			vcid_addr += (i << PHY_CTX_SHIFT);
  			pcid_addr += (i << PHY_CTX_SHIFT);
  
@@ -481847,11 +500543,45 @@
 -
 -			REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
 -			REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
-+				CTX_WR(bp, vcid_addr, offset, 0);
++				bnx2_ctx_wr(bp, vcid_addr, offset, 0);
  		}
  	}
  }
-@@ -2206,7 +2299,43 @@ bnx2_set_mac_addr(struct bnx2 *bp)
+@@ -2158,11 +2301,12 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+ 	good_mbuf_cnt = 0;
+ 
+ 	/* Allocate a bunch of mbufs and save the good ones in an array. */
+-	val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
++	val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
+ 	while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
+-		REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
++		bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
++				BNX2_RBUF_COMMAND_ALLOC_REQ);
+ 
+-		val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
++		val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
+ 
+ 		val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
+ 
+@@ -2172,7 +2316,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+ 			good_mbuf_cnt++;
+ 		}
+ 
+-		val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
++		val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
+ 	}
+ 
+ 	/* Free the good ones back to the mbuf pool thus discarding
+@@ -2183,7 +2327,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
+ 		val = good_mbuf[good_mbuf_cnt];
+ 		val = (val << 9) | val | 1;
+ 
+-		REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
++		bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
+ 	}
+ 	kfree(good_mbuf);
+ 	return 0;
+@@ -2206,7 +2350,43 @@ bnx2_set_mac_addr(struct bnx2 *bp)
  }
  
  static inline int
@@ -481896,7 +500626,7 @@
  {
  	struct sk_buff *skb;
  	struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
-@@ -2231,15 +2360,15 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
+@@ -2231,15 +2411,15 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
  	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
  	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
  
@@ -481915,7 +500645,7 @@
  	u32 new_link_state, old_link_state;
  	int is_set = 1;
  
-@@ -2257,30 +2386,41 @@ bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
+@@ -2257,30 +2437,41 @@ bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
  }
  
  static void
@@ -481969,7 +500699,7 @@
  
  	while (sw_cons != hw_cons) {
  		struct sw_bd *tx_buf;
-@@ -2327,19 +2467,16 @@ bnx2_tx_int(struct bnx2 *bp)
+@@ -2327,19 +2518,16 @@ bnx2_tx_int(struct bnx2 *bp)
  
  		sw_cons = NEXT_TX_BD(sw_cons);
  
@@ -481995,7 +500725,7 @@
  	/* Need to make the tx_cons update visible to bnx2_start_xmit()
  	 * before checking for netif_queue_stopped().  Without the
  	 * memory barrier, there is a small possibility that bnx2_start_xmit()
-@@ -2348,17 +2485,68 @@ bnx2_tx_int(struct bnx2 *bp)
+@@ -2348,17 +2536,68 @@ bnx2_tx_int(struct bnx2 *bp)
  	smp_mb();
  
  	if (unlikely(netif_queue_stopped(bp->dev)) &&
@@ -482067,7 +500797,7 @@
  	u16 cons, u16 prod)
  {
  	struct sw_bd *cons_rx_buf, *prod_rx_buf;
-@@ -2371,7 +2559,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
+@@ -2371,7 +2610,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
  		pci_unmap_addr(cons_rx_buf, mapping),
  		bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
  
@@ -482076,7 +500806,7 @@
  
  	prod_rx_buf->skb = skb;
  
-@@ -2387,10 +2575,102 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
+@@ -2387,10 +2626,102 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
  	prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
  }
  
@@ -482181,7 +500911,7 @@
  
  	if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
  		cons++;
-@@ -2398,22 +2678,22 @@ bnx2_get_hw_rx_cons(struct bnx2 *bp)
+@@ -2398,22 +2729,22 @@ bnx2_get_hw_rx_cons(struct bnx2 *bp)
  }
  
  static int
@@ -482210,7 +500940,7 @@
  		u32 status;
  		struct sw_bd *rx_buf;
  		struct sk_buff *skb;
-@@ -2433,7 +2713,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
+@@ -2433,7 +2764,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
  			bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
  
  		rx_hdr = (struct l2_fhdr *) skb->data;
@@ -482219,7 +500949,7 @@
  
  		if ((status = rx_hdr->l2_fhdr_status) &
  			(L2_FHDR_ERRORS_BAD_CRC |
-@@ -2442,18 +2722,30 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
+@@ -2442,18 +2773,30 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
  			L2_FHDR_ERRORS_TOO_SHORT |
  			L2_FHDR_ERRORS_GIANT_FRAME)) {
  
@@ -482257,7 +500987,7 @@
  
  			/* aligned copy */
  			skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
-@@ -2461,24 +2753,13 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
+@@ -2461,24 +2804,13 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
  			skb_reserve(new_skb, 2);
  			skb_put(new_skb, len);
  
@@ -482285,7 +501015,7 @@
  
  		skb->protocol = eth_type_trans(skb, bp->dev);
  
-@@ -2501,7 +2782,7 @@ reuse_rx:
+@@ -2501,7 +2833,7 @@ reuse_rx:
  		}
  
  #ifdef BCM_VLAN
@@ -482294,7 +501024,7 @@
  			vlan_hwaccel_receive_skb(skb, bp->vlgrp,
  				rx_hdr->l2_fhdr_vlan_tag);
  		}
-@@ -2521,16 +2802,20 @@ next_rx:
+@@ -2521,16 +2853,20 @@ next_rx:
  
  		/* Refresh hw_cons to see if there is new work */
  		if (sw_cons == hw_cons) {
@@ -482319,7 +501049,7 @@
  
  	mmiowb();
  
-@@ -2546,8 +2831,9 @@ bnx2_msi(int irq, void *dev_instance)
+@@ -2546,8 +2882,9 @@ bnx2_msi(int irq, void *dev_instance)
  {
  	struct net_device *dev = dev_instance;
  	struct bnx2 *bp = netdev_priv(dev);
@@ -482330,7 +501060,7 @@
  	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
  		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
  		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
-@@ -2556,7 +2842,7 @@ bnx2_msi(int irq, void *dev_instance)
+@@ -2556,7 +2893,7 @@ bnx2_msi(int irq, void *dev_instance)
  	if (unlikely(atomic_read(&bp->intr_sem) != 0))
  		return IRQ_HANDLED;
  
@@ -482339,7 +501069,7 @@
  
  	return IRQ_HANDLED;
  }
-@@ -2566,14 +2852,15 @@ bnx2_msi_1shot(int irq, void *dev_instance)
+@@ -2566,14 +2903,15 @@ bnx2_msi_1shot(int irq, void *dev_instance)
  {
  	struct net_device *dev = dev_instance;
  	struct bnx2 *bp = netdev_priv(dev);
@@ -482357,7 +501087,7 @@
  
  	return IRQ_HANDLED;
  }
-@@ -2583,7 +2870,8 @@ bnx2_interrupt(int irq, void *dev_instance)
+@@ -2583,7 +2921,8 @@ bnx2_interrupt(int irq, void *dev_instance)
  {
  	struct net_device *dev = dev_instance;
  	struct bnx2 *bp = netdev_priv(dev);
@@ -482367,7 +501097,7 @@
  
  	/* When using INTx, it is possible for the interrupt to arrive
  	 * at the CPU before the status block posted prior to the
-@@ -2591,7 +2879,7 @@ bnx2_interrupt(int irq, void *dev_instance)
+@@ -2591,7 +2930,7 @@ bnx2_interrupt(int irq, void *dev_instance)
  	 * When using MSI, the MSI message will always complete after
  	 * the status block write.
  	 */
@@ -482376,7 +501106,7 @@
  	    (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
  	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
  		return IRQ_NONE;
-@@ -2609,24 +2897,41 @@ bnx2_interrupt(int irq, void *dev_instance)
+@@ -2609,24 +2948,41 @@ bnx2_interrupt(int irq, void *dev_instance)
  	if (unlikely(atomic_read(&bp->intr_sem) != 0))
  		return IRQ_HANDLED;
  
@@ -482425,13 +501155,14 @@
  		return 1;
  
  	if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
-@@ -2636,16 +2941,40 @@ bnx2_has_work(struct bnx2 *bp)
+@@ -2636,16 +2992,40 @@ bnx2_has_work(struct bnx2 *bp)
  	return 0;
  }
  
 -static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
 +static int bnx2_tx_poll(struct napi_struct *napi, int budget)
-+{
+ {
+-	struct status_block *sblk = bp->status_blk;
 +	struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
 +	struct bnx2 *bp = bnapi->bp;
 +	int work_done = 0;
@@ -482455,8 +501186,7 @@
 +
 +static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
 +			  int work_done, int budget)
- {
--	struct status_block *sblk = bp->status_blk;
++{
 +	struct status_block *sblk = bnapi->status_blk;
  	u32 status_attn_bits = sblk->status_attn_bits;
  	u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
@@ -482469,7 +501199,7 @@
  
  		/* This is needed to take care of transient status
  		 * during link changes.
-@@ -2655,49 +2984,50 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
+@@ -2655,49 +3035,50 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
  		REG_RD(bp, BNX2_HC_COMMAND);
  	}
  
@@ -482534,7 +501264,7 @@
  			break;
  		}
  	}
-@@ -2721,10 +3051,10 @@ bnx2_set_rx_mode(struct net_device *dev)
+@@ -2721,10 +3102,10 @@ bnx2_set_rx_mode(struct net_device *dev)
  				  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
  	sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
  #ifdef BCM_VLAN
@@ -482547,7 +501277,7 @@
  		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
  #endif
  	if (dev->flags & IFF_PROMISC) {
-@@ -2781,7 +3111,7 @@ bnx2_set_rx_mode(struct net_device *dev)
+@@ -2781,7 +3162,7 @@ bnx2_set_rx_mode(struct net_device *dev)
  }
  
  static void
@@ -482556,7 +501286,7 @@
  	u32 rv2p_proc)
  {
  	int i;
-@@ -2789,9 +3119,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
+@@ -2789,9 +3170,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
  
  
  	for (i = 0; i < rv2p_code_len; i += 8) {
@@ -482568,16 +501298,83 @@
  		rv2p_code++;
  
  		if (rv2p_proc == RV2P_PROC1) {
-@@ -2837,7 +3167,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+@@ -2821,10 +3202,10 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+ 	int rc;
+ 
+ 	/* Halt the CPU. */
+-	val = REG_RD_IND(bp, cpu_reg->mode);
++	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
+ 	val |= cpu_reg->mode_value_halt;
+-	REG_WR_IND(bp, cpu_reg->mode, val);
+-	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
++	bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
++	bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
+ 
+ 	/* Load the Text area. */
+ 	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
+@@ -2837,7 +3218,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
  			return rc;
  
  		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
 -			REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
-+			REG_WR_IND(bp, offset, le32_to_cpu(fw->text[j]));
++			bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j]));
  	        }
  	}
  
-@@ -2900,20 +3230,34 @@ bnx2_init_cpus(struct bnx2 *bp)
+@@ -2847,7 +3228,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+ 		int j;
+ 
+ 		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
+-			REG_WR_IND(bp, offset, fw->data[j]);
++			bnx2_reg_wr_ind(bp, offset, fw->data[j]);
+ 		}
+ 	}
+ 
+@@ -2857,7 +3238,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+ 		int j;
+ 
+ 		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
+-			REG_WR_IND(bp, offset, 0);
++			bnx2_reg_wr_ind(bp, offset, 0);
+ 		}
+ 	}
+ 
+@@ -2867,7 +3248,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+ 		int j;
+ 
+ 		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
+-			REG_WR_IND(bp, offset, 0);
++			bnx2_reg_wr_ind(bp, offset, 0);
+ 		}
+ 	}
+ 
+@@ -2878,19 +3259,19 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+ 		int j;
+ 
+ 		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
+-			REG_WR_IND(bp, offset, fw->rodata[j]);
++			bnx2_reg_wr_ind(bp, offset, fw->rodata[j]);
+ 		}
+ 	}
+ 
+ 	/* Clear the pre-fetch instruction. */
+-	REG_WR_IND(bp, cpu_reg->inst, 0);
+-	REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
++	bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
++	bnx2_reg_wr_ind(bp, cpu_reg->pc, fw->start_addr);
+ 
+ 	/* Start the CPU. */
+-	val = REG_RD_IND(bp, cpu_reg->mode);
++	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
+ 	val &= ~cpu_reg->mode_value_halt;
+-	REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+-	REG_WR_IND(bp, cpu_reg->mode, val);
++	bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
++	bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
+ 
+ 	return 0;
+ }
+@@ -2900,20 +3281,34 @@ bnx2_init_cpus(struct bnx2 *bp)
  {
  	struct cpu_reg cpu_reg;
  	struct fw_info *fw;
@@ -482616,7 +501413,7 @@
  	if (rc < 0)
  		goto init_cpu_err;
  
-@@ -3029,14 +3373,14 @@ bnx2_init_cpus(struct bnx2 *bp)
+@@ -3029,14 +3424,14 @@ bnx2_init_cpus(struct bnx2 *bp)
  	cpu_reg.spad_base = BNX2_CP_SCRATCH;
  	cpu_reg.mips_view_base = 0x8000000;
  
@@ -482637,7 +501434,7 @@
  init_cpu_err:
  	vfree(text);
  	return rc;
-@@ -3148,7 +3492,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
+@@ -3148,7 +3543,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
  			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
  		}
  
@@ -482646,7 +501443,7 @@
  			bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
  
  		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-@@ -3360,10 +3704,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
+@@ -3360,10 +3755,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
  
  		val = REG_RD(bp, BNX2_NVM_COMMAND);
  		if (val & BNX2_NVM_COMMAND_DONE) {
@@ -482659,7 +501456,7 @@
  			break;
  		}
  	}
-@@ -3377,7 +3719,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
+@@ -3377,7 +3770,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
  static int
  bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
  {
@@ -482669,7 +501466,7 @@
  	int j;
  
  	/* Build the command word. */
-@@ -3394,10 +3737,9 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
+@@ -3394,10 +3788,9 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
  	REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
  
  	memcpy(&val32, val, 4);
@@ -482681,7 +501478,16 @@
  
  	/* Address of the NVRAM to write to. */
  	REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
-@@ -3796,8 +4138,8 @@ bnx2_init_remote_phy(struct bnx2 *bp)
+@@ -3491,7 +3884,7 @@ bnx2_init_nvram(struct bnx2 *bp)
+ 	}
+ 
+ get_flash_size:
+-	val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
++	val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
+ 	val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
+ 	if (val)
+ 		bp->flash_size = val;
+@@ -3796,18 +4189,18 @@ bnx2_init_remote_phy(struct bnx2 *bp)
  {
  	u32 val;
  
@@ -482691,17 +501497,28 @@
 +	if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
  		return;
  
- 	val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
-@@ -3805,7 +4147,7 @@ bnx2_init_remote_phy(struct bnx2 *bp)
+-	val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
++	val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
+ 	if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
  		return;
  
  	if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
 -		bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
 +		bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
  
- 		val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+-		val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
++		val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
  		if (val & BNX2_LINK_STATUS_SERDES_LINK)
-@@ -3831,6 +4173,15 @@ bnx2_init_remote_phy(struct bnx2 *bp)
+ 			bp->phy_port = PORT_FIBRE;
+ 		else
+@@ -3825,12 +4218,20 @@ bnx2_init_remote_phy(struct bnx2 *bp)
+ 			}
+ 			sig = BNX2_DRV_ACK_CAP_SIGNATURE |
+ 			      BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
+-			REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+-				   sig);
++			bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
+ 		}
  	}
  }
  
@@ -482717,7 +501534,18 @@
  static int
  bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
  {
-@@ -3917,7 +4268,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+@@ -3853,8 +4254,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+ 
+ 	/* Deposit a driver reset signature so the firmware knows that
+ 	 * this is a soft reset. */
+-	REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
+-		   BNX2_DRV_RESET_SIGNATURE_MAGIC);
++	bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
++		      BNX2_DRV_RESET_SIGNATURE_MAGIC);
+ 
+ 	/* Do a dummy read to force the chip to complete all current transaction
+ 	 * before we issue a reset. */
+@@ -3917,7 +4318,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
  	spin_lock_bh(&bp->phy_lock);
  	old_port = bp->phy_port;
  	bnx2_init_remote_phy(bp);
@@ -482727,7 +501555,7 @@
  		bnx2_set_default_remote_link(bp);
  	spin_unlock_bh(&bp->phy_lock);
  
-@@ -3930,6 +4282,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
+@@ -3930,6 +4332,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
  		rc = bnx2_alloc_bad_rbuf(bp);
  	}
  
@@ -482737,7 +501565,7 @@
  	return rc;
  }
  
-@@ -3937,7 +4292,7 @@ static int
+@@ -3937,7 +4342,7 @@ static int
  bnx2_init_chip(struct bnx2 *bp)
  {
  	u32 val;
@@ -482746,7 +501574,7 @@
  
  	/* Make sure the interrupt is not active. */
  	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
-@@ -3953,11 +4308,11 @@ bnx2_init_chip(struct bnx2 *bp)
+@@ -3953,11 +4358,11 @@ bnx2_init_chip(struct bnx2 *bp)
  
  	val |= (0x2 << 20) | (1 << 11);
  
@@ -482760,7 +501588,7 @@
  		val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
  
  	REG_WR(bp, BNX2_DMA_CONFIG, val);
-@@ -3968,7 +4323,7 @@ bnx2_init_chip(struct bnx2 *bp)
+@@ -3968,7 +4373,7 @@ bnx2_init_chip(struct bnx2 *bp)
  		REG_WR(bp, BNX2_TDMA_CONFIG, val);
  	}
  
@@ -482769,7 +501597,7 @@
  		u16 val16;
  
  		pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
-@@ -4033,7 +4388,9 @@ bnx2_init_chip(struct bnx2 *bp)
+@@ -4033,7 +4438,9 @@ bnx2_init_chip(struct bnx2 *bp)
  		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
  	REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
  
@@ -482780,24 +501608,27 @@
  	bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
  
  	/* Set up how to generate a link change interrupt. */
-@@ -4080,7 +4437,25 @@ bnx2_init_chip(struct bnx2 *bp)
+@@ -4080,7 +4487,28 @@ bnx2_init_chip(struct bnx2 *bp)
  		      BNX2_HC_CONFIG_COLLECT_STATS;
  	}
  
 -	if (bp->flags & ONE_SHOT_MSI_FLAG)
 +	if (bp->flags & BNX2_FLAG_USING_MSIX) {
++		u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
++			   BNX2_HC_SB_CONFIG_1;
++
 +		REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
 +		       BNX2_HC_MSIX_BIT_VECTOR_VAL);
 +
-+		REG_WR(bp, BNX2_HC_SB_CONFIG_1,
++		REG_WR(bp, base,
 +			BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
 +			BNX2_HC_SB_CONFIG_1_ONE_SHOT);
 +
-+		REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP_1,
++		REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
 +			(bp->tx_quick_cons_trip_int << 16) |
 +			 bp->tx_quick_cons_trip);
 +
-+		REG_WR(bp, BNX2_HC_TX_TICKS_1,
++		REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
 +			(bp->tx_ticks_int << 16) | bp->tx_ticks);
 +
 +		val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
@@ -482807,7 +501638,7 @@
  		val |= BNX2_HC_CONFIG_ONE_SHOT;
  
  	REG_WR(bp, BNX2_HC_CONFIG, val);
-@@ -4112,6 +4487,25 @@ bnx2_init_chip(struct bnx2 *bp)
+@@ -4112,9 +4540,29 @@ bnx2_init_chip(struct bnx2 *bp)
  }
  
  static void
@@ -482833,7 +501664,31 @@
  bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
  {
  	u32 val, offset0, offset1, offset2, offset3;
-@@ -4144,7 +4538,17 @@ static void
++	u32 cid_addr = GET_CID_ADDR(cid);
+ 
+ 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ 		offset0 = BNX2_L2CTX_TYPE_XI;
+@@ -4128,23 +4576,33 @@ bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
+ 		offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
+ 	}
+ 	val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
+-	CTX_WR(bp, GET_CID_ADDR(cid), offset0, val);
++	bnx2_ctx_wr(bp, cid_addr, offset0, val);
+ 
+ 	val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
+-	CTX_WR(bp, GET_CID_ADDR(cid), offset1, val);
++	bnx2_ctx_wr(bp, cid_addr, offset1, val);
+ 
+ 	val = (u64) bp->tx_desc_mapping >> 32;
+-	CTX_WR(bp, GET_CID_ADDR(cid), offset2, val);
++	bnx2_ctx_wr(bp, cid_addr, offset2, val);
+ 
+ 	val = (u64) bp->tx_desc_mapping & 0xffffffff;
+-	CTX_WR(bp, GET_CID_ADDR(cid), offset3, val);
++	bnx2_ctx_wr(bp, cid_addr, offset3, val);
+ }
+ 
+ static void
  bnx2_init_tx_ring(struct bnx2 *bp)
  {
  	struct tx_bd *txbd;
@@ -482852,7 +501707,7 @@
  
  	bp->tx_wake_thresh = bp->tx_ring_size / 2;
  
-@@ -4154,11 +4558,8 @@ bnx2_init_tx_ring(struct bnx2 *bp)
+@@ -4154,11 +4612,8 @@ bnx2_init_tx_ring(struct bnx2 *bp)
  	txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
  
  	bp->tx_prod = 0;
@@ -482864,7 +501719,7 @@
  	bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
  	bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
  
-@@ -4166,84 +4567,152 @@ bnx2_init_tx_ring(struct bnx2 *bp)
+@@ -4166,84 +4621,154 @@ bnx2_init_tx_ring(struct bnx2 *bp)
  }
  
  static void
@@ -482908,9 +501763,13 @@
 -				       0xffffffff;
 +		rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
 +		rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
-+	}
+ 	}
 +}
-+
+ 
+-	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
+-	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
+-	val |= 0x02 << 8;
+-	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
 +static void
 +bnx2_init_rx_ring(struct bnx2 *bp)
 +{
@@ -482922,39 +501781,40 @@
 +	bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
 +			     bp->rx_buf_use_size, bp->rx_max_ring);
 +
-+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
++	bnx2_init_rx_context0(bp);
++
++	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
++		val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
++		REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
++	}
++
++	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
 +	if (bp->rx_pg_ring_size) {
 +		bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
 +				     bp->rx_pg_desc_mapping,
 +				     PAGE_SIZE, bp->rx_max_pg_ring);
 +		val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
-+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
-+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
++		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
++		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
 +		       BNX2_L2CTX_RBDC_JUMBO_KEY);
 +
 +		val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
-+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
++		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
 +
 +		val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
-+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
++		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
 +
 +		if (CHIP_NUM(bp) == CHIP_NUM_5709)
 +			REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
- 	}
- 
- 	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
- 	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
- 	val |= 0x02 << 8;
--	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
-+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
++	}
  
  	val = (u64) bp->rx_desc_mapping[0] >> 32;
 -	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
-+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
++	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
  
  	val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
 -	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
-+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
++	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
  
 +	ring_prod = prod = bnapi->rx_pg_prod;
 +	for (i = 0; i < bp->rx_pg_ring_size; i++) {
@@ -483052,7 +501912,7 @@
  	bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
  }
  
-@@ -4306,6 +4775,8 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
+@@ -4306,6 +4831,8 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
  
  		dev_kfree_skb(skb);
  	}
@@ -483061,7 +501921,7 @@
  }
  
  static void
-@@ -4328,6 +4799,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
+@@ -4328,6 +4855,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
  	if ((rc = bnx2_init_chip(bp)) != 0)
  		return rc;
  
@@ -483069,7 +501929,19 @@
  	bnx2_init_tx_ring(bp);
  	bnx2_init_rx_ring(bp);
  	return 0;
-@@ -4599,13 +5071,18 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
+@@ -4531,9 +5059,9 @@ bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
+ 
+ 		for (offset = 0; offset < size; offset += 4) {
+ 
+-			REG_WR_IND(bp, start + offset, test_pattern[i]);
++			bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
+ 
+-			if (REG_RD_IND(bp, start + offset) !=
++			if (bnx2_reg_rd_ind(bp, start + offset) !=
+ 				test_pattern[i]) {
+ 				return -ENODEV;
+ 			}
+@@ -4599,13 +5127,18 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
  	struct sw_bd *rx_buf;
  	struct l2_fhdr *rx_hdr;
  	int ret = -ENODEV;
@@ -483089,7 +501961,7 @@
  			return 0;
  
  		bp->loopback = PHY_LOOPBACK;
-@@ -4614,7 +5091,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
+@@ -4614,7 +5147,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
  	else
  		return -EINVAL;
  
@@ -483098,7 +501970,7 @@
  	skb = netdev_alloc_skb(bp->dev, pkt_size);
  	if (!skb)
  		return -ENOMEM;
-@@ -4633,7 +5110,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
+@@ -4633,7 +5166,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
  	REG_RD(bp, BNX2_HC_COMMAND);
  
  	udelay(5);
@@ -483107,7 +501979,7 @@
  
  	num_pkts = 0;
  
-@@ -4663,11 +5140,10 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
+@@ -4663,11 +5196,10 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
  	pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
  	dev_kfree_skb(skb);
  
@@ -483121,7 +501993,7 @@
  	if (rx_idx != rx_start_idx + num_pkts) {
  		goto loopback_test_done;
  	}
-@@ -4739,7 +5215,7 @@ bnx2_test_loopback(struct bnx2 *bp)
+@@ -4739,7 +5271,7 @@ bnx2_test_loopback(struct bnx2 *bp)
  static int
  bnx2_test_nvram(struct bnx2 *bp)
  {
@@ -483130,7 +502002,7 @@
  	u8 *data = (u8 *) buf;
  	int rc = 0;
  	u32 magic, csum;
-@@ -4776,7 +5252,7 @@ bnx2_test_link(struct bnx2 *bp)
+@@ -4776,7 +5308,7 @@ bnx2_test_link(struct bnx2 *bp)
  {
  	u32 bmsr;
  
@@ -483139,7 +502011,7 @@
  		if (bp->link_up)
  			return 0;
  		return -ENODEV;
-@@ -4824,13 +5300,51 @@ bnx2_test_intr(struct bnx2 *bp)
+@@ -4824,13 +5356,51 @@ bnx2_test_intr(struct bnx2 *bp)
  	return -ENODEV;
  }
  
@@ -483158,7 +502030,7 @@
 +	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
 +	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
 +
-+	if (an_dbg & MISC_SHDW_AN_DBG_NOSYNC)
++	if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
 +		return 0;
 +
 +	bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
@@ -483193,7 +502065,7 @@
  		u32 bmcr;
  
  		bp->current_interval = bp->timer_interval;
-@@ -4838,30 +5352,19 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
+@@ -4838,30 +5408,19 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
  		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
  
  		if (bmcr & BMCR_ANENABLE) {
@@ -483228,7 +502100,7 @@
  		bnx2_write_phy(bp, 0x17, 0x0f01);
  		bnx2_read_phy(bp, 0x15, &phy2);
  		if (phy2 & 0x20) {
-@@ -4871,21 +5374,33 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
+@@ -4871,21 +5430,33 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
  			bmcr |= BMCR_ANENABLE;
  			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
  
@@ -483265,7 +502137,16 @@
  		bp->serdes_an_pending = 0;
  		return;
  	}
-@@ -4932,7 +5447,7 @@ bnx2_timer(unsigned long data)
+@@ -4925,14 +5496,15 @@ bnx2_timer(unsigned long data)
+ 
+ 	bnx2_send_heart_beat(bp);
+ 
+-	bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
++	bp->stats_blk->stat_FwRxDrop =
++		bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
+ 
+ 	/* workaround occasional corrupted counters */
+ 	if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
  		REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
  					    BNX2_HC_COMMAND_STATS_NOW);
  
@@ -483274,18 +502155,18 @@
  		if (CHIP_NUM(bp) == CHIP_NUM_5706)
  			bnx2_5706_serdes_timer(bp);
  		else
-@@ -4947,18 +5462,23 @@ static int
+@@ -4947,18 +5519,23 @@ static int
  bnx2_request_irq(struct bnx2 *bp)
  {
  	struct net_device *dev = bp->dev;
 -	int rc = 0;
+-
+-	if (bp->flags & USING_MSI_FLAG) {
+-		irq_handler_t	fn = bnx2_msi;
 +	unsigned long flags;
 +	struct bnx2_irq *irq;
 +	int rc = 0, i;
  
--	if (bp->flags & USING_MSI_FLAG) {
--		irq_handler_t	fn = bnx2_msi;
--
 -		if (bp->flags & ONE_SHOT_MSI_FLAG)
 -			fn = bnx2_msi_1shot;
 +	if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
@@ -483308,7 +502189,7 @@
  	return rc;
  }
  
-@@ -4966,13 +5486,81 @@ static void
+@@ -4966,13 +5543,81 @@ static void
  bnx2_free_irq(struct bnx2 *bp)
  {
  	struct net_device *dev = bp->dev;
@@ -483395,7 +502276,7 @@
  }
  
  /* Called with rtnl_lock */
-@@ -4991,19 +5579,12 @@ bnx2_open(struct net_device *dev)
+@@ -4991,19 +5636,12 @@ bnx2_open(struct net_device *dev)
  	if (rc)
  		return rc;
  
@@ -483418,7 +502299,7 @@
  		bnx2_free_mem(bp);
  		return rc;
  	}
-@@ -5011,7 +5592,7 @@ bnx2_open(struct net_device *dev)
+@@ -5011,7 +5649,7 @@ bnx2_open(struct net_device *dev)
  	rc = bnx2_init_nic(bp);
  
  	if (rc) {
@@ -483427,7 +502308,7 @@
  		bnx2_free_irq(bp);
  		bnx2_free_skbs(bp);
  		bnx2_free_mem(bp);
-@@ -5024,7 +5605,7 @@ bnx2_open(struct net_device *dev)
+@@ -5024,7 +5662,7 @@ bnx2_open(struct net_device *dev)
  
  	bnx2_enable_int(bp);
  
@@ -483436,7 +502317,7 @@
  		/* Test MSI to make sure it is working
  		 * If MSI test fails, go back to INTx mode
  		 */
-@@ -5038,13 +5619,15 @@ bnx2_open(struct net_device *dev)
+@@ -5038,13 +5676,15 @@ bnx2_open(struct net_device *dev)
  			bnx2_disable_int(bp);
  			bnx2_free_irq(bp);
  
@@ -483453,7 +502334,7 @@
  				bnx2_free_skbs(bp);
  				bnx2_free_mem(bp);
  				del_timer_sync(&bp->timer);
-@@ -5053,9 +5636,10 @@ bnx2_open(struct net_device *dev)
+@@ -5053,9 +5693,10 @@ bnx2_open(struct net_device *dev)
  			bnx2_enable_int(bp);
  		}
  	}
@@ -483466,7 +502347,7 @@
  
  	netif_start_queue(dev);
  
-@@ -5119,8 +5703,10 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -5119,8 +5760,10 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
  	u32 len, vlan_tag_flags, last_frag, mss;
  	u16 prod, ring_prod;
  	int i;
@@ -483478,7 +502359,7 @@
  		netif_stop_queue(dev);
  		printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
  			dev->name);
-@@ -5136,7 +5722,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -5136,7 +5779,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
  		vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
  	}
  
@@ -483487,7 +502368,7 @@
  		vlan_tag_flags |=
  			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
  	}
-@@ -5235,9 +5821,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -5235,9 +5878,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
  	bp->tx_prod = prod;
  	dev->trans_start = jiffies;
  
@@ -483499,7 +502380,7 @@
  			netif_wake_queue(dev);
  	}
  
-@@ -5259,9 +5845,9 @@ bnx2_close(struct net_device *dev)
+@@ -5259,9 +5902,9 @@ bnx2_close(struct net_device *dev)
  		msleep(1);
  
  	bnx2_disable_int_sync(bp);
@@ -483511,7 +502392,7 @@
  		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
  	else if (bp->wol)
  		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
-@@ -5375,7 +5961,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -5375,7 +6018,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  	int support_serdes = 0, support_copper = 0;
  
  	cmd->supported = SUPPORTED_Autoneg;
@@ -483520,7 +502401,7 @@
  		support_serdes = 1;
  		support_copper = 1;
  	} else if (bp->phy_port == PORT_FIBRE)
-@@ -5386,7 +5972,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -5386,7 +6029,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  	if (support_serdes) {
  		cmd->supported |= SUPPORTED_1000baseT_Full |
  			SUPPORTED_FIBRE;
@@ -483529,7 +502410,7 @@
  			cmd->supported |= SUPPORTED_2500baseX_Full;
  
  	}
-@@ -5442,7 +6028,8 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -5442,7 +6085,8 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  	if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
  		goto err_out_unlock;
  
@@ -483539,7 +502420,7 @@
  		goto err_out_unlock;
  
  	if (cmd->autoneg == AUTONEG_ENABLE) {
-@@ -5462,7 +6049,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -5462,7 +6106,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  			advertising = cmd->advertising;
  
  		} else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
@@ -483548,7 +502429,7 @@
  			    (cmd->port == PORT_TP))
  				goto err_out_unlock;
  		} else if (cmd->advertising == ADVERTISED_1000baseT_Full)
-@@ -5485,7 +6072,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -5485,7 +6129,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  				goto err_out_unlock;
  
  			if (cmd->speed == SPEED_2500 &&
@@ -483557,7 +502438,7 @@
  				goto err_out_unlock;
  		}
  		else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
-@@ -5584,7 +6171,7 @@ bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+@@ -5584,7 +6228,7 @@ bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  {
  	struct bnx2 *bp = netdev_priv(dev);
  
@@ -483566,7 +502447,7 @@
  		wol->supported = 0;
  		wol->wolopts = 0;
  	}
-@@ -5607,7 +6194,7 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+@@ -5607,7 +6251,7 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
  		return -EINVAL;
  
  	if (wol->wolopts & WAKE_MAGIC) {
@@ -483575,7 +502456,7 @@
  			return -EINVAL;
  
  		bp->wol = 1;
-@@ -5630,7 +6217,7 @@ bnx2_nway_reset(struct net_device *dev)
+@@ -5630,7 +6274,7 @@ bnx2_nway_reset(struct net_device *dev)
  
  	spin_lock_bh(&bp->phy_lock);
  
@@ -483584,7 +502465,7 @@
  		int rc;
  
  		rc = bnx2_setup_remote_phy(bp, bp->phy_port);
-@@ -5639,7 +6226,7 @@ bnx2_nway_reset(struct net_device *dev)
+@@ -5639,7 +6283,7 @@ bnx2_nway_reset(struct net_device *dev)
  	}
  
  	/* Force a link down visible on the other side */
@@ -483593,7 +502474,7 @@
  		bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
  		spin_unlock_bh(&bp->phy_lock);
  
-@@ -5778,27 +6365,19 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+@@ -5778,27 +6422,19 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
  
  	ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
  	ering->rx_mini_max_pending = 0;
@@ -483624,7 +502505,7 @@
  	if (netif_running(bp->dev)) {
  		bnx2_netif_stop(bp);
  		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
-@@ -5806,8 +6385,8 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+@@ -5806,8 +6442,8 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
  		bnx2_free_mem(bp);
  	}
  
@@ -483635,7 +502516,7 @@
  
  	if (netif_running(bp->dev)) {
  		int rc;
-@@ -5818,10 +6397,25 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+@@ -5818,10 +6454,25 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
  		bnx2_init_nic(bp);
  		bnx2_netif_start(bp);
  	}
@@ -483662,7 +502543,7 @@
  static void
  bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
  {
-@@ -6244,7 +6838,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -6244,7 +6895,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  	case SIOCGMIIREG: {
  		u32 mii_regval;
  
@@ -483671,7 +502552,7 @@
  			return -EOPNOTSUPP;
  
  		if (!netif_running(dev))
-@@ -6263,7 +6857,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -6263,7 +6914,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  		if (!capable(CAP_NET_ADMIN))
  			return -EPERM;
  
@@ -483680,7 +502561,7 @@
  			return -EOPNOTSUPP;
  
  		if (!netif_running(dev))
-@@ -6310,14 +6904,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
+@@ -6310,14 +6961,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
  		return -EINVAL;
  
  	dev->mtu = new_mtu;
@@ -483696,7 +502577,7 @@
  }
  
  #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
-@@ -6342,7 +6929,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
+@@ -6342,7 +6986,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
  	if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
  		return;
  	else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
@@ -483705,7 +502586,7 @@
  		return;
  	}
  
-@@ -6356,7 +6943,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
+@@ -6356,7 +7000,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
  		case 0x4:
  		case 0x5:
  		case 0x6:
@@ -483714,7 +502595,7 @@
  			return;
  		}
  	} else {
-@@ -6364,7 +6951,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
+@@ -6364,7 +7008,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
  		case 0x1:
  		case 0x2:
  		case 0x4:
@@ -483723,7 +502604,7 @@
  			return;
  		}
  	}
-@@ -6379,7 +6966,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
+@@ -6379,7 +7023,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
  	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
  		u32 clkreg;
  
@@ -483732,7 +502613,7 @@
  
  		clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
  
-@@ -6418,7 +7005,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
+@@ -6418,7 +7062,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
  	}
  
  	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
@@ -483741,7 +502622,7 @@
  
  }
  
-@@ -6506,7 +7093,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6506,7 +7150,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
  			rc = -EIO;
  			goto err_out_unmap;
  		}
@@ -483752,7 +502633,7 @@
  	} else {
  		bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
  		if (bp->pcix_cap == 0) {
-@@ -6517,9 +7106,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6517,9 +7163,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
  		}
  	}
  
@@ -483768,7 +502649,7 @@
  	}
  
  	/* 5708 cannot support DMA addresses > 40-bit.  */
-@@ -6542,7 +7136,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6542,7 +7193,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
  		goto err_out_unmap;
  	}
  
@@ -483777,7 +502658,7 @@
  		bnx2_get_pci_speed(bp);
  
  	/* 5706A0 may falsely detect SERR and PERR. */
-@@ -6552,7 +7146,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6552,7 +7203,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
  		REG_WR(bp, PCI_COMMAND, reg);
  	}
  	else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
@@ -483786,7 +502667,46 @@
  
  		dev_err(&pdev->dev,
  			"5706 A1 can only be used in a PCIX bus, aborting.\n");
-@@ -6602,7 +7196,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6561,20 +7212,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+ 
+ 	bnx2_init_nvram(bp);
+ 
+-	reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
++	reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
+ 
+ 	if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
+ 	    BNX2_SHM_HDR_SIGNATURE_SIG) {
+ 		u32 off = PCI_FUNC(pdev->devfn) << 2;
+ 
+-		bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
++		bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
+ 	} else
+ 		bp->shmem_base = HOST_VIEW_SHMEM_BASE;
+ 
+ 	/* Get the permanent MAC address.  First we need to make sure the
+ 	 * firmware is actually running.
+ 	 */
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
++	reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
+ 
+ 	if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
+ 	    BNX2_DEV_INFO_SIGNATURE_MAGIC) {
+@@ -6583,7 +7234,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+ 		goto err_out_unmap;
+ 	}
+ 
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
++	reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
+ 	for (i = 0, j = 0; i < 3; i++) {
+ 		u8 num, k, skip0;
+ 
+@@ -6597,54 +7248,53 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+ 		if (i != 2)
+ 			bp->fw_version[j++] = '.';
+ 	}
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
++	reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+ 	if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
  		bp->wol = 1;
  
  	if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
@@ -483794,8 +502714,42 @@
 +		bp->flags |= BNX2_FLAG_ASF_ENABLE;
  
  		for (i = 0; i < 30; i++) {
- 			reg = REG_RD_IND(bp, bp->shmem_base +
-@@ -6638,13 +7232,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+-			reg = REG_RD_IND(bp, bp->shmem_base +
+-					     BNX2_BC_STATE_CONDITION);
++			reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+ 			if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+ 				break;
+ 			msleep(10);
+ 		}
+ 	}
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
++	reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+ 	reg &= BNX2_CONDITION_MFW_RUN_MASK;
+ 	if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
+ 	    reg != BNX2_CONDITION_MFW_RUN_NONE) {
+ 		int i;
+-		u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
++		u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
+ 
+ 		bp->fw_version[j++] = ' ';
+ 		for (i = 0; i < 3; i++) {
+-			reg = REG_RD_IND(bp, addr + i * 4);
++			reg = bnx2_reg_rd_ind(bp, addr + i * 4);
+ 			reg = swab32(reg);
+ 			memcpy(&bp->fw_version[j], &reg, 4);
+ 			j += 4;
+ 		}
+ 	}
+ 
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
++	reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
+ 	bp->mac_addr[0] = (u8) (reg >> 8);
+ 	bp->mac_addr[1] = (u8) reg;
+ 
+-	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
++	reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
+ 	bp->mac_addr[2] = (u8) (reg >> 24);
+ 	bp->mac_addr[3] = (u8) (reg >> 16);
  	bp->mac_addr[4] = (u8) (reg >> 8);
  	bp->mac_addr[5] = (u8) reg;
  
@@ -483811,7 +502765,7 @@
  	bp->tx_quick_cons_trip_int = 20;
  	bp->tx_quick_cons_trip = 20;
  	bp->tx_ticks_int = 80;
-@@ -6666,36 +7260,36 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
+@@ -6666,36 +7316,35 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
  	if (CHIP_NUM(bp) == CHIP_NUM_5709)
  		bnx2_get_5709_media(bp);
  	else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
@@ -483822,8 +502776,9 @@
 -	if (bp->phy_flags & PHY_SERDES_FLAG) {
 +	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
  		bp->phy_port = PORT_FIBRE;
- 		reg = REG_RD_IND(bp, bp->shmem_base +
- 				     BNX2_SHARED_HW_CFG_CONFIG);
+-		reg = REG_RD_IND(bp, bp->shmem_base +
+-				     BNX2_SHARED_HW_CFG_CONFIG);
++		reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
  		if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
 -			bp->flags |= NO_WOL_FLAG;
 +			bp->flags |= BNX2_FLAG_NO_WOL;
@@ -483855,7 +502810,7 @@
  		bp->wol = 0;
  	}
  
-@@ -6769,13 +7363,13 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
+@@ -6769,13 +7418,13 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
  {
  	char *s = str;
  
@@ -483872,7 +502827,7 @@
  			s += sprintf(s, " 32-bit");
  		else
  			s += sprintf(s, " 64-bit");
-@@ -6784,6 +7378,21 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
+@@ -6784,6 +7433,21 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
  	return str;
  }
  
@@ -483894,7 +502849,7 @@
  static int __devinit
  bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
-@@ -6825,7 +7434,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -6825,7 +7489,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  	dev->ethtool_ops = &bnx2_ethtool_ops;
  
  	bp = netdev_priv(dev);
@@ -483903,7 +502858,7 @@
  
  #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
  	dev->poll_controller = poll_bnx2;
-@@ -6910,7 +7519,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
+@@ -6910,7 +7574,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
  	bnx2_netif_stop(bp);
  	netif_device_detach(dev);
  	del_timer_sync(&bp->timer);
@@ -483913,7 +502868,7 @@
  	else if (bp->wol)
  		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
 diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
-index 30ba366..d8e0347 100644
+index 30ba366..3aa0364 100644
 --- a/drivers/net/bnx2.h
 +++ b/drivers/net/bnx2.h
 @@ -154,6 +154,33 @@ struct status_block {
@@ -483958,7 +502913,20 @@
  		#define L2_FHDR_ERRORS_BAD_CRC		(1<<17)
  		#define L2_FHDR_ERRORS_PHY_DECODE	(1<<18)
  		#define L2_FHDR_ERRORS_ALIGNMENT	(1<<19)
-@@ -332,6 +360,12 @@ struct l2_fhdr {
+@@ -320,6 +348,12 @@ struct l2_fhdr {
+ #define BNX2_L2CTX_BD_PRE_READ				0x00000000
+ #define BNX2_L2CTX_CTX_SIZE				0x00000000
+ #define BNX2_L2CTX_CTX_TYPE				0x00000000
++#define BNX2_L2CTX_LO_WATER_MARK_DEFAULT		 32
++#define BNX2_L2CTX_LO_WATER_MARK_SCALE			 4
++#define BNX2_L2CTX_LO_WATER_MARK_DIS			 0
++#define BNX2_L2CTX_HI_WATER_MARK_SHIFT			 4
++#define BNX2_L2CTX_HI_WATER_MARK_SCALE			 16
++#define BNX2_L2CTX_WATER_MARKS_MSK			 0x000000ff
+ #define BNX2_L2CTX_CTX_TYPE_SIZE_L2			 ((0x20/20)<<16)
+ #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE		 (0xf<<28)
+ #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_UNDEFINED	 (0<<28)
+@@ -332,6 +366,12 @@ struct l2_fhdr {
  #define BNX2_L2CTX_NX_BDHADDR_LO			0x00000014
  #define BNX2_L2CTX_NX_BDIDX				0x00000018
  
@@ -483971,7 +502939,7 @@
  
  /*
   *  pci_config_l definition
-@@ -406,6 +440,7 @@ struct l2_fhdr {
+@@ -406,6 +446,7 @@ struct l2_fhdr {
  #define BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM	 (1L<<17)
  #define BNX2_PCICFG_INT_ACK_CMD_MASK_INT		 (1L<<18)
  #define BNX2_PCICFG_INT_ACK_CMD_INTERRUPT_NUM		 (0xfL<<24)
@@ -483979,7 +502947,7 @@
  
  #define BNX2_PCICFG_STATUS_BIT_SET_CMD			0x00000088
  #define BNX2_PCICFG_STATUS_BIT_CLEAR_CMD		0x0000008c
-@@ -421,6 +456,9 @@ struct l2_fhdr {
+@@ -421,6 +462,9 @@ struct l2_fhdr {
  #define BNX2_PCI_GRC_WINDOW_ADDR_VALUE			 (0x1ffL<<13)
  #define BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN		 (1L<<31)
  
@@ -483989,7 +502957,7 @@
  #define BNX2_PCI_CONFIG_1				0x00000404
  #define BNX2_PCI_CONFIG_1_RESERVED0			 (0xffL<<0)
  #define BNX2_PCI_CONFIG_1_READ_BOUNDARY			 (0x7L<<8)
-@@ -693,6 +731,8 @@ struct l2_fhdr {
+@@ -693,6 +737,8 @@ struct l2_fhdr {
  #define BNX2_PCI_GRC_WINDOW3_ADDR			0x00000618
  #define BNX2_PCI_GRC_WINDOW3_ADDR_VALUE			 (0x1ffL<<13)
  
@@ -483998,7 +502966,7 @@
  
  /*
   *  misc_reg definition
-@@ -4445,6 +4485,14 @@ struct l2_fhdr {
+@@ -4445,6 +4491,17 @@ struct l2_fhdr {
  #define BNX2_MQ_MEM_RD_DATA2_VALUE			 (0x3fffffffL<<0)
  #define BNX2_MQ_MEM_RD_DATA2_VALUE_XI			 (0x7fffffffL<<0)
  
@@ -484010,35 +502978,58 @@
 +#define BNX2_MQ_MAP_L2_3_ARM				 (0x3L<<26)
 +#define BNX2_MQ_MAP_L2_3_ENA				 (0x1L<<31)
 +#define BNX2_MQ_MAP_L2_3_DEFAULT			 0x82004646
++
++#define BNX2_MQ_MAP_L2_5				0x00003d34
++#define BNX2_MQ_MAP_L2_5_ARM				 (0x3L<<26)
  
  /*
   *  tsch_reg definition
-@@ -6296,6 +6344,15 @@ struct l2_fhdr {
+@@ -5462,6 +5519,15 @@ struct l2_fhdr {
+ #define BNX2_HC_PERIODIC_TICKS_8_HC_PERIODIC_TICKS	 (0xffffL<<0)
+ #define BNX2_HC_PERIODIC_TICKS_8_HC_INT_PERIODIC_TICKS	 (0xffffL<<16)
+ 
++#define BNX2_HC_SB_CONFIG_SIZE	(BNX2_HC_SB_CONFIG_2 - BNX2_HC_SB_CONFIG_1)
++#define BNX2_HC_COMP_PROD_TRIP_OFF	(BNX2_HC_COMP_PROD_TRIP_1 -	\
++					 BNX2_HC_SB_CONFIG_1)
++#define BNX2_HC_COM_TICKS_OFF	(BNX2_HC_COM_TICKS_1 - BNX2_HC_SB_CONFIG_1)
++#define BNX2_HC_CMD_TICKS_OFF	(BNX2_HC_CMD_TICKS_1 - BNX2_HC_SB_CONFIG_1)
++#define BNX2_HC_TX_QUICK_CONS_TRIP_OFF	(BNX2_HC_TX_QUICK_CONS_TRIP_1 -	\
++					 BNX2_HC_SB_CONFIG_1)
++#define BNX2_HC_TX_TICKS_OFF	(BNX2_HC_TX_TICKS_1 - BNX2_HC_SB_CONFIG_1)
++
+ 
+ /*
+  *  txp_reg definition
+@@ -6296,6 +6362,16 @@ struct l2_fhdr {
  #define MII_BNX2_DSP_RW_PORT			0x15
  #define MII_BNX2_DSP_ADDRESS			0x17
  #define MII_BNX2_DSP_EXPAND_REG			 0x0f00
 +#define MII_EXPAND_REG1				  (MII_BNX2_DSP_EXPAND_REG | 1)
 +#define MII_EXPAND_REG1_RUDI_C			   0x20
-+#define MII_EXPAND_SERDES_CTL			  (MII_BNX2_DSP_EXPAND_REG | 2)
++#define MII_EXPAND_SERDES_CTL			  (MII_BNX2_DSP_EXPAND_REG | 3)
 +
 +#define MII_BNX2_MISC_SHADOW			0x1c
 +#define MISC_SHDW_AN_DBG			 0x6800
 +#define MISC_SHDW_AN_DBG_NOSYNC			  0x0002
++#define MISC_SHDW_AN_DBG_RUDI_INVALID		  0x0100
 +#define MISC_SHDW_MODE_CTL			 0x7c00
 +#define MISC_SHDW_MODE_CTL_SIG_DET		  0x0010
  
  #define MII_BNX2_BLK_ADDR			0x1f
  #define MII_BNX2_BLK_ADDR_IEEE0			 0x0000
-@@ -6336,7 +6393,7 @@ struct l2_fhdr {
+@@ -6336,9 +6412,9 @@ struct l2_fhdr {
  #define MAX_ETHERNET_PACKET_SIZE	1514
  #define MAX_ETHERNET_JUMBO_PACKET_SIZE	9014
  
 -#define RX_COPY_THRESH			92
 +#define RX_COPY_THRESH			128
  
- #define BNX2_MISC_ENABLE_DEFAULT	0x7ffffff
+-#define BNX2_MISC_ENABLE_DEFAULT	0x7ffffff
++#define BNX2_MISC_ENABLE_DEFAULT	0x17ffffff
  
-@@ -6355,9 +6412,11 @@ struct l2_fhdr {
+ #define DMA_READ_CHANS	5
+ #define DMA_WRITE_CHANS	3
+@@ -6355,9 +6431,11 @@ struct l2_fhdr {
  #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
  
  #define MAX_RX_RINGS	4
@@ -484050,7 +503041,7 @@
  
  #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
  		(MAX_TX_DESC_CNT - 1)) ?				\
-@@ -6370,6 +6429,7 @@ struct l2_fhdr {
+@@ -6370,6 +6448,7 @@ struct l2_fhdr {
  	(x) + 2 : (x) + 1
  
  #define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
@@ -484058,7 +503049,7 @@
  
  #define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> (BCM_PAGE_BITS - 4))
  #define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
-@@ -6408,6 +6468,17 @@ struct sw_bd {
+@@ -6408,6 +6487,17 @@ struct sw_bd {
  	DECLARE_PCI_UNMAP_ADDR(mapping)
  };
  
@@ -484076,7 +503067,7 @@
  /* Buffered flash (Atmel: AT45DB011B) specific information */
  #define SEEPROM_PAGE_BITS			2
  #define SEEPROM_PHY_PAGE_SIZE			(1 << SEEPROM_PAGE_BITS)
-@@ -6465,6 +6536,39 @@ struct flash_spec {
+@@ -6465,6 +6555,39 @@ struct flash_spec {
  	u8  *name;
  };
  
@@ -484116,7 +503107,7 @@
  struct bnx2 {
  	/* Fields used in the tx and intr/napi performance paths are grouped */
  	/* together in the beginning of the structure. */
-@@ -6473,33 +6577,32 @@ struct bnx2 {
+@@ -6473,33 +6596,32 @@ struct bnx2 {
  	struct net_device	*dev;
  	struct pci_dev		*pdev;
  
@@ -484165,7 +503156,7 @@
  
  #ifdef BCM_VLAN
  	struct			vlan_group *vlgrp;
-@@ -6508,16 +6611,17 @@ struct bnx2 {
+@@ -6508,16 +6630,17 @@ struct bnx2 {
  	u32			rx_offset;
  	u32			rx_buf_use_size;	/* useable size */
  	u32			rx_buf_size;		/* with alignment */
@@ -484187,7 +503178,7 @@
  
  	/* TX constants */
  	struct tx_bd	*tx_desc_ring;
-@@ -6540,15 +6644,16 @@ struct bnx2 {
+@@ -6540,15 +6663,16 @@ struct bnx2 {
  	spinlock_t		indirect_lock;
  
  	u32			phy_flags;
@@ -484213,7 +503204,7 @@
  
  	u32			mii_bmcr;
  	u32			mii_bmsr;
-@@ -6605,6 +6710,10 @@ struct bnx2 {
+@@ -6605,6 +6729,10 @@ struct bnx2 {
  	int			rx_ring_size;
  	dma_addr_t		rx_desc_mapping[MAX_RX_RINGS];
  
@@ -484224,7 +503215,7 @@
  	u16			tx_quick_cons_trip;
  	u16			tx_quick_cons_trip_int;
  	u16			rx_quick_cons_trip;
-@@ -6622,6 +6731,7 @@ struct bnx2 {
+@@ -6622,6 +6750,7 @@ struct bnx2 {
  
  	u32			stats_ticks;
  
@@ -484232,17 +503223,41 @@
  	dma_addr_t		status_blk_mapping;
  
  	struct statistics_block	*stats_blk;
-@@ -6680,6 +6790,9 @@ struct bnx2 {
+@@ -6680,10 +6809,10 @@ struct bnx2 {
  	u32			flash_size;
  
  	int			status_stats_size;
-+
+-};
+ 
+-static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
+-static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
 +	struct bnx2_irq		irq_tbl[BNX2_MAX_MSIX_VEC];
 +	int			irq_nvecs;
- };
++};
  
- static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
-@@ -6737,7 +6850,7 @@ struct fw_info {
+ #define REG_RD(bp, offset)					\
+ 	readl(bp->regview + offset)
+@@ -6694,19 +6823,6 @@ static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
+ #define REG_WR16(bp, offset, val)				\
+ 	writew(val, bp->regview + offset)
+ 
+-#define REG_RD_IND(bp, offset)					\
+-	bnx2_reg_rd_ind(bp, offset)
+-
+-#define REG_WR_IND(bp, offset, val)				\
+-	bnx2_reg_wr_ind(bp, offset, val)
+-
+-/* Indirect context access.  Unlike the MBQ_WR, these macros will not
+- * trigger a chip event. */
+-static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val);
+-
+-#define CTX_WR(bp, cid_addr, offset, val)			\
+-	bnx2_ctx_wr(bp, cid_addr, offset, val)
+-
+ struct cpu_reg {
+ 	u32 mode;
+ 	u32 mode_value_halt;
+@@ -6737,7 +6853,7 @@ struct fw_info {
  	const u32 text_addr;
  	const u32 text_len;
  	const u32 text_index;
@@ -510449,6 +529464,21 @@
  {
  	struct net_device *dev = dev_id;
  	struct lance_private *lp = netdev_priv(dev);
+diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
+index d66c605..266ec87 100644
+--- a/drivers/net/dl2k.h
++++ b/drivers/net/dl2k.h
+@@ -388,8 +388,8 @@ enum _mii_mssr {
+ 	MII_MSSR_CFG_RES = 0x4000,
+ 	MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
+ 	MII_MSSR_REMOTE_RCVR = 0x1000,
+-	MII_MSSR_LP_1000BT_HD = 0x0800,
+-	MII_MSSR_LP_1000BT_FD = 0x0400,
++	MII_MSSR_LP_1000BT_FD = 0x0800,
++	MII_MSSR_LP_1000BT_HD = 0x0400,
+ 	MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
+ };
+ 
 diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
 index 3286d2a..6a20a54 100644
 --- a/drivers/net/dm9000.c
@@ -534819,7 +553849,7 @@
  		mp->rx_bufs[i] = skb;
  	    }
 diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
-index e8dc2f4..6ef6b8b 100644
+index e8dc2f4..f651a81 100644
 --- a/drivers/net/macvlan.c
 +++ b/drivers/net/macvlan.c
 @@ -73,8 +73,6 @@ static void macvlan_broadcast(struct sk_buff *skb,
@@ -534878,6 +553908,15 @@
  			netif_carrier_off(dev);
  	}
  }
+@@ -486,7 +508,7 @@ static int __init macvlan_init_module(void)
+ 		goto err1;
+ 	return 0;
+ err1:
+-	macvlan_handle_frame_hook = macvlan_handle_frame;
++	macvlan_handle_frame_hook = NULL;
+ 	unregister_netdevice_notifier(&macvlan_notifier_block);
+ 	return err;
+ }
 diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
 index 5064873..535a446 100644
 --- a/drivers/net/mlx4/fw.c
@@ -545766,11 +564805,92 @@
  	{},
  };
  
+diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
+index 569028b..6f245cf 100644
+--- a/drivers/net/usb/asix.c
++++ b/drivers/net/usb/asix.c
+@@ -33,8 +33,7 @@
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+ #include <linux/crc32.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ #define DRIVER_VERSION "14-Jun-2006"
+ static const char driver_name [] = "asix";
+diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
+index a42acc3..a934428 100644
+--- a/drivers/net/usb/cdc_ether.c
++++ b/drivers/net/usb/cdc_ether.c
+@@ -31,8 +31,7 @@
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+ #include <linux/usb/cdc.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ 
+ #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+@@ -228,15 +227,16 @@ next_desc:
+ 		buf += buf [0];
+ 	}
+ 
+-	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+-	 * so we'll hard-wire the interfaces and not check for descriptors.
++	/* Microsoft ActiveSync based and some regular RNDIS devices lack the
++	 * CDC descriptors, so we'll hard-wire the interfaces and not check
++	 * for descriptors.
+ 	 */
+-	if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
++	if (rndis && !info->u) {
+ 		info->control = usb_ifnum_to_if(dev->udev, 0);
+ 		info->data = usb_ifnum_to_if(dev->udev, 1);
+ 		if (!info->control || !info->data) {
+ 			dev_dbg(&intf->dev,
+-				"activesync: master #0/%p slave #1/%p\n",
++				"rndis: master #0/%p slave #1/%p\n",
+ 				info->control,
+ 				info->data);
+ 			goto bad_desc;
+@@ -316,7 +316,6 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
+ }
+ EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
+ 
+-
+ /*-------------------------------------------------------------------------
+  *
+  * Communications Device Class, Ethernet Control model
+diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
+index 943988e..0ec7936 100644
+--- a/drivers/net/usb/cdc_subset.c
++++ b/drivers/net/usb/cdc_subset.c
+@@ -26,8 +26,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ 
+ /*
 diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
-index 1ffdd10..633a511 100644
+index 1ffdd10..4b131a6 100644
 --- a/drivers/net/usb/dm9601.c
 +++ b/drivers/net/usb/dm9601.c
-@@ -101,17 +101,16 @@ static void dm_write_async_callback(struct urb *urb)
+@@ -20,8 +20,7 @@
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+ #include <linux/crc32.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ /* datasheet:
+  http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
+@@ -101,17 +100,16 @@ static void dm_write_async_callback(struct urb *urb)
  	usb_free_urb(urb);
  }
  
@@ -545791,7 +564911,7 @@
  		return;
  	}
  
-@@ -123,8 +122,8 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+@@ -123,8 +121,8 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
  	}
  
  	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -545802,7 +564922,7 @@
  	req->wIndex = cpu_to_le16(reg);
  	req->wLength = cpu_to_le16(length);
  
-@@ -142,45 +141,19 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+@@ -142,45 +140,19 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
  	}
  }
  
@@ -545856,6 +564976,754 @@
  }
  
  static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
+diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
+index 031cf5c..f7ccfad 100644
+--- a/drivers/net/usb/gl620a.c
++++ b/drivers/net/usb/gl620a.c
+@@ -29,8 +29,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ 
+ /*
+diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
+index 5ea7411..c3d119f 100644
+--- a/drivers/net/usb/mcs7830.c
++++ b/drivers/net/usb/mcs7830.c
+@@ -31,8 +31,7 @@
+ #include <linux/module.h>
+ #include <linux/netdevice.h>
+ #include <linux/usb.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ /* requests */
+ #define MCS7830_RD_BMREQ	(USB_DIR_IN  | USB_TYPE_VENDOR | \
+diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
+index 19bf8da..034e8a7 100644
+--- a/drivers/net/usb/net1080.c
++++ b/drivers/net/usb/net1080.c
+@@ -28,11 +28,10 @@
+ #include <linux/workqueue.h>
+ #include <linux/mii.h>
+ #include <linux/usb.h>
++#include <linux/usb/usbnet.h>
+ 
+ #include <asm/unaligned.h>
+ 
+-#include "usbnet.h"
+-
+ 
+ /*
+  * Netchip 1080 driver ... http://www.netchip.com
+diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
+index 4530093..08555f8 100644
+--- a/drivers/net/usb/plusb.c
++++ b/drivers/net/usb/plusb.c
+@@ -28,8 +28,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ 
+ /*
+diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
+index 1ebe325..a613247 100644
+--- a/drivers/net/usb/rndis_host.c
++++ b/drivers/net/usb/rndis_host.c
+@@ -29,8 +29,8 @@
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+ #include <linux/usb/cdc.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
++#include <linux/usb/rndis_host.h>
+ 
+ 
+ /*
+@@ -56,217 +56,17 @@
+  */
+ 
+ /*
+- * CONTROL uses CDC "encapsulated commands" with funky notifications.
+- *  - control-out:  SEND_ENCAPSULATED
+- *  - interrupt-in:  RESPONSE_AVAILABLE
+- *  - control-in:  GET_ENCAPSULATED
+- *
+- * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+- *
+- * REVISIT some RNDIS implementations seem to have curious issues still
+- * to be resolved.
+- */
+-struct rndis_msg_hdr {
+-	__le32	msg_type;			/* RNDIS_MSG_* */
+-	__le32	msg_len;
+-	// followed by data that varies between messages
+-	__le32	request_id;
+-	__le32	status;
+-	// ... and more
+-} __attribute__ ((packed));
+-
+-/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+-#define	CONTROL_BUFFER_SIZE		1025
+-
+-/* RNDIS defines an (absurdly huge) 10 second control timeout,
+- * but ActiveSync seems to use a more usual 5 second timeout
+- * (which matches the USB 2.0 spec).
+- */
+-#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
+-
+-
+-#define ccpu2 __constant_cpu_to_le32
+-
+-#define RNDIS_MSG_COMPLETION	ccpu2(0x80000000)
+-
+-/* codes for "msg_type" field of rndis messages;
+- * only the data channel uses packet messages (maybe batched);
+- * everything else goes on the control channel.
+- */
+-#define RNDIS_MSG_PACKET	ccpu2(0x00000001)	/* 1-N packets */
+-#define RNDIS_MSG_INIT		ccpu2(0x00000002)
+-#define RNDIS_MSG_INIT_C	(RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
+-#define RNDIS_MSG_HALT		ccpu2(0x00000003)
+-#define RNDIS_MSG_QUERY		ccpu2(0x00000004)
+-#define RNDIS_MSG_QUERY_C	(RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
+-#define RNDIS_MSG_SET		ccpu2(0x00000005)
+-#define RNDIS_MSG_SET_C		(RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
+-#define RNDIS_MSG_RESET		ccpu2(0x00000006)
+-#define RNDIS_MSG_RESET_C	(RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
+-#define RNDIS_MSG_INDICATE	ccpu2(0x00000007)
+-#define RNDIS_MSG_KEEPALIVE	ccpu2(0x00000008)
+-#define RNDIS_MSG_KEEPALIVE_C	(RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
+-
+-/* codes for "status" field of completion messages */
+-#define	RNDIS_STATUS_SUCCESS		ccpu2(0x00000000)
+-#define	RNDIS_STATUS_FAILURE		ccpu2(0xc0000001)
+-#define	RNDIS_STATUS_INVALID_DATA	ccpu2(0xc0010015)
+-#define	RNDIS_STATUS_NOT_SUPPORTED	ccpu2(0xc00000bb)
+-#define	RNDIS_STATUS_MEDIA_CONNECT	ccpu2(0x4001000b)
+-#define	RNDIS_STATUS_MEDIA_DISCONNECT	ccpu2(0x4001000c)
+-
+-
+-struct rndis_data_hdr {
+-	__le32	msg_type;		/* RNDIS_MSG_PACKET */
+-	__le32	msg_len;		// rndis_data_hdr + data_len + pad
+-	__le32	data_offset;		// 36 -- right after header
+-	__le32	data_len;		// ... real packet size
+-
+-	__le32	oob_data_offset;	// zero
+-	__le32	oob_data_len;		// zero
+-	__le32	num_oob;		// zero
+-	__le32	packet_data_offset;	// zero
+-
+-	__le32	packet_data_len;	// zero
+-	__le32	vc_handle;		// zero
+-	__le32	reserved;		// zero
+-} __attribute__ ((packed));
+-
+-struct rndis_init {		/* OUT */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_INIT */
+-	__le32	msg_len;			// 24
+-	__le32	request_id;
+-	__le32	major_version;			// of rndis (1.0)
+-	__le32	minor_version;
+-	__le32	max_transfer_size;
+-} __attribute__ ((packed));
+-
+-struct rndis_init_c {		/* IN */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_INIT_C */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	status;
+-	__le32	major_version;			// of rndis (1.0)
+-	__le32	minor_version;
+-	__le32	device_flags;
+-	__le32	medium;				// zero == 802.3
+-	__le32	max_packets_per_message;
+-	__le32	max_transfer_size;
+-	__le32	packet_alignment;		// max 7; (1<<n) bytes
+-	__le32	af_list_offset;			// zero
+-	__le32	af_list_size;			// zero
+-} __attribute__ ((packed));
+-
+-struct rndis_halt {		/* OUT (no reply) */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_HALT */
+-	__le32	msg_len;
+-	__le32	request_id;
+-} __attribute__ ((packed));
+-
+-struct rndis_query {		/* OUT */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_QUERY */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	oid;
+-	__le32	len;
+-	__le32	offset;
+-/*?*/	__le32	handle;				// zero
+-} __attribute__ ((packed));
+-
+-struct rndis_query_c {		/* IN */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_QUERY_C */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	status;
+-	__le32	len;
+-	__le32	offset;
+-} __attribute__ ((packed));
+-
+-struct rndis_set {		/* OUT */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_SET */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	oid;
+-	__le32	len;
+-	__le32	offset;
+-/*?*/	__le32	handle;				// zero
+-} __attribute__ ((packed));
+-
+-struct rndis_set_c {		/* IN */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_SET_C */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	status;
+-} __attribute__ ((packed));
+-
+-struct rndis_reset {		/* IN */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_RESET */
+-	__le32	msg_len;
+-	__le32	reserved;
+-} __attribute__ ((packed));
+-
+-struct rndis_reset_c {		/* OUT */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_RESET_C */
+-	__le32	msg_len;
+-	__le32	status;
+-	__le32	addressing_lost;
+-} __attribute__ ((packed));
+-
+-struct rndis_indicate {		/* IN (unrequested) */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_INDICATE */
+-	__le32	msg_len;
+-	__le32	status;
+-	__le32	length;
+-	__le32	offset;
+-/**/	__le32	diag_status;
+-	__le32	error_offset;
+-/**/	__le32	message;
+-} __attribute__ ((packed));
+-
+-struct rndis_keepalive {	/* OUT (optionally IN) */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE */
+-	__le32	msg_len;
+-	__le32	request_id;
+-} __attribute__ ((packed));
+-
+-struct rndis_keepalive_c {	/* IN (optionally OUT) */
+-	// header and:
+-	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE_C */
+-	__le32	msg_len;
+-	__le32	request_id;
+-	__le32	status;
+-} __attribute__ ((packed));
+-
+-/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
+- * there are gobs more that may optionally be supported.  We'll avoid as much
+- * of that mess as possible.
+- */
+-#define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
+-#define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
+-#define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
+-
+-/*
+  * RNDIS notifications from device: command completion; "reverse"
+  * keepalives; etc
+  */
+-static void rndis_status(struct usbnet *dev, struct urb *urb)
++void rndis_status(struct usbnet *dev, struct urb *urb)
+ {
+ 	devdbg(dev, "rndis status urb, len %d stat %d",
+ 		urb->actual_length, urb->status);
+ 	// FIXME for keepalives, respond immediately (asynchronously)
+ 	// if not an RNDIS status, do like cdc_status(dev,urb) does
+ }
++EXPORT_SYMBOL_GPL(rndis_status);
+ 
+ /*
+  * RPC done RNDIS-style.  Caller guarantees:
+@@ -278,7 +78,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
+  * Call context is likely probe(), before interface name is known,
+  * which is why we won't try to use it in the diagnostics.
+  */
+-static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
++int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
+ {
+ 	struct cdc_state	*info = (void *) &dev->data;
+ 	int			master_ifnum;
+@@ -347,10 +147,26 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
+ 					request_id, xid);
+ 				/* then likely retry */
+ 			} else switch (buf->msg_type) {
+-			case RNDIS_MSG_INDICATE: {	/* fault */
+-				// struct rndis_indicate *msg = (void *)buf;
+-				dev_info(&info->control->dev,
+-					"rndis fault indication\n");
++			case RNDIS_MSG_INDICATE: {	/* fault/event */
++				struct rndis_indicate *msg = (void *)buf;
++				int state = 0;
++
++				switch (msg->status) {
++				case RNDIS_STATUS_MEDIA_CONNECT:
++					state = 1;
++				case RNDIS_STATUS_MEDIA_DISCONNECT:
++					dev_info(&info->control->dev,
++						"rndis media %sconnect\n",
++						!state?"dis":"");
++					if (dev->driver_info->link_change)
++						dev->driver_info->link_change(
++							dev, state);
++					break;
++				default:
++					dev_info(&info->control->dev,
++						"rndis indication: 0x%08x\n",
++						le32_to_cpu(msg->status));
++				}
+ 				}
+ 				break;
+ 			case RNDIS_MSG_KEEPALIVE: {	/* ping */
+@@ -387,6 +203,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
+ 	dev_dbg(&info->control->dev, "rndis response timeout\n");
+ 	return -ETIMEDOUT;
+ }
++EXPORT_SYMBOL_GPL(rndis_command);
+ 
+ /*
+  * rndis_query:
+@@ -453,7 +270,8 @@ response_error:
+ 	return -EDOM;
+ }
+ 
+-static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
++int
++generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
+ {
+ 	int			retval;
+ 	struct net_device	*net = dev->net;
+@@ -467,8 +285,9 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+ 		struct rndis_query_c	*get_c;
+ 		struct rndis_set	*set;
+ 		struct rndis_set_c	*set_c;
++		struct rndis_halt	*halt;
+ 	} u;
+-	u32			tmp;
++	u32			tmp, *phym;
+ 	int			reply_len;
+ 	unsigned char		*bp;
+ 
+@@ -517,7 +336,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+ 				"dev can't take %u byte packets (max %u)\n",
+ 				dev->hard_mtu, tmp);
+ 			retval = -EINVAL;
+-			goto fail_and_release;
++			goto halt_fail_and_release;
+ 		}
+ 		dev->hard_mtu = tmp;
+ 		net->mtu = dev->hard_mtu - net->hard_header_len;
+@@ -533,13 +352,43 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+ 		dev->hard_mtu, tmp, dev->rx_urb_size,
+ 		1 << le32_to_cpu(u.init_c->packet_alignment));
+ 
++	/* module has some device initialization code needs to be done right
++	 * after RNDIS_INIT */
++	if (dev->driver_info->early_init &&
++			dev->driver_info->early_init(dev) != 0)
++		goto halt_fail_and_release;
++
++	/* Check physical medium */
++	reply_len = sizeof *phym;
++	retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM,
++			0, (void **) &phym, &reply_len);
++	if (retval != 0)
++		/* OID is optional so don't fail here. */
++		*phym = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED;
++	if ((flags & FLAG_RNDIS_PHYM_WIRELESS) &&
++			*phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
++		if (netif_msg_probe(dev))
++			dev_dbg(&intf->dev, "driver requires wireless "
++				"physical medium, but device is not.\n");
++		retval = -ENODEV;
++		goto halt_fail_and_release;
++	}
++	if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) &&
++			*phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
++		if (netif_msg_probe(dev))
++			dev_dbg(&intf->dev, "driver requires non-wireless "
++				"physical medium, but device is wireless.\n");
++		retval = -ENODEV;
++		goto halt_fail_and_release;
++	}
++
+ 	/* Get designated host ethernet address */
+ 	reply_len = ETH_ALEN;
+ 	retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
+ 			48, (void **) &bp, &reply_len);
+ 	if (unlikely(retval< 0)) {
+ 		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
+-		goto fail_and_release;
++		goto halt_fail_and_release;
+ 	}
+ 	memcpy(net->dev_addr, bp, ETH_ALEN);
+ 
+@@ -550,12 +399,12 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+ 	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
+ 	u.set->len = ccpu2(4);
+ 	u.set->offset = ccpu2((sizeof *u.set) - 8);
+-	*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
++	*(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER;
+ 
+ 	retval = rndis_command(dev, u.header);
+ 	if (unlikely(retval < 0)) {
+ 		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
+-		goto fail_and_release;
++		goto halt_fail_and_release;
+ 	}
+ 
+ 	retval = 0;
+@@ -563,6 +412,11 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+ 	kfree(u.buf);
+ 	return retval;
+ 
++halt_fail_and_release:
++	memset(u.halt, 0, sizeof *u.halt);
++	u.halt->msg_type = RNDIS_MSG_HALT;
++	u.halt->msg_len = ccpu2(sizeof *u.halt);
++	(void) rndis_command(dev, (void *)u.halt);
+ fail_and_release:
+ 	usb_set_intfdata(info->data, NULL);
+ 	usb_driver_release_interface(driver_of(intf), info->data);
+@@ -571,13 +425,19 @@ fail:
+ 	kfree(u.buf);
+ 	return retval;
+ }
++EXPORT_SYMBOL_GPL(generic_rndis_bind);
++
++static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
++{
++	return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS);
++}
+ 
+-static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
++void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
+ {
+ 	struct rndis_halt	*halt;
+ 
+ 	/* try to clear any rndis state/activity (no i/o from stack!) */
+-	halt = kzalloc(sizeof *halt, GFP_KERNEL);
++	halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
+ 	if (halt) {
+ 		halt->msg_type = RNDIS_MSG_HALT;
+ 		halt->msg_len = ccpu2(sizeof *halt);
+@@ -585,13 +445,14 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
+ 		kfree(halt);
+ 	}
+ 
+-	return usbnet_cdc_unbind(dev, intf);
++	usbnet_cdc_unbind(dev, intf);
+ }
++EXPORT_SYMBOL_GPL(rndis_unbind);
+ 
+ /*
+  * DATA -- host must not write zlps
+  */
+-static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
++int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ {
+ 	/* peripheral may have batched packets to us... */
+ 	while (likely(skb->len)) {
+@@ -633,8 +494,9 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ 	/* caller will usbnet_skb_return the remaining packet */
+ 	return 1;
+ }
++EXPORT_SYMBOL_GPL(rndis_rx_fixup);
+ 
+-static struct sk_buff *
++struct sk_buff *
+ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+ {
+ 	struct rndis_data_hdr	*hdr;
+@@ -679,6 +541,7 @@ fill:
+ 	/* FIXME make the last packet always be short ... */
+ 	return skb;
+ }
++EXPORT_SYMBOL_GPL(rndis_tx_fixup);
+ 
+ 
+ static const struct driver_info	rndis_info = {
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
+index 8ed1fc5..8463efb 100644
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -41,8 +41,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/mii.h>
+ #include <linux/usb.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ #define DRIVER_VERSION		"22-Aug-2005"
+ 
+@@ -1204,6 +1203,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
+ 		if ((dev->driver_info->flags & FLAG_ETHER) != 0
+ 				&& (net->dev_addr [0] & 0x02) == 0)
+ 			strcpy (net->name, "eth%d");
++		/* WLAN devices should always be named "wlan%d" */
++		if ((dev->driver_info->flags & FLAG_WLAN) != 0)
++			strcpy(net->name, "wlan%d");
+ 
+ 		/* maybe the remote can't receive an Ethernet MTU */
+ 		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
+deleted file mode 100644
+index 1fae434..0000000
+--- a/drivers/net/usb/usbnet.h
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/*
+- * USB Networking Link Interface
+- *
+- * Copyright (C) 2000-2005 by David Brownell <dbrownell at users.sourceforge.net>
+- * Copyright (C) 2003-2005 David Hollis <dhollis at davehollis.com>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-
+-
+-#ifndef	__USBNET_H
+-#define	__USBNET_H
+-
+-
+-/* interface from usbnet core to each USB networking link we handle */
+-struct usbnet {
+-	/* housekeeping */
+-	struct usb_device	*udev;
+-	struct usb_interface	*intf;
+-	struct driver_info	*driver_info;
+-	const char		*driver_name;
+-	wait_queue_head_t	*wait;
+-	struct mutex		phy_mutex;
+-	unsigned char		suspend_count;
+-
+-	/* i/o info: pipes etc */
+-	unsigned		in, out;
+-	struct usb_host_endpoint *status;
+-	unsigned		maxpacket;
+-	struct timer_list	delay;
+-
+-	/* protocol/interface state */
+-	struct net_device	*net;
+-	struct net_device_stats	stats;
+-	int			msg_enable;
+-	unsigned long		data [5];
+-	u32			xid;
+-	u32			hard_mtu;	/* count any extra framing */
+-	size_t			rx_urb_size;	/* size for rx urbs */
+-	struct mii_if_info	mii;
+-
+-	/* various kinds of pending driver work */
+-	struct sk_buff_head	rxq;
+-	struct sk_buff_head	txq;
+-	struct sk_buff_head	done;
+-	struct urb		*interrupt;
+-	struct tasklet_struct	bh;
+-
+-	struct work_struct	kevent;
+-	unsigned long		flags;
+-#		define EVENT_TX_HALT	0
+-#		define EVENT_RX_HALT	1
+-#		define EVENT_RX_MEMORY	2
+-#		define EVENT_STS_SPLIT	3
+-#		define EVENT_LINK_RESET	4
+-};
+-
+-static inline struct usb_driver *driver_of(struct usb_interface *intf)
+-{
+-	return to_usb_driver(intf->dev.driver);
+-}
+-
+-/* interface from the device/framing level "minidriver" to core */
+-struct driver_info {
+-	char		*description;
+-
+-	int		flags;
+-/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
+-#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */
+-#define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
+-#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
+-#define FLAG_FRAMING_RN	0x0008		/* RNDIS batches, plus huge header */
+-
+-#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
+-#define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
+-
+-#define FLAG_FRAMING_AX 0x0040		/* AX88772/178 packets */
+-
+-	/* init device ... can sleep, or cause probe() failure */
+-	int	(*bind)(struct usbnet *, struct usb_interface *);
+-
+-	/* cleanup device ... can sleep, but can't fail */
+-	void	(*unbind)(struct usbnet *, struct usb_interface *);
+-
+-	/* reset device ... can sleep */
+-	int	(*reset)(struct usbnet *);
+-
+-	/* see if peer is connected ... can sleep */
+-	int	(*check_connect)(struct usbnet *);
+-
+-	/* for status polling */
+-	void	(*status)(struct usbnet *, struct urb *);
+-
+-	/* link reset handling, called from defer_kevent */
+-	int	(*link_reset)(struct usbnet *);
+-
+-	/* fixup rx packet (strip framing) */
+-	int	(*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
+-
+-	/* fixup tx packet (add framing) */
+-	struct sk_buff	*(*tx_fixup)(struct usbnet *dev,
+-				struct sk_buff *skb, gfp_t flags);
+-
+-	/* for new devices, use the descriptor-reading code instead */
+-	int		in;		/* rx endpoint */
+-	int		out;		/* tx endpoint */
+-
+-	unsigned long	data;		/* Misc driver specific data */
+-};
+-
+-/* Minidrivers are just drivers using the "usbnet" core as a powerful
+- * network-specific subroutine library ... that happens to do pretty
+- * much everything except custom framing and chip-specific stuff.
+- */
+-extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
+-extern int usbnet_suspend (struct usb_interface *, pm_message_t );
+-extern int usbnet_resume (struct usb_interface *);
+-extern void usbnet_disconnect(struct usb_interface *);
+-
+-
+-/* Drivers that reuse some of the standard USB CDC infrastructure
+- * (notably, using multiple interfaces according to the CDC
+- * union descriptor) get some helper code.
+- */
+-struct cdc_state {
+-	struct usb_cdc_header_desc	*header;
+-	struct usb_cdc_union_desc	*u;
+-	struct usb_cdc_ether_desc	*ether;
+-	struct usb_interface		*control;
+-	struct usb_interface		*data;
+-};
+-
+-extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
+-extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
+-
+-/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
+-#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
+-			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+-			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
+-			|USB_CDC_PACKET_TYPE_DIRECTED)
+-
+-
+-/* we record the state for each of our queued skbs */
+-enum skb_state {
+-	illegal = 0,
+-	tx_start, tx_done,
+-	rx_start, rx_done, rx_cleanup
+-};
+-
+-struct skb_data {	/* skb->cb is one of these */
+-	struct urb		*urb;
+-	struct usbnet		*dev;
+-	enum skb_state		state;
+-	size_t			length;
+-};
+-
+-
+-extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
+-extern void usbnet_defer_kevent (struct usbnet *, int);
+-extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
+-extern void usbnet_unlink_rx_urbs(struct usbnet *);
+-
+-extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
+-extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
+-extern u32 usbnet_get_link (struct net_device *net);
+-extern u32 usbnet_get_msglevel (struct net_device *);
+-extern void usbnet_set_msglevel (struct net_device *, u32);
+-extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
+-extern int usbnet_nway_reset(struct net_device *net);
+-
+-/* messaging support includes the interface name, so it must not be
+- * used before it has one ... notably, in minidriver bind() calls.
+- */
+-#ifdef DEBUG
+-#define devdbg(usbnet, fmt, arg...) \
+-	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+-#else
+-#define devdbg(usbnet, fmt, arg...) do {} while(0)
+-#endif
+-
+-#define deverr(usbnet, fmt, arg...) \
+-	printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+-#define devwarn(usbnet, fmt, arg...) \
+-	printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+-
+-#define devinfo(usbnet, fmt, arg...) \
+-	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
+-
+-
+-#endif	/* __USBNET_H */
+diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c
+index 9f98e8c..e24f7b3 100644
+--- a/drivers/net/usb/zaurus.c
++++ b/drivers/net/usb/zaurus.c
+@@ -29,8 +29,7 @@
+ #include <linux/crc32.h>
+ #include <linux/usb.h>
+ #include <linux/usb/cdc.h>
+-
+-#include "usbnet.h"
++#include <linux/usb/usbnet.h>
+ 
+ 
+ /*
 diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
 index 07263cd..87c180b 100644
 --- a/drivers/net/via-rhine.c
@@ -546178,13 +566046,41 @@
  		wanxl_pci_remove_one(pdev);
  		return -ENODEV;
 diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
-index 2c08c0a..f372960 100644
+index 2c08c0a..714a6ca 100644
 --- a/drivers/net/wireless/Kconfig
 +++ b/drivers/net/wireless/Kconfig
-@@ -545,6 +545,62 @@ config USB_ZD1201
+@@ -545,6 +545,90 @@ config USB_ZD1201
  	  To compile this driver as a module, choose M here: the
  	  module will be called zd1201.
  
++config USB_NET_RNDIS_WLAN
++	tristate "Wireless RNDIS USB support"
++	depends on USB && WLAN_80211 && EXPERIMENTAL
++	select USB_USBNET
++	select USB_NET_CDCETHER
++	select USB_NET_RNDIS_HOST
++	select WIRELESS_EXT
++	---help---
++	  This is a driver for wireless RNDIS devices.
++	  These are USB based adapters found in devices such as:
++
++	  Buffalo WLI-U2-KG125S
++	  U.S. Robotics USR5421
++	  Belkin F5D7051
++	  Linksys WUSB54GSv2
++	  Linksys WUSB54GSC
++	  Asus WL169gE
++	  Eminent EM4045
++	  BT Voyager 1055
++	  Linksys WUSB54GSv1
++	  U.S. Robotics USR5420
++	  BUFFALO WLI-USB-G54
++
++	  All of these devices are based on Broadcom 4320 chip which is the
++	  only wireless RNDIS chip known to date.
++
++	  If you choose to build a module, it'll be called rndis_wlan.
++
 +config RTL8180
 +	tristate "Realtek 8180/8185 PCI support"
 +	depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
@@ -546244,7 +566140,7 @@
  config RTL8187
  	tristate "Realtek 8187 USB support"
  	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
-@@ -648,6 +704,23 @@ config P54_PCI
+@@ -648,6 +732,23 @@ config P54_PCI
  
  	  If you choose to build a module, it'll be called p54pci.
  
@@ -546269,10 +566165,15 @@
  source "drivers/net/wireless/hostap/Kconfig"
  source "drivers/net/wireless/bcm43xx/Kconfig"
 diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
-index 6f32b53..6af7b15 100644
+index 6f32b53..091dfe2 100644
 --- a/drivers/net/wireless/Makefile
 +++ b/drivers/net/wireless/Makefile
-@@ -47,14 +47,20 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
+@@ -44,17 +44,25 @@ obj-$(CONFIG_ZD1211RW)		+= zd1211rw/
+ obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
+ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
+ 
++obj-$(CONFIG_USB_NET_RNDIS_WLAN)	+= rndis_wlan.o
++
  obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
  obj-$(CONFIG_LIBERTAS)		+= libertas/
  
@@ -550074,7 +569975,7 @@
 +#endif
 diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
 new file mode 100644
-index 0000000..72bcf32
+index 0000000..d6599d2
 --- /dev/null
 +++ b/drivers/net/wireless/ath5k/base.c
 @@ -0,0 +1,2974 @@
@@ -552060,7 +571961,7 @@
 +	struct ath5k_buf *bf = sc->bbuf;
 +	struct ath5k_hw *ah = sc->ah;
 +
-+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n");
++	ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 +
 +	if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
 +			sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
@@ -552076,10 +571977,10 @@
 +	 */
 +	if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) {
 +		sc->bmisscount++;
-+		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
 +			"missed %u consecutive beacons\n", sc->bmisscount);
 +		if (sc->bmisscount > 3) {		/* NB: 3 is a guess */
-+			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
 +				"stuck beacon time (%u missed)\n",
 +				sc->bmisscount);
 +			tasklet_schedule(&sc->restq);
@@ -552087,7 +571988,7 @@
 +		return;
 +	}
 +	if (unlikely(sc->bmisscount != 0)) {
-+		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
++		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
 +			"resume beacon xmit after %u misses\n",
 +			sc->bmisscount);
 +		sc->bmisscount = 0;
@@ -552107,7 +572008,7 @@
 +
 +	ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
 +	ath5k_hw_tx_start(ah, sc->bhalq);
-+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n",
++	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
 +		sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 +
 +	sc->bsent++;
@@ -553239,12 +573140,12 @@
 +#endif
 diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
 new file mode 100644
-index 0000000..4ba649e
+index 0000000..bb581ef
 --- /dev/null
 +++ b/drivers/net/wireless/ath5k/debug.c
-@@ -0,0 +1,469 @@
+@@ -0,0 +1,551 @@
 +/*
-+ * Copyright (c) 2007 Bruno Randolf <bruno at thinktube.com>
++ * Copyright (c) 2007-2008 Bruno Randolf <bruno at thinktube.com>
 + *
 + *  This file is free software: you may copy, redistribute and/or modify it
 + *  under the terms of the GNU General Public License as published by the
@@ -553445,7 +573346,7 @@
 +{
 +	struct ath5k_softc *sc = file->private_data;
 +	char buf[100];
-+	snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
++	snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
 +	return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
 +}
 +
@@ -553454,7 +573355,12 @@
 +				 size_t count, loff_t *ppos)
 +{
 +	struct ath5k_softc *sc = file->private_data;
-+	if (strncmp(userbuf, "reset", 5) == 0) {
++	char buf[20];
++
++	if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
++		return -EFAULT;
++
++	if (strncmp(buf, "reset", 5) == 0) {
 +		ath5k_hw_reset_tsf(sc->ah);
 +		printk(KERN_INFO "debugfs reset TSF\n");
 +	}
@@ -553476,8 +573382,8 @@
 +{
 +	struct ath5k_softc *sc = file->private_data;
 +	struct ath5k_hw *ah = sc->ah;
-+	char buf[1000];
-+	int len = 0;
++	char buf[500];
++	unsigned int len = 0;
 +	unsigned int v;
 +	u64 tsf;
 +
@@ -553522,11 +573428,15 @@
 +{
 +	struct ath5k_softc *sc = file->private_data;
 +	struct ath5k_hw *ah = sc->ah;
++	char buf[20];
 +
-+	if (strncmp(userbuf, "disable", 7) == 0) {
++	if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
++		return -EFAULT;
++
++	if (strncmp(buf, "disable", 7) == 0) {
 +		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
 +		printk(KERN_INFO "debugfs disable beacons\n");
-+	} else if (strncmp(userbuf, "enable", 6) == 0) {
++	} else if (strncmp(buf, "enable", 6) == 0) {
 +		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
 +		printk(KERN_INFO "debugfs enable beacons\n");
 +	}
@@ -553559,6 +573469,82 @@
 +};
 +
 +
++/* debugfs: debug level */
++
++static struct {
++	enum ath5k_debug_level level;
++	const char *name;
++	const char *desc;
++} dbg_info[] = {
++	{ ATH5K_DEBUG_RESET,	"reset",	"reset and initialization" },
++	{ ATH5K_DEBUG_INTR,	"intr",		"interrupt handling" },
++	{ ATH5K_DEBUG_MODE,	"mode",		"mode init/setup" },
++	{ ATH5K_DEBUG_XMIT,	"xmit",		"basic xmit operation" },
++	{ ATH5K_DEBUG_BEACON,	"beacon",	"beacon handling" },
++	{ ATH5K_DEBUG_CALIBRATE, "calib",	"periodic calibration" },
++	{ ATH5K_DEBUG_TXPOWER,	"txpower",	"transmit power setting" },
++	{ ATH5K_DEBUG_LED,	"led",		"LED mamagement" },
++	{ ATH5K_DEBUG_DUMP_RX,	"dumprx",	"print received skb content" },
++	{ ATH5K_DEBUG_DUMP_TX,	"dumptx",	"print transmit skb content" },
++	{ ATH5K_DEBUG_DUMPMODES, "dumpmodes",	"dump modes" },
++	{ ATH5K_DEBUG_TRACE,	"trace",	"trace function calls" },
++	{ ATH5K_DEBUG_ANY,	"all",		"show all debug levels" },
++};
++
++static ssize_t read_file_debug(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	char buf[700];
++	unsigned int len = 0;
++	unsigned int i;
++
++	len += snprintf(buf+len, sizeof(buf)-len,
++		"DEBUG LEVEL: 0x%08x\n\n", sc->debug.level);
++
++	for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
++		len += snprintf(buf+len, sizeof(buf)-len,
++			"%10s %c 0x%08x - %s\n", dbg_info[i].name,
++			sc->debug.level & dbg_info[i].level ? '+' : ' ',
++			dbg_info[i].level, dbg_info[i].desc);
++	}
++	len += snprintf(buf+len, sizeof(buf)-len,
++		"%10s %c 0x%08x - %s\n", dbg_info[i].name,
++		sc->debug.level == dbg_info[i].level ? '+' : ' ',
++		dbg_info[i].level, dbg_info[i].desc);
++
++	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++}
++
++static ssize_t write_file_debug(struct file *file,
++				 const char __user *userbuf,
++				 size_t count, loff_t *ppos)
++{
++	struct ath5k_softc *sc = file->private_data;
++	unsigned int i;
++	char buf[20];
++
++	if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
++		return -EFAULT;
++
++	for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
++		if (strncmp(buf, dbg_info[i].name,
++					strlen(dbg_info[i].name)) == 0) {
++			sc->debug.level ^= dbg_info[i].level; /* toggle bit */
++			break;
++		}
++	}
++	return count;
++}
++
++static const struct file_operations fops_debug = {
++	.read = read_file_debug,
++	.write = write_file_debug,
++	.open = ath5k_debugfs_open,
++	.owner = THIS_MODULE,
++};
++
++
 +/* init */
 +
 +void
@@ -553571,26 +573557,24 @@
 +ath5k_debug_init_device(struct ath5k_softc *sc)
 +{
 +	sc->debug.level = ath5k_debug;
++
 +	sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
-+			ath5k_global_debugfs);
-+	sc->debug.debugfs_debug = debugfs_create_u32("debug",
-+			0666, sc->debug.debugfs_phydir, &sc->debug.level);
++				ath5k_global_debugfs);
++
++	sc->debug.debugfs_debug = debugfs_create_file("debug", 0666,
++				sc->debug.debugfs_phydir, sc, &fops_debug);
 +
 +	sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
-+				sc->debug.debugfs_phydir,
-+				sc, &fops_registers);
++				sc->debug.debugfs_phydir, sc, &fops_registers);
 +
 +	sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
-+				sc->debug.debugfs_phydir,
-+				sc, &fops_tsf);
++				sc->debug.debugfs_phydir, sc, &fops_tsf);
 +
 +	sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
-+				sc->debug.debugfs_phydir,
-+				sc, &fops_beacon);
++				sc->debug.debugfs_phydir, sc, &fops_beacon);
 +
 +	sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
-+				sc->debug.debugfs_phydir,
-+				sc, &fops_reset);
++				sc->debug.debugfs_phydir, sc, &fops_reset);
 +}
 +
 +void
@@ -553660,8 +573644,7 @@
 +	struct ath5k_buf *bf;
 +	int status;
 +
-+	if (likely(!(sc->debug.level &
-+	    (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
++	if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
 +		return;
 +
 +	printk(KERN_DEBUG "rx queue %x, link %p\n",
@@ -553671,7 +573654,7 @@
 +	list_for_each_entry(bf, &sc->rxbuf, list) {
 +		ds = bf->desc;
 +		status = ah->ah_proc_rx_desc(ah, ds);
-+		if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
++		if (!status)
 +			ath5k_debug_printrxbuf(bf, status == 0);
 +	}
 +	spin_unlock_bh(&sc->rxbuflock);
@@ -553714,10 +573697,10 @@
 +#endif /* if ATH5K_DEBUG */
 diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h
 new file mode 100644
-index 0000000..2b491cb
+index 0000000..c4fd8c4
 --- /dev/null
 +++ b/drivers/net/wireless/ath5k/debug.h
-@@ -0,0 +1,216 @@
+@@ -0,0 +1,212 @@
 +/*
 + * Copyright (c) 2007 Bruno Randolf <bruno at thinktube.com>
 + *
@@ -553811,7 +573794,6 @@
 + * @ATH5K_DEBUG_MODE: mode init/setup
 + * @ATH5K_DEBUG_XMIT: basic xmit operation
 + * @ATH5K_DEBUG_BEACON: beacon handling
-+ * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc
 + * @ATH5K_DEBUG_CALIBRATE: periodic calibration
 + * @ATH5K_DEBUG_TXPOWER: transmit power setting
 + * @ATH5K_DEBUG_LED: led management
@@ -553819,7 +573801,6 @@
 + * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
 + * @ATH5K_DEBUG_DUMPMODES: dump modes
 + * @ATH5K_DEBUG_TRACE: trace function calls
-+ * @ATH5K_DEBUG_FATAL: fatal errors
 + * @ATH5K_DEBUG_ANY: show at any debug level
 + *
 + * The debug level is used to control the amount and type of debugging output
@@ -553835,15 +573816,13 @@
 +	ATH5K_DEBUG_MODE	= 0x00000004,
 +	ATH5K_DEBUG_XMIT	= 0x00000008,
 +	ATH5K_DEBUG_BEACON	= 0x00000010,
-+	ATH5K_DEBUG_BEACON_PROC	= 0x00000020,
-+	ATH5K_DEBUG_CALIBRATE	= 0x00000100,
-+	ATH5K_DEBUG_TXPOWER	= 0x00000200,
-+	ATH5K_DEBUG_LED		= 0x00000400,
-+	ATH5K_DEBUG_DUMP_RX	= 0x00001000,
-+	ATH5K_DEBUG_DUMP_TX	= 0x00002000,
-+	ATH5K_DEBUG_DUMPMODES	= 0x00004000,
-+	ATH5K_DEBUG_TRACE	= 0x00010000,
-+	ATH5K_DEBUG_FATAL	= 0x80000000,
++	ATH5K_DEBUG_CALIBRATE	= 0x00000020,
++	ATH5K_DEBUG_TXPOWER	= 0x00000040,
++	ATH5K_DEBUG_LED		= 0x00000080,
++	ATH5K_DEBUG_DUMP_RX	= 0x00000100,
++	ATH5K_DEBUG_DUMP_TX	= 0x00000200,
++	ATH5K_DEBUG_DUMPMODES	= 0x00000400,
++	ATH5K_DEBUG_TRACE	= 0x00001000,
 +	ATH5K_DEBUG_ANY		= 0xffffffff
 +};
 +
@@ -565485,7 +585464,7 @@
  	const size_t bufsize = 1024 * 128;
  	const size_t buforder = get_order(bufsize);
 diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
-index 5e8f8ac..3e73d2a 100644
+index 5e8f8ac..8a708b7 100644
 --- a/drivers/net/wireless/b43/dma.c
 +++ b/drivers/net/wireless/b43/dma.c
 @@ -37,6 +37,8 @@
@@ -565753,7 +585732,14 @@
  		ring = dma->tx_ring5;
  		break;
  	default:
-@@ -1112,6 +1120,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+@@ -1106,32 +1114,45 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+ {
+ 	const struct b43_dma_ops *ops = ring->ops;
+ 	u8 *header;
+-	int slot;
++	int slot, old_top_slot, old_used_slots;
+ 	int err;
+ 	struct b43_dmadesc_generic *desc;
  	struct b43_dmadesc_meta *meta;
  	struct b43_dmadesc_meta *meta_hdr;
  	struct sk_buff *bounce_skb;
@@ -565762,30 +585748,63 @@
  
  #define SLOTS_PER_PACKET  2
  	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-@@ -1121,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+ 
++	old_top_slot = ring->current_slot;
++	old_used_slots = ring->used_slots;
++
+ 	/* Get a slot for the header. */
+ 	slot = request_slot(ring);
  	desc = ops->idx2desc(ring, slot, &meta_hdr);
  	memset(meta_hdr, 0, sizeof(*meta_hdr));
  
 -	header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
-+	header = &(ring->txhdr_cache[slot * hdrsize]);
-+	cookie = generate_cookie(ring, slot);
- 	b43_generate_txhdr(ring->dev, header,
+-	b43_generate_txhdr(ring->dev, header,
 -			   skb->data, skb->len, ctl,
 -			   generate_cookie(ring, slot));
-+			   skb->data, skb->len, ctl, cookie);
++	header = &(ring->txhdr_cache[slot * hdrsize]);
++	cookie = generate_cookie(ring, slot);
++	err = b43_generate_txhdr(ring->dev, header,
++				 skb->data, skb->len, ctl, cookie);
++	if (unlikely(err)) {
++		ring->current_slot = old_top_slot;
++		ring->used_slots = old_used_slots;
++		return err;
++	}
  
  	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
 -					   sizeof(struct b43_txhdr_fw4), 1);
+-	if (dma_mapping_error(meta_hdr->dmaaddr))
 +					   hdrsize, 1);
- 	if (dma_mapping_error(meta_hdr->dmaaddr))
++	if (dma_mapping_error(meta_hdr->dmaaddr)) {
++		ring->current_slot = old_top_slot;
++		ring->used_slots = old_used_slots;
  		return -EIO;
++	}
  	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
 -			     sizeof(struct b43_txhdr_fw4), 1, 0, 0);
 +			     hdrsize, 1, 0, 0);
  
  	/* Get a slot for the payload. */
  	slot = request_slot(ring);
-@@ -1164,16 +1174,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+@@ -1147,6 +1168,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+ 	if (dma_mapping_error(meta->dmaaddr)) {
+ 		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+ 		if (!bounce_skb) {
++			ring->current_slot = old_top_slot;
++			ring->used_slots = old_used_slots;
+ 			err = -ENOMEM;
+ 			goto out_unmap_hdr;
+ 		}
+@@ -1157,6 +1180,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
+ 		meta->skb = skb;
+ 		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ 		if (dma_mapping_error(meta->dmaaddr)) {
++			ring->current_slot = old_top_slot;
++			ring->used_slots = old_used_slots;
+ 			err = -EIO;
+ 			goto out_free_bounce;
+ 		}
+@@ -1164,16 +1189,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
  
  	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
  
@@ -565811,7 +585830,7 @@
  	return err;
  }
  
-@@ -1202,10 +1218,27 @@ int b43_dma_tx(struct b43_wldev *dev,
+@@ -1202,10 +1233,27 @@ int b43_dma_tx(struct b43_wldev *dev,
  	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
  {
  	struct b43_dmaring *ring;
@@ -565840,7 +585859,21 @@
  	spin_lock_irqsave(&ring->lock, flags);
  	B43_WARN_ON(!ring->tx);
  	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
-@@ -1233,7 +1266,7 @@ int b43_dma_tx(struct b43_wldev *dev,
+@@ -1219,6 +1267,13 @@ int b43_dma_tx(struct b43_wldev *dev,
+ 	B43_WARN_ON(ring->stopped);
+ 
+ 	err = dma_tx_fragment(ring, skb, ctl);
++	if (unlikely(err == -ENOKEY)) {
++		/* Drop this packet, as we don't have the encryption key
++		 * anymore and must not transmit it unencrypted. */
++		dev_kfree_skb_any(skb);
++		err = 0;
++		goto out_unlock;
++	}
+ 	if (unlikely(err)) {
+ 		b43err(dev->wl, "DMA tx mapping failure\n");
+ 		goto out_unlock;
+@@ -1233,7 +1288,7 @@ int b43_dma_tx(struct b43_wldev *dev,
  			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
  		}
  	}
@@ -565849,7 +585882,7 @@
  	spin_unlock_irqrestore(&ring->lock, flags);
  
  	return err;
-@@ -1265,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
+@@ -1265,7 +1320,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
  					 1);
  		else
  			unmap_descbuffer(ring, meta->dmaaddr,
@@ -566174,7 +586207,7 @@
  	}
  	b43_radio_selectchannel(dev, sav->old_channel, 1);
 diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
-index 1c93b4f..88d2c15 100644
+index 1c93b4f..64c154d 100644
 --- a/drivers/net/wireless/b43/main.c
 +++ b/drivers/net/wireless/b43/main.c
 @@ -3,7 +3,7 @@
@@ -566524,19 +586557,19 @@
  	__le16 dur;
  	struct ieee80211_hdr *hdr;
 +	size_t ie_start;
++
++	src_size = dev->wl->current_beacon->len;
++	src_data = (const u8 *)dev->wl->current_beacon->data;
  
 -	B43_WARN_ON(!dev->cached_beacon);
 -	src_size = dev->cached_beacon->len;
 -	src_data = (const u8 *)dev->cached_beacon->data;
-+	src_size = dev->wl->current_beacon->len;
-+	src_data = (const u8 *)dev->wl->current_beacon->data;
- 
--	if (unlikely(src_size < 0x24)) {
--		b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
 +	/* Get the start offset of the variable IEs in the packet. */
 +	ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
 +	B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
-+
+ 
+-	if (unlikely(src_size < 0x24)) {
+-		b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
 +	if (B43_WARN_ON(src_size < ie_start))
  		return NULL;
 -	}
@@ -566609,19 +586642,11 @@
 -}
 -
 -static void b43_update_templates(struct b43_wldev *dev)
-+/* Asynchronously update the packet templates in template RAM.
-+ * Locking: Requires wl->irq_lock to be locked. */
-+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
- {
+-{
 -	u32 status;
 -
 -	B43_WARN_ON(!dev->cached_beacon);
-+	/* This is the top half of the ansynchronous beacon update.
-+	 * The bottom half is the beacon IRQ.
-+	 * Beacon update must be asynchronous to avoid sending an
-+	 * invalid beacon. This can happen for example, if the firmware
-+	 * transmits a beacon while we are updating it. */
- 
+-
 -	b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
 -	b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
 -	b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
@@ -566632,9 +586657,17 @@
 -}
 -
 -static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
--{
++/* Asynchronously update the packet templates in template RAM.
++ * Locking: Requires wl->irq_lock to be locked. */
++static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
+ {
 -	int err;
--
++	/* This is the top half of the ansynchronous beacon update.
++	 * The bottom half is the beacon IRQ.
++	 * Beacon update must be asynchronous to avoid sending an
++	 * invalid beacon. This can happen for example, if the firmware
++	 * transmits a beacon while we are updating it. */
+ 
 -	err = b43_refresh_cached_beacon(dev, beacon);
 -	if (unlikely(err))
 -		return;
@@ -567463,7 +587496,7 @@
 + * "antenna_nr" is the antenna identifier we got from ieee80211. */
 +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
 +				  u8 antenna_nr)
-+{
+ {
 +	u8 antenna_mask;
 +
 +	if (antenna_nr == 0) {
@@ -567486,7 +587519,7 @@
 +}
 +
 +static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
- {
++{
 +	antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
  	switch (antenna) {
  	case 0:		/* default/diversity */
@@ -567661,13 +587694,13 @@
  	case B43_PHYTYPE_G:
 -		if (phy_rev > 8)
 +		if (phy_rev > 9)
- 			unsupported = 1;
- 		break;
++			unsupported = 1;
++		break;
 +#ifdef CONFIG_B43_NPHY
 +	case B43_PHYTYPE_N:
 +		if (phy_rev > 1)
-+			unsupported = 1;
-+		break;
+ 			unsupported = 1;
+ 		break;
 +#endif
  	default:
  		unsupported = 1;
@@ -567857,7 +587890,16 @@
  
  //FIXME
  #if 1
-@@ -3421,8 +3558,8 @@ out:
+@@ -3395,8 +3532,6 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
+ 	b43_bluetooth_coext_enable(dev);
+ 
+ 	ssb_bus_powerup(bus, 1);	/* Enable dynamic PCTL */
+-	memset(wl->bssid, 0, ETH_ALEN);
+-	memset(wl->mac_addr, 0, ETH_ALEN);
+ 	b43_upload_card_macaddress(dev);
+ 	b43_security_init(dev);
+ 	b43_rng_init(wl);
+@@ -3421,8 +3556,8 @@ out:
  	return err;
  }
  
@@ -567868,7 +587910,7 @@
  {
  	struct b43_wl *wl = hw_to_b43_wl(hw);
  	struct b43_wldev *dev;
-@@ -3445,7 +3582,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
+@@ -3445,7 +3580,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
  
  	dev = wl->current_dev;
  	wl->operating = 1;
@@ -567877,7 +587919,7 @@
  	wl->if_type = conf->type;
  	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
  
-@@ -3461,8 +3598,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
+@@ -3461,8 +3596,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
  	return err;
  }
  
@@ -567888,7 +587930,7 @@
  {
  	struct b43_wl *wl = hw_to_b43_wl(hw);
  	struct b43_wldev *dev = wl->current_dev;
-@@ -3473,7 +3610,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
+@@ -3473,7 +3608,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
  	mutex_lock(&wl->mutex);
  
  	B43_WARN_ON(!wl->operating);
@@ -567898,7 +587940,7 @@
  
  	wl->operating = 0;
  
-@@ -3486,7 +3624,7 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
+@@ -3486,12 +3622,21 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
  	mutex_unlock(&wl->mutex);
  }
  
@@ -567907,7 +587949,47 @@
  {
  	struct b43_wl *wl = hw_to_b43_wl(hw);
  	struct b43_wldev *dev = wl->current_dev;
-@@ -3521,7 +3659,7 @@ static int b43_start(struct ieee80211_hw *hw)
+ 	int did_init = 0;
+ 	int err = 0;
++	bool do_rfkill_exit = 0;
++
++	/* Kill all old instance specific information to make sure
++	 * the card won't use it in the short timeframe between start
++	 * and mac80211 reconfiguring it. */
++	memset(wl->bssid, 0, ETH_ALEN);
++	memset(wl->mac_addr, 0, ETH_ALEN);
++	wl->filter_flags = 0;
++	wl->radiotap_enabled = 0;
+ 
+ 	/* First register RFkill.
+ 	 * LEDs that are registered later depend on it. */
+@@ -3501,8 +3646,10 @@ static int b43_start(struct ieee80211_hw *hw)
+ 
+ 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ 		err = b43_wireless_core_init(dev);
+-		if (err)
++		if (err) {
++			do_rfkill_exit = 1;
+ 			goto out_mutex_unlock;
++		}
+ 		did_init = 1;
+ 	}
+ 
+@@ -3511,6 +3658,7 @@ static int b43_start(struct ieee80211_hw *hw)
+ 		if (err) {
+ 			if (did_init)
+ 				b43_wireless_core_exit(dev);
++			do_rfkill_exit = 1;
+ 			goto out_mutex_unlock;
+ 		}
+ 	}
+@@ -3518,10 +3666,13 @@ static int b43_start(struct ieee80211_hw *hw)
+  out_mutex_unlock:
+ 	mutex_unlock(&wl->mutex);
+ 
++	if (do_rfkill_exit)
++		b43_rfkill_exit(dev);
++
  	return err;
  }
  
@@ -567916,7 +587998,7 @@
  {
  	struct b43_wl *wl = hw_to_b43_wl(hw);
  	struct b43_wldev *dev = wl->current_dev;
-@@ -3535,19 +3673,76 @@ static void b43_stop(struct ieee80211_hw *hw)
+@@ -3535,19 +3686,76 @@ static void b43_stop(struct ieee80211_hw *hw)
  	mutex_unlock(&wl->mutex);
  }
  
@@ -568005,7 +588087,7 @@
  };
  
  /* Hard-reset the chip. Do not call this directly.
-@@ -3592,72 +3787,30 @@ static void b43_chip_reset(struct work_struct *work)
+@@ -3592,72 +3800,30 @@ static void b43_chip_reset(struct work_struct *work)
  }
  
  static int b43_setup_modes(struct b43_wldev *dev,
@@ -568096,7 +588178,7 @@
  
  	return 0;
  }
-@@ -3675,7 +3828,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
+@@ -3675,7 +3841,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
  	struct ssb_bus *bus = dev->dev->bus;
  	struct pci_dev *pdev = bus->host_pci;
  	int err;
@@ -568105,7 +588187,7 @@
  	u32 tmp;
  
  	/* Do NOT do any device initialization here.
-@@ -3695,17 +3848,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
+@@ -3695,17 +3861,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
  		u32 tmshigh;
  
  		tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
@@ -568127,7 +588209,7 @@
  	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
  	b43_wireless_core_reset(dev, tmp);
  
-@@ -3717,31 +3865,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
+@@ -3717,31 +3878,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
  	    (pdev->device != 0x4312 &&
  	     pdev->device != 0x4319 && pdev->device != 0x4324)) {
  		/* No multiband support. */
@@ -568172,7 +588254,7 @@
  	if (err)
  		goto err_powerdown;
  
-@@ -3812,8 +3963,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
+@@ -3812,8 +3976,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
  	tasklet_init(&wldev->isr_tasklet,
  		     (void (*)(unsigned long))b43_interrupt_tasklet,
  		     (unsigned long)wldev);
@@ -568181,7 +588263,7 @@
  	INIT_LIST_HEAD(&wldev->list);
  
  	err = b43_wireless_core_attach(wldev);
-@@ -3838,20 +3987,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
+@@ -3838,20 +4000,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
  	/* boardflags workarounds */
  	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
  	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
@@ -568204,7 +588286,7 @@
  }
  
  static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
-@@ -3878,16 +4017,17 @@ static int b43_wireless_init(struct ssb_device *dev)
+@@ -3878,16 +4030,17 @@ static int b43_wireless_init(struct ssb_device *dev)
  	}
  
  	/* fill hw info */
@@ -568226,7 +588308,7 @@
  
  	/* Get and initialize struct b43_wl */
  	wl = hw_to_b43_wl(hw);
-@@ -3895,6 +4035,7 @@ static int b43_wireless_init(struct ssb_device *dev)
+@@ -3895,6 +4048,7 @@ static int b43_wireless_init(struct ssb_device *dev)
  	wl->hw = hw;
  	spin_lock_init(&wl->irq_lock);
  	spin_lock_init(&wl->leds_lock);
@@ -575801,7 +595883,7 @@
 +
 +#endif /* B43_WA_H_ */
 diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
-index 3307ba1..3fc53e8 100644
+index 3307ba1..7caa26e 100644
 --- a/drivers/net/wireless/b43/xmit.c
 +++ b/drivers/net/wireless/b43/xmit.c
 @@ -5,7 +5,7 @@
@@ -575833,12 +595915,12 @@
 -			       const struct ieee80211_tx_control *txctl,
 -			       u16 cookie)
 +/* Generate a TX data header. */
-+void b43_generate_txhdr(struct b43_wldev *dev,
-+			u8 *_txhdr,
-+			const unsigned char *fragment_data,
-+			unsigned int fragment_len,
-+			const struct ieee80211_tx_control *txctl,
-+			u16 cookie)
++int b43_generate_txhdr(struct b43_wldev *dev,
++		       u8 *_txhdr,
++		       const unsigned char *fragment_data,
++		       unsigned int fragment_len,
++		       const struct ieee80211_tx_control *txctl,
++		       u16 cookie)
  {
 +	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
  	const struct b43_phy *phy = &dev->phy;
@@ -575853,7 +595935,22 @@
  								 fragment_len,
  								 fbrate_base100kbps);
  	}
-@@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+@@ -235,29 +237,44 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+ 
+ 		B43_WARN_ON(key_idx >= dev->max_nr_keys);
+ 		key = &(dev->key[key_idx]);
+-		B43_WARN_ON(!key->keyconf);
++
++		if (unlikely(!key->keyconf)) {
++			/* This key is invalid. This might only happen
++			 * in a short timeframe after machine resume before
++			 * we were able to reconfigure keys.
++			 * Drop this packet completely. Do not transmit it
++			 * unencrypted to avoid leaking information. */
++			return -ENOKEY;
++		}
+ 
+ 		/* Hardware appends ICV. */
  		plcp_fragment_len += txctl->icv_len;
  
  		key_idx = b43_kidx_to_fw(dev, key_idx);
@@ -575891,7 +595988,7 @@
  
  	/* Set channel radio code. Note that the micrcode ORs 0x100 to
  	 * this value before comparing it to the value in SHM, if this
-@@ -267,18 +276,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+@@ -267,18 +284,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
  
  	/* PHY TX Control word */
  	if (rate_ofdm)
@@ -575928,7 +596025,7 @@
  		break;
  	default:
  		B43_WARN_ON(1);
-@@ -286,14 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+@@ -286,14 +312,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
  
  	/* MAC control */
  	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
@@ -575949,7 +596046,7 @@
  
  	/* Generate the RTS or CTS-to-self frame */
  	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
-@@ -302,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+@@ -302,6 +330,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
  		struct ieee80211_hdr *hdr;
  		int rts_rate, rts_rate_fb;
  		int rts_rate_ofdm, rts_rate_fb_ofdm;
@@ -575957,7 +596054,7 @@
  
  		rts_rate = txctl->rts_cts_rate;
  		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
-@@ -309,59 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
+@@ -309,59 +338,85 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
  		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
  
  		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
@@ -576069,10 +596166,11 @@
 -{
 -	generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
 -			   fragment_data, fragment_len, txctl, cookie);
++	return 0;
  }
  
  static s8 b43_rssi_postprocess(struct b43_wldev *dev,
-@@ -384,7 +430,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
+@@ -384,7 +439,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
  			else
  				tmp -= 3;
  		} else {
@@ -576081,7 +596179,7 @@
  			    boardflags_lo & B43_BFL_RSSI) {
  				if (in_rssi > 63)
  					in_rssi = 63;
-@@ -488,7 +534,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
+@@ -488,7 +543,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
  	}
  	wlhdr = (struct ieee80211_hdr *)(skb->data);
  	fctl = le16_to_cpu(wlhdr->frame_control);
@@ -576089,7 +596187,7 @@
  
  	if (macstat & B43_RX_MAC_DEC) {
  		unsigned int keyidx;
-@@ -525,7 +570,24 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
+@@ -525,7 +579,24 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
  	else
  		status.rate = b43_plcp_get_bitrate_cck(plcp);
  	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
@@ -576115,7 +596213,7 @@
  
  	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
  	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
-@@ -586,10 +648,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
+@@ -586,10 +657,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
  			dev->wl->ieee_stats.dot11RTSSuccessCount++;
  	}
  
@@ -576127,7 +596225,7 @@
  }
  
  /* Handle TX status report as received through DMA/PIO queues */
-@@ -618,19 +677,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
+@@ -618,19 +686,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
  /* Stop any TX operation on the device (suspend the hardware queues) */
  void b43_tx_suspend(struct b43_wldev *dev)
  {
@@ -576150,10 +596248,10 @@
  
  #if 0
 diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
-index 6dc0793..ca2a2ab 100644
+index 6dc0793..4176503 100644
 --- a/drivers/net/wireless/b43/xmit.h
 +++ b/drivers/net/wireless/b43/xmit.h
-@@ -19,68 +19,160 @@ _b43_declare_plcp_hdr(6);
+@@ -19,74 +19,166 @@ _b43_declare_plcp_hdr(6);
  #undef _b43_declare_plcp_hdr
  
  /* TX header for v4 firmware */
@@ -576307,6 +596405,12 @@
 -#define  B43_TX4_PHY_ANT0		0x0000	/* Use antenna 0 */
 -#define  B43_TX4_PHY_ANT1		0x0100	/* Use antenna 1 */
 -#define  B43_TX4_PHY_ANTLAST	0x0300	/* Use last used antenna */
+-
+-void b43_generate_txhdr(struct b43_wldev *dev,
+-			u8 * txhdr,
+-			const unsigned char *fragment_data,
+-			unsigned int fragment_len,
+-			const struct ieee80211_tx_control *txctl, u16 cookie);
 +#define B43_TXH_PHY_ENC			0x0003 /* Data frame encoding */
 +#define  B43_TXH_PHY_ENC_CCK		0x0000 /* CCK */
 +#define  B43_TXH_PHY_ENC_OFDM		0x0001 /* OFDM */
@@ -576365,9 +596469,15 @@
 +	return 104 + sizeof(struct b43_plcp_hdr6);
 +}
 +
++
++int b43_generate_txhdr(struct b43_wldev *dev,
++		       u8 * txhdr,
++		       const unsigned char *fragment_data,
++		       unsigned int fragment_len,
++		       const struct ieee80211_tx_control *txctl, u16 cookie);
  
- void b43_generate_txhdr(struct b43_wldev *dev,
- 			u8 * txhdr,
+ /* Transmit Status */
+ struct b43_txstatus {
 diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
 index 7e23ec2..6745579 100644
 --- a/drivers/net/wireless/b43legacy/Kconfig
@@ -576432,10 +596542,10 @@
 -		xmit.o \
 -		$(b43legacy-obj-y)
 diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
-index afe145c..93419ad 100644
+index afe145c..c80edd2 100644
 --- a/drivers/net/wireless/b43legacy/b43legacy.h
 +++ b/drivers/net/wireless/b43legacy/b43legacy.h
-@@ -19,6 +19,7 @@
+@@ -19,10 +19,11 @@
  
  #include "debugfs.h"
  #include "leds.h"
@@ -576443,7 +596553,65 @@
  #include "phy.h"
  
  
-@@ -275,6 +276,8 @@
+-#define B43legacy_IRQWAIT_MAX_RETRIES	100
++#define B43legacy_IRQWAIT_MAX_RETRIES	20
+ 
+ #define B43legacy_RX_MAX_SSI		60 /* best guess at max ssi */
+ 
+@@ -39,9 +40,8 @@
+ #define B43legacy_MMIO_DMA4_IRQ_MASK	0x44
+ #define B43legacy_MMIO_DMA5_REASON	0x48
+ #define B43legacy_MMIO_DMA5_IRQ_MASK	0x4C
+-#define B43legacy_MMIO_MACCTL		0x120
+-#define B43legacy_MMIO_STATUS_BITFIELD	0x120
+-#define B43legacy_MMIO_STATUS2_BITFIELD	0x124
++#define B43legacy_MMIO_MACCTL		0x120	/* MAC control */
++#define B43legacy_MMIO_MACCMD		0x124	/* MAC command */
+ #define B43legacy_MMIO_GEN_IRQ_REASON	0x128
+ #define B43legacy_MMIO_GEN_IRQ_MASK	0x12C
+ #define B43legacy_MMIO_RAM_CONTROL	0x130
+@@ -176,31 +176,25 @@
+ #define B43legacy_RADIOCTL_ID		0x01
+ 
+ /* MAC Control bitfield */
++#define B43legacy_MACCTL_ENABLED	0x00000001 /* MAC Enabled */
++#define B43legacy_MACCTL_PSM_RUN	0x00000002 /* Run Microcode */
++#define B43legacy_MACCTL_PSM_JMP0	0x00000004 /* Microcode jump to 0 */
++#define B43legacy_MACCTL_SHM_ENABLED	0x00000100 /* SHM Enabled */
+ #define B43legacy_MACCTL_IHR_ENABLED	0x00000400 /* IHR Region Enabled */
++#define B43legacy_MACCTL_BE		0x00010000 /* Big Endian mode */
+ #define B43legacy_MACCTL_INFRA		0x00020000 /* Infrastructure mode */
+ #define B43legacy_MACCTL_AP		0x00040000 /* AccessPoint mode */
++#define B43legacy_MACCTL_RADIOLOCK	0x00080000 /* Radio lock */
+ #define B43legacy_MACCTL_BEACPROMISC	0x00100000 /* Beacon Promiscuous */
+ #define B43legacy_MACCTL_KEEP_BADPLCP	0x00200000 /* Keep bad PLCP frames */
+ #define B43legacy_MACCTL_KEEP_CTL	0x00400000 /* Keep control frames */
+ #define B43legacy_MACCTL_KEEP_BAD	0x00800000 /* Keep bad frames (FCS) */
+ #define B43legacy_MACCTL_PROMISC	0x01000000 /* Promiscuous mode */
++#define B43legacy_MACCTL_HWPS		0x02000000 /* Hardware Power Saving */
++#define B43legacy_MACCTL_AWAKE		0x04000000 /* Device is awake */
++#define B43legacy_MACCTL_TBTTHOLD	0x10000000 /* TBTT Hold */
+ #define B43legacy_MACCTL_GMODE		0x80000000 /* G Mode */
+ 
+-/* StatusBitField */
+-#define B43legacy_SBF_MAC_ENABLED	0x00000001
+-#define B43legacy_SBF_CORE_READY	0x00000004
+-#define B43legacy_SBF_400		0x00000400 /*FIXME: fix name*/
+-#define B43legacy_SBF_XFER_REG_BYTESWAP	0x00010000
+-#define B43legacy_SBF_MODE_NOTADHOC	0x00020000
+-#define B43legacy_SBF_MODE_AP		0x00040000
+-#define B43legacy_SBF_RADIOREG_LOCK	0x00080000
+-#define B43legacy_SBF_MODE_MONITOR	0x00400000
+-#define B43legacy_SBF_MODE_PROMISC	0x01000000
+-#define B43legacy_SBF_PS1		0x02000000
+-#define B43legacy_SBF_PS2		0x04000000
+-#define B43legacy_SBF_NO_SSID_BCAST	0x08000000
+-#define B43legacy_SBF_TIME_UPDATE	0x10000000
+-
+ /* 802.11 core specific TM State Low flags */
+ #define B43legacy_TMSLOW_GMODE		0x20000000 /* G Mode Enable */
+ #define B43legacy_TMSLOW_PLLREFSEL	0x00200000 /* PLL Freq Ref Select */
+@@ -275,6 +269,8 @@
  #define B43legacy_DEFAULT_SHORT_RETRY_LIMIT	7
  #define B43legacy_DEFAULT_LONG_RETRY_LIMIT	4
  
@@ -576452,7 +596620,7 @@
  /* Max size of a security key */
  #define B43legacy_SEC_KEYSIZE		16
  /* Security algorithms. */
-@@ -412,7 +415,6 @@ struct b43legacy_phy {
+@@ -412,7 +408,6 @@ struct b43legacy_phy {
  	u8 calibrated:1;
  	u8 radio_rev;		/* Radio revision */
  
@@ -576460,7 +596628,7 @@
  	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
  
  	/* ACI (adjacent channel interference) flags. */
-@@ -455,11 +457,6 @@ struct b43legacy_phy {
+@@ -455,11 +450,6 @@ struct b43legacy_phy {
  	s16 lna_gain;		/* LNA */
  	s16 pga_gain;		/* PGA */
  
@@ -576472,7 +596640,7 @@
  	/* Desired TX power level (in dBm). This is set by the user and
  	 * adjusted in b43legacy_phy_xmitpower(). */
  	u8 power_level;
-@@ -483,9 +480,6 @@ struct b43legacy_phy {
+@@ -483,9 +473,6 @@ struct b43legacy_phy {
  		u16 txpwr_offset;
  	};
  
@@ -576482,7 +596650,7 @@
  	/* Current Interference Mitigation mode */
  	int interfmode;
  	/* Stack of saved values from the Interference Mitigation code.
-@@ -510,6 +504,16 @@ struct b43legacy_phy {
+@@ -510,6 +497,16 @@ struct b43legacy_phy {
  	u16 lofcal;
  
  	u16 initval;
@@ -576499,7 +596667,7 @@
  };
  
  /* Data structures for DMA transmission, per 80211 core. */
-@@ -571,10 +575,7 @@ struct b43legacy_wl {
+@@ -571,10 +568,7 @@ struct b43legacy_wl {
  	 * at a time. General information about this interface follows.
  	 */
  
@@ -576511,7 +596679,7 @@
  	/* MAC address (can be NULL). */
  	u8 mac_addr[ETH_ALEN];
  	/* Current BSSID (can be NULL). */
-@@ -592,9 +593,14 @@ struct b43legacy_wl {
+@@ -592,9 +586,14 @@ struct b43legacy_wl {
  	u8 rng_initialized;
  	char rng_name[30 + 1];
  
@@ -576526,7 +596694,7 @@
  };
  
  /* Pointers to the firmware data and meta information about it. */
-@@ -663,8 +669,11 @@ struct b43legacy_wldev {
+@@ -663,8 +662,11 @@ struct b43legacy_wldev {
  	/* Various statistics about the physical device. */
  	struct b43legacy_stats stats;
  
@@ -577129,7 +597297,7 @@
  
  #endif /* B43legacy_LEDS_H_ */
 diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
-index 32d5e17..4ed4243 100644
+index 32d5e17..aa20d5d 100644
 --- a/drivers/net/wireless/b43legacy/main.c
 +++ b/drivers/net/wireless/b43legacy/main.c
 @@ -3,7 +3,7 @@
@@ -577160,6 +597328,75 @@
  static char modparam_fwpostfix[16];
  module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
  MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
+@@ -237,8 +225,8 @@ static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
+ 
+ 	B43legacy_WARN_ON(offset % 4 != 0);
+ 
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	if (status & B43legacy_MACCTL_BE)
+ 		val = swab32(val);
+ 
+ 	b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
+@@ -446,9 +434,9 @@ static void b43legacy_time_lock(struct b43legacy_wldev *dev)
+ {
+ 	u32 status;
+ 
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	status |= B43legacy_SBF_TIME_UPDATE;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	status |= B43legacy_MACCTL_TBTTHOLD;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
+ 	mmiowb();
+ }
+ 
+@@ -456,9 +444,9 @@ static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
+ {
+ 	u32 status;
+ 
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	status &= ~B43legacy_SBF_TIME_UPDATE;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	status &= ~B43legacy_MACCTL_TBTTHOLD;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
+ }
+ 
+ static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
+@@ -659,7 +647,7 @@ void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
+ 		b43legacy_ram_write(dev, i * 4, buffer[i]);
+ 
+ 	/* dummy read follows */
+-	b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
++	b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ 
+ 	b43legacy_write16(dev, 0x0568, 0x0000);
+ 	b43legacy_write16(dev, 0x07C0, 0x0000);
+@@ -806,9 +794,9 @@ static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
+ static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
+ {
+ 	b43legacy_jssi_write(dev, 0x7F7F7F7F);
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
++	b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+ 			  b43legacy_read32(dev,
+-			  B43legacy_MMIO_STATUS2_BITFIELD)
++			  B43legacy_MMIO_MACCMD)
+ 			  | (1 << 4));
+ 	B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
+ 			    dev->phy.channel);
+@@ -907,8 +895,8 @@ static void handle_irq_atim_end(struct b43legacy_wldev *dev)
+ {
+ 	if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
+ 		return;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+-			  b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
++	b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
++			  b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
+ 			  | 0x4);
+ }
+ 
 @@ -988,7 +976,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
  	plcp.data = 0;
  	b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
@@ -577178,6 +597415,44 @@
  					       *dest_size,
  					       B43legacy_RATE_TO_100KBPS(rate));
  	hdr->duration_id = dur;
+@@ -1118,9 +1106,9 @@ static void b43legacy_update_templates(struct b43legacy_wldev *dev)
+ 	b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+ 					    B43legacy_CCK_RATE_11MB);
+ 
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ 	status |= 0x03;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
++	b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status);
+ }
+ 
+ static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
+@@ -1178,7 +1166,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
+ 		return;
+ 
+ 	dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
+ 
+ 	if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+ 		/* ACK beacon IRQ. */
+@@ -1194,14 +1182,14 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
+ 		b43legacy_write_beacon_template(dev, 0x68, 0x18,
+ 						B43legacy_CCK_RATE_1MB);
+ 		status |= 0x1;
+-		b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
++		b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+ 				  status);
+ 	}
+ 	if (!(status & 0x2)) {
+ 		b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+ 						B43legacy_CCK_RATE_1MB);
+ 		status |= 0x2;
+-		b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
++		b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+ 				  status);
+ 	}
+ }
 @@ -1217,7 +1205,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
  	u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
  	u32 merged_dma_reason = 0;
@@ -577233,15 +597508,101 @@
  	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
  	mmiowb();
  	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-@@ -1755,7 +1741,6 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
- 			  B43legacy_MMIO_STATUS_BITFIELD)
+@@ -1562,9 +1548,20 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+ 	u16 fwpatch;
+ 	u16 fwdate;
+ 	u16 fwtime;
+-	u32 tmp;
++	u32 tmp, macctl;
+ 	int err = 0;
+ 
++	/* Jump the microcode PSM to offset 0 */
++	macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	B43legacy_WARN_ON(macctl & B43legacy_MACCTL_PSM_RUN);
++	macctl |= B43legacy_MACCTL_PSM_JMP0;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
++	/* Zero out all microcode PSM registers and shared memory. */
++	for (i = 0; i < 64; i++)
++		b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, i, 0);
++	for (i = 0; i < 4096; i += 2)
++		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, i, 0);
++
+ 	/* Upload Microcode. */
+ 	data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+ 	len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+@@ -1595,7 +1592,12 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+ 
+ 	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ 			  B43legacy_IRQ_ALL);
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
++
++	/* Start the microcode PSM */
++	macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	macctl &= ~B43legacy_MACCTL_PSM_JMP0;
++	macctl |= B43legacy_MACCTL_PSM_RUN;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+ 
+ 	/* Wait for the microcode to load and respond */
+ 	i = 0;
+@@ -1608,9 +1610,13 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+ 			b43legacyerr(dev->wl, "Microcode not responding\n");
+ 			b43legacy_print_fw_helptext(dev->wl);
+ 			err = -ENODEV;
+-			goto out;
++			goto error;
++		}
++		msleep_interruptible(50);
++		if (signal_pending(current)) {
++			err = -EINTR;
++			goto error;
+ 		}
+-		udelay(10);
+ 	}
+ 	/* dummy read follows */
+ 	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+@@ -1631,9 +1637,8 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+ 			     " is supported. You must change your firmware"
+ 			     " files.\n");
+ 		b43legacy_print_fw_helptext(dev->wl);
+-		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
+ 		err = -EOPNOTSUPP;
+-		goto out;
++		goto error;
+ 	}
+ 	b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
+ 	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+@@ -1643,7 +1648,14 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+ 	dev->fw.rev = fwrev;
+ 	dev->fw.patch = fwpatch;
+ 
+-out:
++	return 0;
++
++error:
++	macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	macctl &= ~B43legacy_MACCTL_PSM_RUN;
++	macctl |= B43legacy_MACCTL_PSM_JMP0;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
++
+ 	return err;
+ }
+ 
+@@ -1750,12 +1762,11 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
+ 	u32 mask;
+ 	u32 set;
+ 
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
+ 			  b43legacy_read32(dev,
+-			  B43legacy_MMIO_STATUS_BITFIELD)
++			  B43legacy_MMIO_MACCTL)
  			  & 0xFFFF3FFF);
  
 -	b43legacy_leds_switch_all(dev, 0);
  	b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
  			  b43legacy_read16(dev,
  			  B43legacy_MMIO_GPIO_MASK)
-@@ -1767,7 +1752,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
+@@ -1767,7 +1778,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
  		mask |= 0x0060;
  		set |= 0x0060;
  	}
@@ -577250,16 +597611,24 @@
  		b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
  				  b43legacy_read16(dev,
  				  B43legacy_MMIO_GPIO_MASK)
-@@ -1811,6 +1796,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
+@@ -1811,17 +1822,23 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
  {
  	dev->mac_suspended--;
  	B43legacy_WARN_ON(dev->mac_suspended < 0);
 +	B43legacy_WARN_ON(irqs_disabled());
  	if (dev->mac_suspended == 0) {
- 		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+-		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
++		b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
  				  b43legacy_read32(dev,
-@@ -1822,6 +1808,11 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
- 		b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-				  B43legacy_MMIO_STATUS_BITFIELD)
+-				  | B43legacy_SBF_MAC_ENABLED);
++				  B43legacy_MMIO_MACCTL)
++				  | B43legacy_MACCTL_ENABLED);
+ 		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ 				  B43legacy_IRQ_MAC_SUSPENDED);
+ 		/* the next two are dummy reads */
+-		b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
++		b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
  		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
  		b43legacy_power_saving_ctl_bits(dev, -1, -1);
 +
@@ -577270,7 +597639,7 @@
  	}
  }
  
-@@ -1831,20 +1822,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
+@@ -1831,20 +1848,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
  	int i;
  	u32 tmp;
  
@@ -577288,10 +597657,13 @@
 +		dev->irq_savedstate = tmp;
 +
  		b43legacy_power_saving_ctl_bits(dev, -1, 1);
- 		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+-		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
++		b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
  				  b43legacy_read32(dev,
- 				  B43legacy_MMIO_STATUS_BITFIELD)
- 				  & ~B43legacy_SBF_MAC_ENABLED);
+-				  B43legacy_MMIO_STATUS_BITFIELD)
+-				  & ~B43legacy_SBF_MAC_ENABLED);
++				  B43legacy_MMIO_MACCTL)
++				  & ~B43legacy_MACCTL_ENABLED);
  		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
 -		for (i = 10000; i; i--) {
 +		for (i = 40; i; i--) {
@@ -577304,7 +597676,7 @@
  		}
  		b43legacyerr(dev->wl, "MAC suspend failed\n");
  	}
-@@ -1989,27 +1991,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
+@@ -1989,27 +2017,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
  			      B43legacy_SHM_SH_PRPHYCTL, tmp);
  }
  
@@ -577333,7 +597705,27 @@
  	b43legacy_gpio_cleanup(dev);
  	/* firmware is released later */
  }
-@@ -2039,9 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+@@ -2022,12 +2033,15 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+ 	struct b43legacy_phy *phy = &dev->phy;
+ 	int err;
+ 	int tmp;
+-	u32 value32;
++	u32 value32, macctl;
+ 	u16 value16;
+ 
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+-			  B43legacy_SBF_CORE_READY
+-			  | B43legacy_SBF_400);
++	/* Initialize the MAC control */
++	macctl = B43legacy_MACCTL_IHR_ENABLED | B43legacy_MACCTL_SHM_ENABLED;
++	if (dev->phy.gmode)
++		macctl |= B43legacy_MACCTL_GMODE;
++	macctl |= B43legacy_MACCTL_INFRA;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+ 
+ 	err = b43legacy_request_firmware(dev);
+ 	if (err)
+@@ -2039,9 +2053,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
  	err = b43legacy_gpio_init(dev);
  	if (err)
  		goto out; /* firmware is released later */
@@ -577345,7 +597737,26 @@
  	b43legacy_radio_turn_on(dev);
  
  	b43legacy_write16(dev, 0x03E6, 0x0000);
-@@ -2113,14 +2099,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+@@ -2066,12 +2081,12 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+ 	if (dev->dev->id.revision < 5)
+ 		b43legacy_write32(dev, 0x010C, 0x01000000);
+ 
+-	value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+-	value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	value32 |= B43legacy_SBF_MODE_NOTADHOC;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
++	value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	value32 &= ~B43legacy_MACCTL_INFRA;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
++	value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	value32 |= B43legacy_MACCTL_INFRA;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
+ 
+ 	if (b43legacy_using_pio(dev)) {
+ 		b43legacy_write32(dev, 0x0210, 0x00000100);
+@@ -2113,14 +2128,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
  	b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
  			  dev->dev->bus->chipco.fast_pwrup_delay);
  
@@ -577365,7 +597776,7 @@
  	b43legacy_gpio_cleanup(dev);
  	goto out;
  }
-@@ -2140,7 +2129,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
+@@ -2140,7 +2158,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
  static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
  {
  	b43legacy_phy_lo_mark_all_unused(dev);
@@ -577374,7 +597785,7 @@
  		b43legacy_mac_suspend(dev);
  		b43legacy_calc_nrssi_slope(dev);
  		b43legacy_mac_enable(dev);
-@@ -2156,20 +2145,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
+@@ -2156,20 +2174,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
  static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
  {
  	b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
@@ -577397,7 +597808,7 @@
  }
  
  static void do_periodic_work(struct b43legacy_wldev *dev)
-@@ -2177,94 +2155,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
+@@ -2177,94 +2184,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
  	unsigned int state;
  
  	state = dev->periodic_state;
@@ -577474,10 +597885,10 @@
 -		 * be preemtible and release the spinlock. */
 -		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 -		b43legacy_synchronize_irq(dev);
--
--		do_periodic_work(dev);
 +	do_periodic_work(dev);
  
+-		do_periodic_work(dev);
+-
 -		spin_lock_irqsave(&dev->wl->irq_lock, flags);
 -		b43legacy_interrupt_enable(dev, savedirqs);
 -		b43legacy_tx_resume(dev);
@@ -577508,7 +597919,7 @@
  }
  
  static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
-@@ -2366,9 +2295,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
+@@ -2366,9 +2324,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
  	return err;
  }
  
@@ -577521,7 +597932,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev = wl->current_dev;
-@@ -2392,15 +2321,15 @@ out:
+@@ -2392,15 +2350,15 @@ out:
  	return NETDEV_TX_OK;
  }
  
@@ -577542,7 +597953,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev = wl->current_dev;
-@@ -2422,8 +2351,8 @@ out:
+@@ -2422,8 +2380,8 @@ out:
  	return err;
  }
  
@@ -577553,7 +597964,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	unsigned long flags;
-@@ -2572,8 +2501,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna)
+@@ -2572,8 +2530,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna)
  	}
  }
  
@@ -577564,7 +597975,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev;
-@@ -2634,6 +2563,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
+@@ -2634,6 +2592,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
  			b43legacy_short_slot_timing_disable(dev);
  	}
  
@@ -577573,7 +597984,7 @@
  	/* Adjust the desired TX power level. */
  	if (conf->power_level != 0) {
  		if (conf->power_level != phy->power_level) {
-@@ -2660,7 +2591,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
+@@ -2660,7 +2620,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
  					      " physically off. Press the"
  					      " button to turn it on.\n");
  		} else {
@@ -577582,7 +597993,7 @@
  			b43legacyinfo(dev->wl, "Radio turned off by"
  				      " software\n");
  		}
-@@ -2676,37 +2607,11 @@ out_unlock_mutex:
+@@ -2676,37 +2636,11 @@ out_unlock_mutex:
  	return err;
  }
  
@@ -577625,7 +598036,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev = wl->current_dev;
-@@ -2741,9 +2646,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+@@ -2741,9 +2675,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw,
  	spin_unlock_irqrestore(&wl->irq_lock, flags);
  }
  
@@ -577638,7 +598049,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev = wl->current_dev;
-@@ -2753,7 +2658,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw,
+@@ -2753,7 +2687,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw,
  		return -ENODEV;
  	mutex_lock(&wl->mutex);
  	spin_lock_irqsave(&wl->irq_lock, flags);
@@ -577647,7 +598058,7 @@
  	if (conf->bssid)
  		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
  	else
-@@ -2942,8 +2847,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
+@@ -2942,8 +2876,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
  	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
  	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
  
@@ -577656,7 +598067,7 @@
  	/* Assume the radio is enabled. If it's not enabled, the state will
  	 * immediately get fixed on the first periodic work run. */
  	dev->radio_hw_enable = 1;
-@@ -2976,7 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
+@@ -2976,7 +2908,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
  	phy->lofcal = 0xFFFF;
  	phy->initval = 0xFFFF;
  
@@ -577664,7 +598075,7 @@
  	phy->interfmode = B43legacy_INTERFMODE_NONE;
  	phy->channel = 0xFF;
  }
-@@ -3029,6 +2931,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
+@@ -3029,29 +2960,51 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
  #endif /* CONFIG_SSB_DRIVER_PCICORE */
  }
  
@@ -577685,7 +598096,25 @@
  /* Shutdown a wireless core */
  /* Locking: wl->mutex */
  static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
-@@ -3047,11 +2963,12 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
+ {
+ 	struct b43legacy_wl *wl = dev->wl;
+ 	struct b43legacy_phy *phy = &dev->phy;
++	u32 macctl;
+ 
+ 	B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
+ 	if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
+ 		return;
+ 	b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
+ 
++	/* Stop the microcode PSM. */
++	macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	macctl &= ~B43legacy_MACCTL_PSM_RUN;
++	macctl |= B43legacy_MACCTL_PSM_JMP0;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
++
+ 	mutex_unlock(&wl->mutex);
+ 	/* Must unlock as it would otherwise deadlock. No races here.
+ 	 * Cancel possibly pending workqueues. */
  	cancel_work_sync(&dev->restart_work);
  	mutex_lock(&wl->mutex);
  
@@ -577699,7 +598128,7 @@
  	b43legacy_switch_analog(dev, 0);
  	if (phy->dyn_tssi_tbl)
  		kfree(phy->tssi2dbm);
-@@ -3093,7 +3010,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
+@@ -3093,7 +3046,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
  
  	/* Flags */
  	phy->calibrated = 0;
@@ -577707,7 +598136,7 @@
  
  	if (phy->_lo_pairs)
  		memset(phy->_lo_pairs, 0,
-@@ -3153,7 +3069,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+@@ -3153,7 +3105,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
  		hf |= B43legacy_HF_SYMW;
  		if (phy->rev == 1)
  			hf |= B43legacy_HF_GDCW;
@@ -577716,7 +598145,7 @@
  			hf |= B43legacy_HF_OFDMPABOOST;
  	} else if (phy->type == B43legacy_PHYTYPE_B) {
  		hf |= B43legacy_HF_SYMW;
-@@ -3162,16 +3078,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+@@ -3162,16 +3114,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
  	}
  	b43legacy_hf_write(dev, hf);
  
@@ -577736,7 +598165,7 @@
  
  	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
  			      0x0044, 3);
-@@ -3223,6 +3132,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+@@ -3223,6 +3168,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
  
  	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
  
@@ -577744,7 +598173,7 @@
  out:
  	return err;
  
-@@ -3239,8 +3149,8 @@ err_kfree_lo_control:
+@@ -3239,8 +3185,8 @@ err_kfree_lo_control:
  	return err;
  }
  
@@ -577755,7 +598184,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev;
-@@ -3263,7 +3173,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
+@@ -3263,7 +3209,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
  
  	dev = wl->current_dev;
  	wl->operating = 1;
@@ -577764,7 +598193,7 @@
  	wl->if_type = conf->type;
  	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
  
-@@ -3279,8 +3189,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
+@@ -3279,8 +3225,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
  	return err;
  }
  
@@ -577775,7 +598204,7 @@
  {
  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
  	struct b43legacy_wldev *dev = wl->current_dev;
-@@ -3291,7 +3201,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+@@ -3291,7 +3237,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
  	mutex_lock(&wl->mutex);
  
  	B43legacy_WARN_ON(!wl->operating);
@@ -577785,7 +598214,7 @@
  
  	wl->operating = 0;
  
-@@ -3304,13 +3215,17 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+@@ -3304,19 +3251,26 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
  	mutex_unlock(&wl->mutex);
  }
  
@@ -577796,15 +598225,39 @@
  	struct b43legacy_wldev *dev = wl->current_dev;
  	int did_init = 0;
  	int err = 0;
- 
++	bool do_rfkill_exit = 0;
++
 +	/* First register RFkill.
 +	 * LEDs that are registered later depend on it. */
 +	b43legacy_rfkill_init(dev);
-+
+ 
  	mutex_lock(&wl->mutex);
  
  	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
-@@ -3335,11 +3250,13 @@ out_mutex_unlock:
+ 		err = b43legacy_wireless_core_init(dev);
+-		if (err)
++		if (err) {
++			do_rfkill_exit = 1;
+ 			goto out_mutex_unlock;
++		}
+ 		did_init = 1;
+ 	}
+ 
+@@ -3325,6 +3279,7 @@ static int b43legacy_start(struct ieee80211_hw *hw)
+ 		if (err) {
+ 			if (did_init)
+ 				b43legacy_wireless_core_exit(dev);
++			do_rfkill_exit = 1;
+ 			goto out_mutex_unlock;
+ 		}
+ 	}
+@@ -3332,14 +3287,19 @@ static int b43legacy_start(struct ieee80211_hw *hw)
+ out_mutex_unlock:
+ 	mutex_unlock(&wl->mutex);
+ 
++	if (do_rfkill_exit)
++		b43legacy_rfkill_exit(dev);
++
  	return err;
  }
  
@@ -577819,7 +598272,7 @@
  	mutex_lock(&wl->mutex);
  	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
  		b43legacy_wireless_core_stop(dev);
-@@ -3347,20 +3264,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw)
+@@ -3347,20 +3307,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw)
  	mutex_unlock(&wl->mutex);
  }
  
@@ -577873,7 +598326,7 @@
  };
  
  /* Hard-reset the chip. Do not call this directly.
-@@ -3498,18 +3436,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+@@ -3498,18 +3479,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
  	else
  		have_bphy = 1;
  
@@ -577893,7 +598346,7 @@
  	/* Check if this device supports multiband. */
  	if (!pdev ||
  	    (pdev->device != 0x4312 &&
-@@ -3535,17 +3468,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+@@ -3535,17 +3511,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
  
  	err = b43legacy_validate_chipaccess(dev);
  	if (err)
@@ -577914,7 +598367,7 @@
  	b43legacy_switch_analog(dev, 0);
  	ssb_device_disable(dev->dev, 0);
  	ssb_bus_may_powerdown(bus);
-@@ -3553,8 +3486,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+@@ -3553,8 +3529,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
  out:
  	return err;
  
@@ -577923,7 +598376,7 @@
  err_powerdown:
  	ssb_bus_may_powerdown(bus);
  	return err;
-@@ -3637,12 +3568,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
+@@ -3637,12 +3611,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
  	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
  	    bus->boardinfo.type == 0x4E &&
  	    bus->boardinfo.rev > 0x40)
@@ -577937,7 +598390,7 @@
  }
  
  static void b43legacy_wireless_exit(struct ssb_device *dev,
-@@ -3677,10 +3603,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
+@@ -3677,10 +3646,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
  	hw->max_noise = -110;
  	hw->queues = 1; /* FIXME: hardware has more queues */
  	SET_IEEE80211_DEV(hw, dev->dev);
@@ -577965,7 +598418,7 @@
    Copyright (c) 2005  Danny van Dyk <kugelfang at gentoo.org>
    Copyright (c) 2005  Andreas Jaggi <andreas.jaggi at waterwave.ch>
 diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
-index 491e518..c16febb 100644
+index 491e518..8e5c09b 100644
 --- a/drivers/net/wireless/b43legacy/phy.c
 +++ b/drivers/net/wireless/b43legacy/phy.c
 @@ -3,7 +3,7 @@
@@ -578031,6 +598484,15 @@
  }
  
  u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
+@@ -144,7 +140,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
+ {
+ 	struct b43legacy_phy *phy = &dev->phy;
+ 
+-	b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
++	b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */
+ 	if (phy->calibrated)
+ 		return;
+ 	if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
 @@ -441,7 +437,7 @@ static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
  	might_sleep();
  
@@ -578185,6 +598647,29 @@
  		else
  			phy->idle_tssi = 62;
  		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+@@ -2234,16 +2231,16 @@ bit26 = 1;
+ 		 *	or the latest PS-Poll packet sent was successful,
+ 		 *	set bit26  */
+ 	}
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ 	if (bit25)
+-		status |= B43legacy_SBF_PS1;
++		status |= B43legacy_MACCTL_HWPS;
+ 	else
+-		status &= ~B43legacy_SBF_PS1;
++		status &= ~B43legacy_MACCTL_HWPS;
+ 	if (bit26)
+-		status |= B43legacy_SBF_PS2;
++		status |= B43legacy_MACCTL_AWAKE;
+ 	else
+-		status &= ~B43legacy_SBF_PS2;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
++		status &= ~B43legacy_MACCTL_AWAKE;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
+ 	if (bit26 && dev->dev->id.revision >= 5) {
+ 		for (i = 0; i < 100; i++) {
+ 			if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
 diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
 index f11b427..ecbe409 100644
 --- a/drivers/net/wireless/b43legacy/phy.h
@@ -578219,8 +598704,25 @@
  
  /* Card uses the loopback gain stuff */
  #define has_loopback_gain(phy)			 \
+diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
+index de843ac..e4f4c5c 100644
+--- a/drivers/net/wireless/b43legacy/pio.c
++++ b/drivers/net/wireless/b43legacy/pio.c
+@@ -334,9 +334,9 @@ struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
+ 	tasklet_init(&queue->txtask, tx_tasklet,
+ 		     (unsigned long)queue);
+ 
+-	value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
++	value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	value &= ~B43legacy_MACCTL_BE;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
+ 
+ 	qsize = b43legacy_read16(dev, queue->mmio_base
+ 				 + B43legacy_PIO_TXQBUFSIZE);
 diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
-index a361dee..318a270 100644
+index a361dee..955832e 100644
 --- a/drivers/net/wireless/b43legacy/radio.c
 +++ b/drivers/net/wireless/b43legacy/radio.c
 @@ -3,7 +3,7 @@
@@ -578232,22 +598734,34 @@
  		     Michael Buesch <mbuesch at freenet.de>
  		     Danny van Dyk <kugelfang at gentoo.org>
  		     Andreas Jaggi <andreas.jaggi at waterwave.ch>
-@@ -92,6 +92,7 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev)
+@@ -91,9 +91,10 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev)
+ {
  	u32 status;
  
- 	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-+	B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK);
- 	status |= B43legacy_SBF_RADIOREG_LOCK;
- 	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	status |= B43legacy_SBF_RADIOREG_LOCK;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);
++	status |= B43legacy_MACCTL_RADIOLOCK;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
  	mmiowb();
-@@ -104,6 +105,7 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
+ 	udelay(10);
+ }
+@@ -103,9 +104,10 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
+ 	u32 status;
  
  	b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
- 	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-+	B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK));
- 	status &= ~B43legacy_SBF_RADIOREG_LOCK;
- 	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+-	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+-	status &= ~B43legacy_SBF_RADIOREG_LOCK;
+-	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
++	status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
++	B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
++	status &= ~B43legacy_MACCTL_RADIOLOCK;
++	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
  	mmiowb();
+ }
+ 
 @@ -284,12 +286,11 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
  	unsigned int j;
  	unsigned int start;
@@ -578969,7 +599483,7 @@
  		u32 plen;
  
 diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
-index cc1ee7f..d6b9362 100644
+index cc1ee7f..3694b1e 100644
 --- a/drivers/net/wireless/hostap/hostap_80211.h
 +++ b/drivers/net/wireless/hostap/hostap_80211.h
 @@ -5,52 +5,52 @@
@@ -579042,6 +599556,18 @@
  			/* followed by some of SSID, Supported rates,
  			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
  			u8 variable[0];
+@@ -71,11 +71,6 @@ struct hostap_80211_rx_status {
+ 	u16 rate; /* in 100 kbps */
+ };
+ 
+-
+-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
+-		     struct hostap_80211_rx_status *rx_stats);
+-
+-
+ /* prism2_rx_80211 'type' argument */
+ enum {
+ 	PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
 diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
 index ef084df..49978bd 100644
 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -579384,7 +599910,7 @@
  
  
 diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
-index 877d3bd..0759380 100644
+index 877d3bd..437a9bc 100644
 --- a/drivers/net/wireless/hostap/hostap_cs.c
 +++ b/drivers/net/wireless/hostap/hostap_cs.c
 @@ -845,15 +845,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
@@ -579407,7 +599933,7 @@
  	PCMCIA_DEVICE_PROD_ID123(
  		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
  		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
-@@ -890,10 +888,9 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
+@@ -890,10 +888,12 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
  	PCMCIA_DEVICE_PROD_ID123(
  		"corega", "WL PCCL-11", "ISL37300P",
  		0xa21501a, 0x59868926, 0xc9049a39),
@@ -579417,6 +599943,9 @@
 -		"RevA",
 -		0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194),
 +		0xa5f472c2, 0x9c05598d, 0xc9049a39),
++	PCMCIA_DEVICE_PROD_ID123(
++		"Wireless LAN" , "11Mbps PC Card", "Version 01.02",
++		0x4b8870ff, 0x70e946d1, 0x4b74baa0),
  	PCMCIA_DEVICE_NULL
  };
  MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
@@ -583424,7 +603953,7 @@
 +
 +#endif
 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
-index fb5f064..6e01873 100644
+index fb5f064..571815d 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
 +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
 @@ -8,7 +8,7 @@
@@ -583755,7 +604284,7 @@
 +#define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
 +#define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
 +#define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
-+#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
++#define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */
 +#define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
 +#define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 +#define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
@@ -585512,7 +606041,7 @@
  
  #endif
 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
-index 3a45fe9..76c4ed1 100644
+index 3a45fe9..4fdeb53 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c
 +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
 @@ -35,15 +35,12 @@
@@ -587208,7 +607737,7 @@
  				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
  
  	BUG_ON(frame_size > MAX_MPDU_SIZE);
-@@ -2277,35 +2344,43 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+@@ -2277,35 +2344,29 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
  	tx_beacon_cmd->tx.supp_rates[1] =
  		(IWL_CCK_BASIC_RATES_MASK & 0xF);
  
@@ -587245,28 +607774,18 @@
  };
  
 -inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
-+/*
-+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
-+ * embedded controller) as EEPROM reader; each read is a series of pulses
-+ * to/from the EEPROM chip, not a single event, so even reads could conflict
-+ * if they weren't arbitrated by some ownership mechanism.  Here, the driver
-+ * simply claims ownership, which should be safe when this function is called
-+ * (i.e. before loading uCode!).
-+ */
-+inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
- {
+-{
 -	_iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
-+	_iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
- 	return 0;
- }
- 
+-	return 0;
+-}
+-
 -MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 +MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids);
 diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
-index 813902e..20b925f 100644
+index 813902e..1da14f9 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h
 +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
-@@ -23,19 +23,955 @@
+@@ -23,19 +23,953 @@
   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   *
   *****************************************************************************/
@@ -587925,7 +608444,6 @@
 -extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work);
 -extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
 -extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
-+extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv);
 +extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv);
 +extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv);
 +extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv);
@@ -588045,7 +608563,6 @@
 +	u16 active_rate_basic;
 +
 +	u8 call_post_assoc_from_beacon;
-+	u8 assoc_station_added;
 +	/* Rate scaling data */
 +	s8 data_retry_limit;
 +	u8 retry_rate;
@@ -591045,7 +611562,7 @@
 +
 +#endif
 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
-index 99a19ef..ff71c09 100644
+index 99a19ef..ffe1e9d 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
 +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
 @@ -8,7 +8,7 @@
@@ -591468,7 +611985,7 @@
 +#define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
 +#define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
 +#define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
-+#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
++#define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */
 +#define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
 +#define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 +#define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
@@ -596822,7 +617339,7 @@
  
  #endif
 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
-index 891f90d..04db34b 100644
+index 891f90d..569347f 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c
 +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
 @@ -36,13 +36,13 @@
@@ -600106,26 +620623,24 @@
  				count+1);
  			return rc;
  		}
-@@ -4722,11 +4961,11 @@ int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+@@ -4722,11 +4961,4 @@ int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
  	return rc;
  }
  
 -inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
-+inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
- {
+-{
 -	iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
-+	iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- 		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
- }
- 
- 
+-		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+-}
+-
+-
 -MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 +MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
-index 4c70081..78bc148 100644
+index 4c70081..9cb82be 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h
 +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
-@@ -23,64 +23,777 @@
+@@ -23,64 +23,776 @@
   * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   *
   *****************************************************************************/
@@ -600860,7 +621375,6 @@
 -extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
 -extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv);
 +extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
-+extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv);
  
 -extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
 -					  struct iwl_tx_queue *txq,
@@ -600941,7 +621455,7 @@
  	dma_addr_t dma_addr;
  	void *v_addr;
  	size_t size;
-@@ -120,21 +833,9 @@ struct iwl_kw {
+@@ -120,21 +832,9 @@ struct iwl_kw {
  #define NRG_NUM_PREV_STAT_L     20
  #define NUM_RX_CHAINS           (3)
  
@@ -600965,7 +621479,7 @@
  	unsigned long time_stamp;
  	u32 packet_count[TID_QUEUE_MAX_SIZE];
  	u8 queue_count;
-@@ -142,8 +843,13 @@ struct iwl_traffic_load {
+@@ -142,8 +842,13 @@ struct iwl_traffic_load {
  	u32 total;
  };
  
@@ -600981,7 +621495,7 @@
  	unsigned long next_retry;
  	u32 wait_for_agg_status;
  	u32 tid_retry;
-@@ -152,13 +858,13 @@ struct iwl_agg_control {
+@@ -152,13 +857,13 @@ struct iwl_agg_control {
  	u8 auto_agg;
  	u32 tid_traffic_load_threshold;
  	u32 ba_timeout;
@@ -601000,7 +621514,7 @@
  #endif
  	spinlock_t lock;
  	s32 max_window_size;
-@@ -179,22 +885,6 @@ struct iwl_lq_mngr {
+@@ -179,22 +884,6 @@ struct iwl_lq_mngr {
  #define CAL_NUM_OF_BEACONS		20
  #define MAXIMUM_ALLOWED_PATHLOSS	15
  
@@ -601023,7 +621537,7 @@
  #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
  
  #define MAX_FA_OFDM  50
-@@ -222,8 +912,6 @@ struct iwl_lq_mngr {
+@@ -222,8 +911,6 @@ struct iwl_lq_mngr {
  #define AUTO_CORR_STEP_CCK     3
  #define AUTO_CORR_MAX_TH_CCK   160
  
@@ -601032,7 +621546,7 @@
  #define NRG_DIFF               2
  #define NRG_STEP_CCK           2
  #define NRG_MARGIN             8
-@@ -239,24 +927,24 @@ struct iwl_lq_mngr {
+@@ -239,24 +926,24 @@ struct iwl_lq_mngr {
  #define IN_BAND_FILTER			0xFF
  #define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
  
@@ -601061,7 +621575,7 @@
  	IWL_CALIB_DISABLED = 0,  /* must be 0 */
  	IWL_CALIB_ENABLED = 1,
  };
-@@ -271,7 +959,7 @@ struct statistics_general_data {
+@@ -271,7 +958,7 @@ struct statistics_general_data {
  };
  
  /* Sensitivity calib data */
@@ -601070,7 +621584,7 @@
  	u32 auto_corr_ofdm;
  	u32 auto_corr_ofdm_mrc;
  	u32 auto_corr_ofdm_x1;
-@@ -300,7 +988,7 @@ struct iwl_sensitivity_data {
+@@ -300,7 +987,7 @@ struct iwl_sensitivity_data {
  };
  
  /* Chain noise (differential Rx gain) calib data */
@@ -601079,7 +621593,7 @@
  	u8 state;
  	u16 beacon_count;
  	u32 chain_noise_a;
-@@ -314,28 +1002,323 @@ struct iwl_chain_noise_data {
+@@ -314,28 +1001,323 @@ struct iwl_chain_noise_data {
  	u8 radio_write;
  };
  
@@ -603836,13 +624350,21 @@
 -
 -#endif
 diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
-index e2a8d95..cd2eb18 100644
+index e2a8d95..cb009f4 100644
 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
 +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
-@@ -252,4 +252,27 @@ static inline unsigned long elapsed_jiffies(unsigned long start,
- 	return end + (MAX_JIFFY_OFFSET - start);
- }
+@@ -246,10 +246,33 @@ static inline int iwl_check_bits(unsigned long field, unsigned long mask)
+ static inline unsigned long elapsed_jiffies(unsigned long start,
+ 					    unsigned long end)
+ {
+-	if (end > start)
++	if (end >= start)
+ 		return end - start;
  
+-	return end + (MAX_JIFFY_OFFSET - start);
++	return end + (MAX_JIFFY_OFFSET - start) + 1;
++}
++
 +static inline u8 iwl_get_dma_hi_address(dma_addr_t addr)
 +{
 +	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
@@ -603864,8 +624386,8 @@
 +{
 +	desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
 +	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
-+}
-+
+ }
+ 
  #endif				/* __iwl_helpers_h__ */
 diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
 deleted file mode 100644
@@ -605285,7 +625807,7 @@
 +
  #endif				/* __iwl_prph_h__ */
 diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
-index 0b3ec7e..748ac12 100644
+index 0b3ec7e..33239f1 100644
 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
 +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
 @@ -27,16 +27,6 @@
@@ -606560,7 +627082,7 @@
  
  	return rc;
  }
-@@ -1520,22 +1552,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+@@ -1520,22 +1552,36 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
   *
   ******************************************************************************/
  
@@ -606570,6 +627092,20 @@
  	memcpy(mac, priv->eeprom.mac_address, 6);
  }
  
++/*
++ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
++ * embedded controller) as EEPROM reader; each read is a series of pulses
++ * to/from the EEPROM chip, not a single event, so even reads could conflict
++ * if they weren't arbitrated by some ownership mechanism.  Here, the driver
++ * simply claims ownership, which should be safe when this function is called
++ * (i.e. before loading uCode!).
++ */
++static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
++{
++	_iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
++	return 0;
++}
++
  /**
 - * iwl_eeprom_init - read EEPROM contents
 + * iwl3945_eeprom_init - read EEPROM contents
@@ -606589,7 +627125,7 @@
  	u32 r;
  	int sz = sizeof(priv->eeprom);
  	int rc;
-@@ -1553,20 +1585,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
+@@ -1553,20 +1599,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
  		return -ENOENT;
  	}
  
@@ -606616,7 +627152,7 @@
  			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
  				break;
  			udelay(IWL_EEPROM_ACCESS_DELAY);
-@@ -1576,7 +1609,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
+@@ -1576,7 +1623,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
  			IWL_ERROR("Time out reading EEPROM[%d]", addr);
  			return -ETIMEDOUT;
  		}
@@ -606625,7 +627161,7 @@
  	}
  
  	return 0;
-@@ -1587,22 +1620,17 @@ int iwl_eeprom_init(struct iwl_priv *priv)
+@@ -1587,22 +1634,17 @@ int iwl_eeprom_init(struct iwl_priv *priv)
   * Misc. internal state and helper functions
   *
   ******************************************************************************/
@@ -606653,7 +627189,7 @@
  		      struct ieee80211_hdr *header, int group100)
  {
  	u32 to_us;
-@@ -1624,9 +1652,9 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1624,9 +1666,9 @@ void iwl_report_frame(struct iwl_priv *priv,
  	u8 agc;
  	u16 sig_avg;
  	u16 noise_diff;
@@ -606666,7 +627202,7 @@
  	u8 *data = IWL_RX_DATA(pkt);
  
  	/* MAC header */
-@@ -1702,11 +1730,11 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1702,11 +1744,11 @@ void iwl_report_frame(struct iwl_priv *priv,
  		else
  			title = "Frame";
  
@@ -606680,7 +627216,7 @@
  
  		/* print frame summary.
  		 * MAC addresses show just the last byte (for brevity),
-@@ -1728,25 +1756,25 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1728,25 +1770,25 @@ void iwl_report_frame(struct iwl_priv *priv,
  		}
  	}
  	if (print_dump)
@@ -606711,7 +627247,7 @@
  				    u16 basic_rate, int *left)
  {
  	u16 ret_rates = 0, bit;
-@@ -1757,7 +1785,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+@@ -1757,7 +1799,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
  		if (bit & supported_rate) {
  			ret_rates |= bit;
@@ -606720,7 +627256,7 @@
  				((bit & basic_rate) ? 0x80 : 0x00);
  			(*cnt)++;
  			(*left)--;
-@@ -1771,9 +1799,9 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+@@ -1771,9 +1813,9 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  }
  
  /**
@@ -606732,7 +627268,7 @@
  			      struct ieee80211_mgmt *frame,
  			      int left, int is_direct)
  {
-@@ -1789,9 +1817,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1789,9 +1831,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	len += 24;
  
  	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
@@ -606744,7 +627280,7 @@
  	frame->seq_ctrl = 0;
  
  	/* fill in our indirect SSID IE */
-@@ -1834,11 +1862,11 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1834,11 +1876,11 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
  
  	cck_rates = IWL_CCK_RATES_MASK & active_rates;
@@ -606758,7 +627294,7 @@
  				 priv->active_rate_basic, &left);
  	active_rates &= ~ret_rates;
  
-@@ -1855,7 +1883,7 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1855,7 +1897,7 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	/* ... fill it in... */
  	*pos++ = WLAN_EID_EXT_SUPP_RATES;
  	*pos = 0;
@@ -606767,7 +627303,7 @@
  				 priv->active_rate_basic, &left);
  	if (*pos > 0)
  		len += 2 + *pos;
-@@ -1867,16 +1895,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1867,16 +1909,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  /*
   * QoS  support
  */
@@ -606790,7 +627326,7 @@
  {
  	u16 cw_min = 15;
  	u16 cw_max = 1023;
-@@ -1963,13 +1991,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
+@@ -1963,13 +2005,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -606805,7 +627341,7 @@
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
  		return;
  
-@@ -1990,16 +2015,16 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+@@ -1990,16 +2029,16 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -606825,7 +627361,7 @@
  /*
   * Power management (not Tx power!) functions
   */
-@@ -2017,7 +2042,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+@@ -2017,7 +2056,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
  
  /* default power management (not Tx power) table values */
  /* for tim  0-10 */
@@ -606834,7 +627370,7 @@
  	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
-@@ -2027,7 +2052,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+@@ -2027,7 +2066,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
  };
  
  /* for tim > 10 */
@@ -606843,7 +627379,7 @@
  	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
  		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
-@@ -2040,11 +2065,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+@@ -2040,11 +2079,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
  		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
  };
  
@@ -606858,7 +627394,7 @@
  	u16 pci_pm;
  
  	IWL_DEBUG_POWER("Initialize power \n");
-@@ -2063,7 +2088,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
+@@ -2063,7 +2102,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
  	if (rc != 0)
  		return 0;
  	else {
@@ -606867,7 +627403,7 @@
  
  		IWL_DEBUG_POWER("adjust power command flags\n");
  
-@@ -2079,15 +2104,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
+@@ -2079,15 +2118,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
  	return rc;
  }
  
@@ -606887,7 +627423,7 @@
  
  	if (mode > IWL_POWER_INDEX_5) {
  		IWL_DEBUG_POWER("Error invalid power mode \n");
-@@ -2100,7 +2125,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
+@@ -2100,7 +2139,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
  	else
  		range = &pow_data->pwr_range_1[1];
  
@@ -606896,7 +627432,7 @@
  
  #ifdef IWL_MAC80211_DISABLE
  	if (priv->assoc_network != NULL) {
-@@ -2143,14 +2168,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
+@@ -2143,14 +2182,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
  	return rc;
  }
  
@@ -606915,7 +627451,7 @@
  	 * else user level */
  	switch (mode) {
  	case IWL_POWER_BATTERY:
-@@ -2164,9 +2189,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+@@ -2164,9 +2203,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
  		break;
  	}
  
@@ -606927,7 +627463,7 @@
  
  	if (final_mode == IWL_POWER_MODE_CAM)
  		clear_bit(STATUS_POWER_PMI, &priv->status);
-@@ -2176,7 +2201,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+@@ -2176,7 +2215,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
  	return rc;
  }
  
@@ -606936,7 +627472,7 @@
  {
  	/* Filter incoming packets to determine if they are targeted toward
  	 * this network, discarding packets coming from ourselves */
-@@ -2206,7 +2231,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -2206,7 +2245,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  
  #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
  
@@ -606945,7 +627481,7 @@
  {
  	switch (status & TX_STATUS_MSK) {
  	case TX_STATUS_SUCCESS:
-@@ -2233,11 +2258,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
+@@ -2233,11 +2272,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
  }
  
  /**
@@ -606959,7 +627495,7 @@
  {
  	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
  		clear_bit(STATUS_SCANNING, &priv->status);
-@@ -2260,17 +2285,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
+@@ -2260,17 +2299,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
  }
  
  /**
@@ -606980,7 +627516,7 @@
  	if (ret && ms) {
  		mutex_unlock(&priv->mutex);
  		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
-@@ -2284,7 +2309,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+@@ -2284,7 +2323,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
  	return ret;
  }
  
@@ -606989,7 +627525,7 @@
  {
  	/* Reset ieee stats */
  
-@@ -2295,13 +2320,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
+@@ -2295,13 +2334,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
  	priv->last_frag_num = -1;
  	priv->last_packet_time = 0;
  
@@ -607005,7 +627541,7 @@
  {
  	u16 new_val = 0;
  	u16 beacon_factor = 0;
-@@ -2314,7 +2339,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+@@ -2314,7 +2353,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
  	return cpu_to_le16(new_val);
  }
  
@@ -607014,7 +627550,7 @@
  {
  	u64 interval_tm_unit;
  	u64 tsf, result;
-@@ -2344,14 +2369,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+@@ -2344,14 +2383,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
  			priv->rxon_timing.beacon_interval =
  				cpu_to_le16(beacon_int);
  			priv->rxon_timing.beacon_interval =
@@ -607031,7 +627567,7 @@
  		/* TODO: we need to get atim_window from upper stack
  		 * for now we set to 0 */
  		priv->rxon_timing.atim_window = 0;
-@@ -2370,14 +2395,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+@@ -2370,14 +2409,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
  		le16_to_cpu(priv->rxon_timing.atim_window));
  }
  
@@ -607048,7 +627584,7 @@
  		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
  		return -EIO;
  	}
-@@ -2404,9 +2429,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
+@@ -2404,9 +2443,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
  	return 0;
  }
  
@@ -607060,7 +627596,7 @@
  
  	if (hw_decrypt)
  		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
-@@ -2416,7 +2441,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+@@ -2416,7 +2455,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
  	return 0;
  }
  
@@ -607069,7 +627605,7 @@
  {
  	if (phymode == MODE_IEEE80211A) {
  		priv->staging_rxon.flags &=
-@@ -2424,7 +2449,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+@@ -2424,7 +2463,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
  		      | RXON_FLG_CCK_MSK);
  		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
  	} else {
@@ -607078,7 +627614,7 @@
  		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
  			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
  		else
-@@ -2440,11 +2465,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+@@ -2440,11 +2479,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
  }
  
  /*
@@ -607093,7 +627629,7 @@
  
  	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
  
-@@ -2481,7 +2506,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2481,7 +2520,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
  #endif
  
@@ -607102,7 +627638,7 @@
  				       le16_to_cpu(priv->staging_rxon.channel));
  
  	if (!ch_info)
-@@ -2501,7 +2526,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2501,7 +2540,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  	else
  		priv->phymode = MODE_IEEE80211G;
  
@@ -607111,7 +627647,7 @@
  
  	priv->staging_rxon.ofdm_basic_rates =
  	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-@@ -2509,15 +2534,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2509,15 +2548,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
  }
  
@@ -607130,7 +627666,7 @@
  			priv->phymode,
  			le16_to_cpu(priv->staging_rxon.channel));
  
-@@ -2528,32 +2550,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
+@@ -2528,32 +2564,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
  		}
  	}
  
@@ -607179,7 +627715,7 @@
  
  	switch (keyinfo->alg) {
  	case ALG_CCMP:
-@@ -2596,8 +2622,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+@@ -2596,8 +2636,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
  /*
   * handle build REPLY_TX command notification.
   */
@@ -607190,7 +627726,7 @@
  				  struct ieee80211_tx_control *ctrl,
  				  struct ieee80211_hdr *hdr,
  				  int is_unicast, u8 std_id)
-@@ -2645,11 +2671,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+@@ -2645,11 +2685,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
  	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
  		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
  		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
@@ -607204,7 +627740,7 @@
  	} else
  		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
  
-@@ -2658,41 +2682,44 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+@@ -2658,41 +2696,44 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
  	cmd->cmd.tx.next_frame_len = 0;
  }
  
@@ -607259,7 +627795,7 @@
  
  		if (sta_id != IWL_INVALID_STATION)
  			return sta_id;
-@@ -2700,11 +2727,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+@@ -2700,11 +2741,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
  		IWL_DEBUG_DROP("Station %s not in station map. "
  			       "Defaulting to broadcast...\n",
  			       print_mac(mac, hdr->addr1));
@@ -607273,7 +627809,7 @@
  		return priv->hw_setting.bcast_sta_id;
  	}
  }
-@@ -2712,18 +2739,18 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+@@ -2712,18 +2753,18 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
  /*
   * start REPLY_TX command process
   */
@@ -607297,7 +627833,7 @@
  	u16 len, idx, len_org;
  	u8 id, hdr_len, unicast;
  	u8 sta_id;
-@@ -2735,13 +2762,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2735,13 +2776,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  	int rc;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -607314,7 +627850,7 @@
  		goto drop_unlock;
  	}
  
-@@ -2755,7 +2782,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2755,7 +2796,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  
  	fc = le16_to_cpu(hdr->frame_control);
  
@@ -607323,13 +627859,13 @@
  	if (ieee80211_is_auth(fc))
  		IWL_DEBUG_TX("Sending AUTH frame\n");
  	else if (ieee80211_is_assoc_request(fc))
-@@ -2764,16 +2791,19 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2764,16 +2805,19 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  		IWL_DEBUG_TX("Sending REASSOC frame\n");
  #endif
  
 -	if (!iwl_is_associated(priv) &&
 +	/* drop all data frame if we are not associated */
-+	if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
++	if ((!iwl3945_is_associated(priv) || !priv->assoc_id) &&
  	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
 -		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
 +		IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
@@ -607346,7 +627882,7 @@
  	if (sta_id == IWL_INVALID_STATION) {
  		DECLARE_MAC_BUF(mac);
  
-@@ -2794,32 +2824,54 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2794,32 +2838,54 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
  		seq_number += 0x10;
  	}
@@ -607410,7 +627946,7 @@
  
  	len_org = len;
  	len = (len + 3) & ~3;
-@@ -2829,37 +2881,45 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2829,37 +2895,45 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  	else
  		len_org = 0;
  
@@ -607465,7 +628001,7 @@
  
  	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
  	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
-@@ -2875,25 +2935,26 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2875,25 +2949,26 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  		txq->need_update = 0;
  	}
  
@@ -607498,7 +628034,7 @@
  			spin_unlock_irqrestore(&priv->lock, flags);
  		}
  
-@@ -2908,13 +2969,13 @@ drop:
+@@ -2908,13 +2983,13 @@ drop:
  	return -1;
  }
  
@@ -607514,7 +628050,7 @@
  	if (!hw) {
  		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
  		return;
-@@ -2932,7 +2993,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -2932,7 +3007,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  		if ((rate->val < IWL_RATE_COUNT) &&
  		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
  			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
@@ -607523,7 +628059,7 @@
  				       (rate->flags & IEEE80211_RATE_BASIC) ?
  				       "*" : "");
  			priv->active_rate |= (1 << rate->val);
-@@ -2940,7 +3001,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -2940,7 +3015,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  				priv->active_rate_basic |= (1 << rate->val);
  		} else
  			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
@@ -607532,7 +628068,7 @@
  	}
  
  	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
-@@ -2969,7 +3030,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -2969,7 +3044,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
  }
  
@@ -607541,7 +628077,7 @@
  {
  	unsigned long flags;
  
-@@ -2980,21 +3041,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -2980,21 +3055,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  			  disable_radio ? "OFF" : "ON");
  
  	if (disable_radio) {
@@ -607567,7 +628103,7 @@
  
  	clear_bit(STATUS_RF_KILL_SW, &priv->status);
  	spin_unlock_irqrestore(&priv->lock, flags);
-@@ -3003,9 +3064,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -3003,9 +3078,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  	msleep(10);
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -607580,7 +628116,7 @@
  	spin_unlock_irqrestore(&priv->lock, flags);
  
  	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-@@ -3018,7 +3079,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -3018,7 +3093,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  	return;
  }
  
@@ -607589,7 +628125,7 @@
  			    u32 decrypt_res, struct ieee80211_rx_status *stats)
  {
  	u16 fc =
-@@ -3050,97 +3111,9 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+@@ -3050,97 +3125,9 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
  	}
  }
  
@@ -607688,7 +628224,7 @@
  {
  	u16 sc = le16_to_cpu(header->seq_ctrl);
  	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-@@ -3151,29 +3124,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3151,29 +3138,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  	switch (priv->iw_mode) {
  	case IEEE80211_IF_TYPE_IBSS:{
  		struct list_head *p;
@@ -607722,7 +628258,7 @@
  			return 0;
  		}
  		last_seq = &entry->seq_num;
-@@ -3207,7 +3177,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3207,7 +3191,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  	return 1;
  }
  
@@ -607731,7 +628267,7 @@
  
  #include "iwl-spectrum.h"
  
-@@ -3222,7 +3192,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3222,7 +3206,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
   * the lower 3 bytes is the time in usec within one beacon interval
   */
  
@@ -607740,7 +628276,7 @@
  {
  	u32 quot;
  	u32 rem;
-@@ -3241,7 +3211,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+@@ -3241,7 +3225,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
   * the same as HW timer counter counting down
   */
  
@@ -607749,7 +628285,7 @@
  {
  	u32 base_low = base & BEACON_TIME_MASK_LOW;
  	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
-@@ -3260,13 +3230,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+@@ -3260,13 +3244,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
  	return cpu_to_le32(res);
  }
  
@@ -607767,7 +628303,7 @@
  		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
  		.data = (void *)&spectrum,
  		.meta.flags = CMD_WANT_SKB,
-@@ -3276,9 +3246,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3276,9 +3260,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  	int spectrum_resp_status;
  	int duration = le16_to_cpu(params->duration);
  
@@ -607779,7 +628315,7 @@
  			le64_to_cpu(params->start_time) - priv->last_tsf,
  			le16_to_cpu(priv->rxon_timing.beacon_interval));
  
-@@ -3291,9 +3261,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3291,9 +3275,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  	cmd.len = sizeof(spectrum);
  	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
  
@@ -607791,7 +628327,7 @@
  				add_time,
  				le16_to_cpu(priv->rxon_timing.beacon_interval));
  	else
-@@ -3306,11 +3276,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3306,11 +3290,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
  		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
  
@@ -607805,7 +628341,7 @@
  	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
  		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
  		rc = -EIO;
-@@ -3320,9 +3290,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3320,9 +3304,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  	switch (spectrum_resp_status) {
  	case 0:		/* Command will be handled */
  		if (res->u.spectrum.id != 0xff) {
@@ -607817,7 +628353,7 @@
  			priv->measurement_status &= ~MEASUREMENT_READY;
  		}
  		priv->measurement_status |= MEASUREMENT_ACTIVE;
-@@ -3340,8 +3309,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3340,8 +3323,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  }
  #endif
  
@@ -607828,7 +628364,7 @@
  {
  
  	tx_sta->status.ack_signal = 0;
-@@ -3360,41 +3329,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+@@ -3360,41 +3343,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
  }
  
  /**
@@ -607886,7 +628422,7 @@
  			(txq_id != IWL_CMD_QUEUE_NUM) &&
  			priv->mac80211_registered)
  		ieee80211_wake_queue(priv->hw, txq_id);
-@@ -3403,7 +3372,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+@@ -3403,7 +3386,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
  	return nfreed;
  }
  
@@ -607895,7 +628431,7 @@
  {
  	return (status & 0xFF) == 0x1;
  }
-@@ -3413,27 +3382,30 @@ static int iwl_is_tx_success(u32 status)
+@@ -3413,27 +3396,30 @@ static int iwl_is_tx_success(u32 status)
   * Generic RX handler implementations
   *
   ******************************************************************************/
@@ -607934,7 +628470,7 @@
  
  	tx_status->retry_count = tx_resp->failure_frame;
  	tx_status->queue_number = status;
-@@ -3441,28 +3413,28 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
+@@ -3441,28 +3427,28 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
  	tx_status->queue_length |= tx_resp->failure_rts;
  
  	tx_status->flags =
@@ -607971,7 +628507,7 @@
  	struct delayed_work *pwork;
  
  	palive = &pkt->u.alive_frame;
-@@ -3476,14 +3448,14 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
+@@ -3476,14 +3462,14 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
  		IWL_DEBUG_INFO("Initialization Alive received.\n");
  		memcpy(&priv->card_alive_init,
  		       &pkt->u.alive_frame,
@@ -607989,7 +628525,7 @@
  	}
  
  	/* We delay the ALIVE response by 5ms to
-@@ -3495,19 +3467,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
+@@ -3495,19 +3481,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
  		IWL_WARNING("uCode did not respond OK.\n");
  }
  
@@ -608015,7 +628551,7 @@
  
  	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
  		"seq 0x%04X ser 0x%08X\n",
-@@ -3520,23 +3492,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
+@@ -3520,23 +3506,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
  
  #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
  
@@ -608048,7 +628584,7 @@
  
  	if (!report->state) {
  		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
-@@ -3549,35 +3521,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+@@ -3549,35 +3535,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
  #endif
  }
  
@@ -608097,7 +628633,7 @@
  
  	if (!beacon) {
  		IWL_ERROR("update beacon failed\n");
-@@ -3592,15 +3564,15 @@ static void iwl_bg_beacon_update(struct work_struct *work)
+@@ -3592,15 +3578,15 @@ static void iwl_bg_beacon_update(struct work_struct *work)
  	priv->ibss_beacon = beacon;
  	mutex_unlock(&priv->mutex);
  
@@ -608119,7 +628655,7 @@
  	u8 rate = beacon->beacon_notify_hdr.rate;
  
  	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
-@@ -3618,25 +3590,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+@@ -3618,25 +3604,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
  }
  
  /* Service response to REPLY_SCAN_CMD (0x80) */
@@ -608156,7 +628692,7 @@
  	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
  	IWL_DEBUG_SCAN("Scan start: "
  		       "%d [802.11%s] "
-@@ -3648,12 +3620,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+@@ -3648,12 +3634,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
  }
  
  /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -608174,7 +628710,7 @@
  
  	IWL_DEBUG_SCAN("Scan ch.res: "
  		       "%d [802.11%s] "
-@@ -3669,14 +3641,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+@@ -3669,14 +3655,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
  					(priv->last_scan_jiffies, jiffies)));
  
  	priv->last_scan_jiffies = jiffies;
@@ -608194,7 +628730,7 @@
  
  	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
  		       scan_notif->scanned_channels,
-@@ -3711,6 +3684,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+@@ -3711,6 +3698,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
  	}
  
  	priv->last_scan_jiffies = jiffies;
@@ -608202,7 +628738,7 @@
  	IWL_DEBUG_INFO("Setting scan to off\n");
  
  	clear_bit(STATUS_SCANNING, &priv->status);
-@@ -3729,10 +3703,10 @@ reschedule:
+@@ -3729,10 +3717,10 @@ reschedule:
  
  /* Handle notification from uCode that card's power state is changing
   * due to software, hardware, or critical temperature RFKILL */
@@ -608216,7 +628752,7 @@
  	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
  	unsigned long status = priv->status;
  
-@@ -3740,7 +3714,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -3740,7 +3728,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
  			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
  
@@ -608225,7 +628761,7 @@
  		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
  
  	if (flags & HW_CARD_DISABLED)
-@@ -3754,7 +3728,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -3754,7 +3742,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  	else
  		clear_bit(STATUS_RF_KILL_SW, &priv->status);
  
@@ -608234,7 +628770,7 @@
  
  	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
  	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
-@@ -3766,7 +3740,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -3766,7 +3754,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  }
  
  /**
@@ -608243,7 +628779,7 @@
   *
   * Setup the RX handlers for each of the reply types sent from the uCode
   * to the host.
-@@ -3774,61 +3748,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -3774,61 +3762,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
   * This function chains into the hardware specific files for them to setup
   * any hardware specific handlers as well.
   */
@@ -608334,7 +628870,7 @@
  
  	/* If a Tx command is being handled and it isn't in the actual
  	 * command queue then there a command routing bug has been introduced
-@@ -3849,7 +3820,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -3849,7 +3834,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
  		rxb->skb = NULL;
  
@@ -608343,7 +628879,7 @@
  
  	if (!(cmd->meta.flags & CMD_ASYNC)) {
  		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-@@ -3879,10 +3850,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -3879,10 +3864,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   * The queue is empty (no good data) if WRITE = READ - 1, and is full if
   * WRITE = READ.
   *
@@ -608356,7 +628892,7 @@
   * and fire the RX interrupt.  The driver can then query the READ index and
   * process as many packets as possible, moving the WRITE index forward as it
   * resets the Rx queue buffers with new memory.
-@@ -3890,8 +3861,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -3890,8 +3875,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   * The management in the driver is as follows:
   * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
   *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
@@ -608367,7 +628903,7 @@
   *   iwl->rxq is replenished and the READ INDEX is updated (updating the
   *   'processed' and 'read' driver indexes as well)
   * + A received packet is processed and handed to the kernel network stack,
-@@ -3904,28 +3875,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -3904,28 +3889,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   *
   * Driver sequence:
   *
@@ -608405,7 +628941,7 @@
  {
  	int s = q->read - q->write;
  	if (s <= 0)
-@@ -3938,15 +3909,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+@@ -3938,15 +3923,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
  }
  
  /**
@@ -608423,7 +628959,7 @@
  {
  	u32 reg = 0;
  	int rc = 0;
-@@ -3957,24 +3922,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+@@ -3957,24 +3936,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
  	if (q->need_update == 0)
  		goto exit_unlock;
  
@@ -608459,7 +628995,7 @@
  
  
  	q->need_update = 0;
-@@ -3985,42 +3955,43 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+@@ -3985,42 +3969,43 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
  }
  
  /**
@@ -608516,7 +629052,7 @@
  		rxq->queue[rxq->write] = rxb;
  		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
  		rxq->free_count--;
-@@ -4032,13 +4003,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
+@@ -4032,13 +4017,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
  		queue_work(priv->workqueue, &priv->rx_replenish);
  
  
@@ -608533,7 +629069,7 @@
  		if (rc)
  			return rc;
  	}
-@@ -4047,24 +4019,25 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
+@@ -4047,24 +4033,25 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
  }
  
  /**
@@ -608567,7 +629103,7 @@
  		rxb->skb =
  		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
  		if (!rxb->skb) {
-@@ -4076,8 +4049,19 @@ void iwl_rx_replenish(void *data)
+@@ -4076,8 +4063,19 @@ void iwl_rx_replenish(void *data)
  			 * more buffers it will schedule replenish */
  			break;
  		}
@@ -608587,7 +629123,7 @@
  		rxb->dma_addr =
  		    pci_map_single(priv->pci_dev, rxb->skb->data,
  				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-@@ -4085,18 +4069,38 @@ void iwl_rx_replenish(void *data)
+@@ -4085,18 +4083,38 @@ void iwl_rx_replenish(void *data)
  		rxq->free_count++;
  	}
  	spin_unlock_irqrestore(&rxq->lock, flags);
@@ -608629,7 +629165,7 @@
  {
  	int i;
  	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-@@ -4113,21 +4117,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+@@ -4113,21 +4131,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
  	rxq->bd = NULL;
  }
  
@@ -608657,7 +629193,7 @@
  	/* Set us so that we have processed and used all buffers, but have
  	 * not restocked the Rx queue with fresh buffers */
  	rxq->read = rxq->write = 0;
-@@ -4136,7 +4144,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
+@@ -4136,7 +4158,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
  	return 0;
  }
  
@@ -608666,7 +629202,7 @@
  {
  	unsigned long flags;
  	int i;
-@@ -4183,7 +4191,7 @@ static u8 ratio2dB[100] = {
+@@ -4183,7 +4205,7 @@ static u8 ratio2dB[100] = {
  /* Calculates a relative dB value from a ratio of linear
   *   (i.e. not dB) signal levels.
   * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
@@ -608675,7 +629211,7 @@
  {
  	/* Anything above 1000:1 just report as 60 dB */
  	if (sig_ratio > 1000)
-@@ -4209,7 +4217,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
+@@ -4209,7 +4231,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
  /* Calculate an indication of rx signal quality (a percentage, not dBm!).
   * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
   *   about formulas used below. */
@@ -608684,7 +629220,7 @@
  {
  	int sig_qual;
  	int degradation = PERFECT_RSSI - rssi_dbm;
-@@ -4244,24 +4252,30 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+@@ -4244,24 +4266,30 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
  }
  
  /**
@@ -608721,7 +629257,7 @@
  	/* Rx interrupt, but nothing sent from uCode */
  	if (i == r)
  		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
-@@ -4269,7 +4283,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4269,7 +4297,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  	while (i != r) {
  		rxb = rxq->queue[i];
  
@@ -608730,7 +629266,7 @@
  		 * then a bug has been introduced in the queue refilling
  		 * routines -- catch it here */
  		BUG_ON(rxb == NULL);
-@@ -4279,7 +4293,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4279,7 +4307,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
  					    IWL_RX_BUF_SIZE,
  					    PCI_DMA_FROMDEVICE);
@@ -608739,7 +629275,7 @@
  
  		/* Reclaim a command buffer only if this packet is a response
  		 *   to a (driver-originated) command.
-@@ -4293,7 +4307,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4293,7 +4321,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  
  		/* Based on type of command response or notification,
  		 *   handle those that need handling via function in
@@ -608748,7 +629284,7 @@
  		if (priv->rx_handlers[pkt->hdr.cmd]) {
  			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
  				"r = %d, i = %d, %s, 0x%02x\n", r, i,
-@@ -4308,11 +4322,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4308,11 +4336,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		}
  
  		if (reclaim) {
@@ -608763,7 +629299,7 @@
  			else
  				IWL_WARNING("Claim null rxb?\n");
  		}
-@@ -4332,15 +4346,28 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4332,15 +4360,28 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		list_add_tail(&rxb->list, &priv->rxq.rx_used);
  		spin_unlock_irqrestore(&rxq->lock, flags);
  		i = (i + 1) & RX_QUEUE_MASK;
@@ -608795,7 +629331,7 @@
  {
  	u32 reg = 0;
  	int rc = 0;
-@@ -4354,41 +4381,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+@@ -4354,41 +4395,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
  		/* wake up nic if it's powered down ...
  		 * uCode will wake up, and interrupt us again, so next
  		 * time we'll skip this part. */
@@ -608848,7 +629384,7 @@
  	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
  	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
  	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
-@@ -4405,24 +4432,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+@@ -4405,24 +4446,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
  }
  #endif
  
@@ -608879,7 +629415,7 @@
  	IWL_DEBUG_ISR("Disabled interrupts\n");
  }
  
-@@ -4449,7 +4476,7 @@ static const char *desc_lookup(int i)
+@@ -4449,7 +4490,7 @@ static const char *desc_lookup(int i)
  #define ERROR_START_OFFSET  (1 * sizeof(u32))
  #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
  
@@ -608888,7 +629424,7 @@
  {
  	u32 i;
  	u32 desc, time, count, base, data1;
-@@ -4458,18 +4485,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4458,18 +4499,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  
  	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
  
@@ -608910,7 +629446,7 @@
  
  	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
  		IWL_ERROR("Start IWL Error Log Dump:\n");
-@@ -4482,19 +4509,19 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4482,19 +4523,19 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  	for (i = ERROR_START_OFFSET;
  	     i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
  	     i += ERROR_ELEM_SIZE) {
@@ -608937,7 +629473,7 @@
  
  		IWL_ERROR
  		    ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
-@@ -4502,18 +4529,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4502,18 +4543,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  		     ilink1, ilink2, data1);
  	}
  
@@ -608961,7 +629497,7 @@
  				u32 num_events, u32 mode)
  {
  	u32 i;
-@@ -4537,21 +4564,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+@@ -4537,21 +4578,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
  	/* "time" is actually "data" for mode 0 (no timestamp).
  	 * place event id # at far right for easier visual parsing. */
  	for (i = 0; i < num_events; i++) {
@@ -608987,7 +629523,7 @@
  {
  	int rc;
  	u32 base;       /* SRAM byte address of event log header */
-@@ -4562,29 +4589,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+@@ -4562,29 +4603,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
  	u32 size;       /* # entries that we'll print */
  
  	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
@@ -609024,7 +629560,7 @@
  		return;
  	}
  
-@@ -4594,31 +4621,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+@@ -4594,31 +4635,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
  	/* if uCode has wrapped back to top of log, start at the oldest entry,
  	 * i.e the next one that uCode would fill. */
  	if (num_wraps)
@@ -609067,7 +629603,7 @@
  	}
  #endif
  
-@@ -4632,7 +4659,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
+@@ -4632,7 +4673,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
  		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
  			  "Restarting adapter due to uCode error.\n");
  
@@ -609076,7 +629612,7 @@
  			memcpy(&priv->recovery_rxon, &priv->active_rxon,
  			       sizeof(priv->recovery_rxon));
  			priv->error_recovering = 1;
-@@ -4641,16 +4668,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
+@@ -4641,16 +4682,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
  	}
  }
  
@@ -609096,7 +629632,7 @@
  
  	spin_lock_irqsave(&priv->lock, flags);
  	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
-@@ -4658,12 +4685,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
+@@ -4658,12 +4699,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -609111,7 +629647,7 @@
  	u32 inta_mask;
  #endif
  
-@@ -4672,18 +4699,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4672,18 +4713,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	/* Ack/clear/reset pending uCode interrupts.
  	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
  	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
@@ -609138,7 +629674,7 @@
  		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
  			      inta, inta_mask, inta_fh);
  	}
-@@ -4703,9 +4731,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4703,9 +4745,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
  
  		/* Tell the device to stop sending interrupts */
@@ -609150,7 +629686,7 @@
  
  		handled |= CSR_INT_BIT_HW_ERR;
  
-@@ -4714,8 +4742,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4714,11 +4756,12 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  		return;
  	}
  
@@ -609159,9 +629695,21 @@
 +#ifdef CONFIG_IWL3945_DEBUG
 +	if (iwl3945_debug_level & (IWL_DL_ISR)) {
  		/* NIC fires this, but we don't use it, redundant with WAKEUP */
- 		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
- 			IWL_DEBUG_ISR("Microcode started or stopped.\n");
-@@ -4731,7 +4759,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+-		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+-			IWL_DEBUG_ISR("Microcode started or stopped.\n");
++		if (inta & CSR_INT_BIT_SCD)
++			IWL_DEBUG_ISR("Scheduler finished to transmit "
++				      "the frame/frames.\n");
+ 
+ 		/* Alive notification via Rx interrupt will do the real work */
+ 		if (inta & CSR_INT_BIT_ALIVE)
+@@ -4726,12 +4769,12 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+ 	}
+ #endif
+ 	/* Safely ignore these bits for debug checks below */
+-	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
++	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
+ 
  	/* HW RF KILL switch toggled (4965 only) */
  	if (inta & CSR_INT_BIT_RF_KILL) {
  		int hw_rf_kill = 0;
@@ -609170,7 +629718,7 @@
  				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
  			hw_rf_kill = 1;
  
-@@ -4761,20 +4789,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4761,20 +4804,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	if (inta & CSR_INT_BIT_SW_ERR) {
  		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
  			  inta);
@@ -609199,7 +629747,7 @@
  
  		handled |= CSR_INT_BIT_WAKEUP;
  	}
-@@ -4783,19 +4811,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4783,19 +4826,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	 * Rx "responses" (frame-received notification), and other
  	 * notifications from uCode come through here*/
  	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
@@ -609224,7 +629772,7 @@
  		}
  		handled |= CSR_INT_BIT_FH_TX;
  	}
-@@ -4810,13 +4838,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4810,13 +4853,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	}
  
  	/* Re-enable all interrupts */
@@ -609244,7 +629792,7 @@
  		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
  			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
  	}
-@@ -4824,9 +4852,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4824,9 +4867,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -609256,7 +629804,7 @@
  	u32 inta, inta_mask;
  	u32 inta_fh;
  	if (!priv)
-@@ -4838,12 +4866,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
+@@ -4838,12 +4881,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
  	 *    back-to-back ISRs and sporadic interrupts from our NIC.
  	 * If we have something to service, the tasklet will re-enable ints.
  	 * If we *don't* have something, we'll re-enable before leaving here. */
@@ -609273,16 +629821,21 @@
  
  	/* Ignore interrupt if there's nothing in NIC to service.
  	 * This may be due to IRQ shared with another device,
-@@ -4862,7 +4890,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
+@@ -4862,8 +4905,11 @@ static irqreturn_t iwl_isr(int irq, void *data)
  	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
  		      inta, inta_mask, inta_fh);
  
 -	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+-	tasklet_schedule(&priv->irq_tasklet);
++	inta &= ~CSR_INT_BIT_SCD;
++
 +	/* iwl3945_irq_tasklet() will service interrupts and re-enable them */
- 	tasklet_schedule(&priv->irq_tasklet);
++	if (likely(inta || inta_fh))
++		tasklet_schedule(&priv->irq_tasklet);
  unplugged:
  	spin_unlock(&priv->lock);
-@@ -4871,18 +4899,18 @@ unplugged:
+ 
+@@ -4871,18 +4917,18 @@ unplugged:
  
   none:
  	/* re-enable interrupts here since we don't have anything to service. */
@@ -609304,7 +629857,7 @@
   * definition below maps to physical channel 42 in the 5.2GHz spectrum.
   * The specific geography and calibration information for that channel
   * is contained in the eeprom map itself.
-@@ -4908,58 +4936,58 @@ unplugged:
+@@ -4908,58 +4954,58 @@ unplugged:
   *********************************************************************/
  
  /* 2.4 GHz */
@@ -609383,7 +629936,7 @@
  		break;
  	default:
  		BUG();
-@@ -4967,7 +4995,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+@@ -4967,7 +5013,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
  	}
  }
  
@@ -609397,7 +629950,7 @@
  						    int phymode, u16 channel)
  {
  	int i;
-@@ -4994,13 +5027,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+@@ -4994,13 +5045,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
  #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
  			    ? # x " " : "")
  
@@ -609417,7 +629970,7 @@
  
  	if (priv->channel_count) {
  		IWL_DEBUG_INFO("Channel map already initialized.\n");
-@@ -5016,15 +5052,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5016,15 +5070,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
  
  	priv->channel_count =
@@ -609439,7 +629992,7 @@
  				     priv->channel_count, GFP_KERNEL);
  	if (!priv->channel_info) {
  		IWL_ERROR("Could not allocate channel_info\n");
-@@ -5039,7 +5075,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5039,7 +5093,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  	 * what just in the EEPROM) */
  	for (band = 1; band <= 5; band++) {
  
@@ -609448,7 +630001,7 @@
  					&eeprom_ch_info, &eeprom_ch_index);
  
  		/* Loop through each band adding each of the channels */
-@@ -5103,6 +5139,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5103,12 +5157,22 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  		}
  	}
  
@@ -609456,7 +630009,22 @@
  	if (iwl3945_txpower_set_from_eeprom(priv))
  		return -EIO;
  
-@@ -5132,7 +5169,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+ 	return 0;
+ }
+ 
++/*
++ * iwl3945_free_channel_map - undo allocations in iwl3945_init_channel_map
++ */
++static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
++{
++	kfree(priv->channel_info);
++	priv->channel_count = 0;
++}
++
+ /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+  * sending probe req.  This should be set long enough to hear probe responses
+  * from more than one AP.  */
+@@ -5132,7 +5196,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  #define IWL_PASSIVE_DWELL_BASE      (100)
  #define IWL_CHANNEL_TUNE_TIME       5
  
@@ -609465,7 +630033,7 @@
  {
  	if (phymode == MODE_IEEE80211A)
  		return IWL_ACTIVE_DWELL_TIME_52;
-@@ -5140,14 +5177,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+@@ -5140,14 +5204,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
  		return IWL_ACTIVE_DWELL_TIME_24;
  }
  
@@ -609483,7 +630051,7 @@
  		/* If we're associated, we clamp the maximum passive
  		 * dwell time to be 98% of the beacon interval (minus
  		 * 2 * channel tune time) */
-@@ -5163,30 +5200,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+@@ -5163,30 +5227,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
  	return passive;
  }
  
@@ -609521,7 +630089,7 @@
  				IWL_DEBUG_SCAN
  				    ("Skipping current channel %d\n",
  				     le16_to_cpu(priv->active_rxon.channel));
-@@ -5197,7 +5234,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5197,7 +5261,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  
  		scan_ch->channel = channels[i].chan;
  
@@ -609530,7 +630098,7 @@
  		if (!is_channel_valid(ch_info)) {
  			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
  				       scan_ch->channel);
-@@ -5219,7 +5256,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5219,7 +5283,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  		scan_ch->active_dwell = cpu_to_le16(active_dwell);
  		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
  
@@ -609539,7 +630107,7 @@
  		scan_ch->tpc.dsp_atten = 110;
  		/* scan_pwr_info->tpc.dsp_atten; */
  
-@@ -5229,8 +5266,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5229,8 +5293,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  		else {
  			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
  			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
@@ -609550,7 +630118,7 @@
  			 */
  		}
  
-@@ -5248,7 +5285,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5248,7 +5312,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  	return added;
  }
  
@@ -609559,7 +630127,7 @@
  {
  	int i, j;
  	for (i = 0; i < 3; i++) {
-@@ -5258,13 +5295,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
+@@ -5258,13 +5322,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
  	}
  }
  
@@ -609575,7 +630143,7 @@
  		rates[i].val = i; /* Rate scaling will work on indexes */
  		rates[i].val2 = i;
  		rates[i].flags = IEEE80211_RATE_SUPPORTED;
-@@ -5276,7 +5313,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
+@@ -5276,7 +5340,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
  			 * If CCK 1M then set rate flag to CCK else CCK_2
  			 * which is CCK | PREAMBLE2
  			 */
@@ -609584,7 +630152,7 @@
  				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
  		}
  
-@@ -5287,11 +5324,11 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
+@@ -5287,11 +5351,11 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
  }
  
  /**
@@ -609599,7 +630167,7 @@
  	struct ieee80211_hw_mode *modes;
  	struct ieee80211_channel *channels;
  	struct ieee80211_channel *geo_ch;
-@@ -5337,7 +5374,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5337,7 +5401,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
  
  	/* 5.2GHz channels start after the 2.4GHz channels */
  	modes[A].mode = MODE_IEEE80211A;
@@ -609608,7 +630176,7 @@
  	modes[A].rates = &rates[4];
  	modes[A].num_rates = 8;	/* just OFDM */
  	modes[A].num_channels = 0;
-@@ -5357,7 +5394,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5357,7 +5421,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
  	priv->ieee_channels = channels;
  	priv->ieee_rates = rates;
  
@@ -609617,7 +630185,24 @@
  
  	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
  		ch = &priv->channel_info[i];
-@@ -5440,57 +5477,21 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5434,63 +5498,38 @@ static int iwl_init_geos(struct iwl_priv *priv)
+ 	return 0;
+ }
+ 
++/*
++ * iwl3945_free_geos - undo allocations in iwl3945_init_geos
++ */
++static void iwl3945_free_geos(struct iwl3945_priv *priv)
++{
++	kfree(priv->modes);
++	kfree(priv->ieee_channels);
++	kfree(priv->ieee_rates);
++	clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
++}
++
+ /******************************************************************************
+  *
+  * uCode download functions
   *
   ******************************************************************************/
  
@@ -609684,7 +630269,7 @@
  {
  	u32 val;
  	u32 save_len = len;
-@@ -5499,18 +5500,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+@@ -5499,18 +5538,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
  
  	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
  
@@ -609706,7 +630291,7 @@
  		if (val != le32_to_cpu(*image)) {
  			IWL_ERROR("uCode INST section is invalid at "
  				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
-@@ -5522,22 +5523,21 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+@@ -5522,22 +5561,21 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
  		}
  	}
  
@@ -609733,7 +630318,7 @@
  {
  	u32 val;
  	int rc = 0;
-@@ -5546,7 +5546,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5546,7 +5584,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  
  	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
  
@@ -609742,7 +630327,7 @@
  	if (rc)
  		return rc;
  
-@@ -5554,9 +5554,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5554,9 +5592,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  		/* read data comes through single port, auto-incr addr */
  		/* NOTE: Use the debugless read so we don't flood kernel log
  		 * if IWL_DL_IO is set */
@@ -609754,7 +630339,7 @@
  		if (val != le32_to_cpu(*image)) {
  #if 0 /* Enable this if you want to see details */
  			IWL_ERROR("uCode INST section is invalid at "
-@@ -5570,17 +5570,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5570,17 +5608,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  		}
  	}
  
@@ -609775,7 +630360,7 @@
  {
  	__le32 *image;
  	u32 len;
-@@ -5589,7 +5589,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5589,7 +5627,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try bootstrap */
  	image = (__le32 *)priv->ucode_boot.v_addr;
  	len = priv->ucode_boot.len;
@@ -609784,7 +630369,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
  		return 0;
-@@ -5598,7 +5598,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5598,7 +5636,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try initialize */
  	image = (__le32 *)priv->ucode_init.v_addr;
  	len = priv->ucode_init.len;
@@ -609793,7 +630378,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
  		return 0;
-@@ -5607,7 +5607,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5607,7 +5645,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try runtime/protocol */
  	image = (__le32 *)priv->ucode_code.v_addr;
  	len = priv->ucode_code.len;
@@ -609802,7 +630387,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
  		return 0;
-@@ -5615,18 +5615,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5615,18 +5653,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  
  	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
  
@@ -609826,7 +630411,7 @@
  {
  	__le32 *image = priv->ucode_boot.v_addr;
  	u32 len = priv->ucode_boot.len;
-@@ -5636,11 +5637,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -5636,11 +5675,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  	IWL_DEBUG_INFO("Begin verify bsm\n");
  
  	/* verify BSM SRAM contents */
@@ -609840,7 +630425,7 @@
  		if (val != le32_to_cpu(*image)) {
  			IWL_ERROR("BSM uCode verification failed at "
  				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
-@@ -5657,7 +5658,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -5657,7 +5696,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  }
  
  /**
@@ -609849,7 +630434,7 @@
   *
   * BSM operation:
   *
-@@ -5688,7 +5689,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -5688,7 +5727,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
   * the runtime uCode instructions and the backup data cache into SRAM,
   * and re-launches the runtime uCode from where it left off.
   */
@@ -609858,7 +630443,7 @@
  {
  	__le32 *image = priv->ucode_boot.v_addr;
  	u32 len = priv->ucode_boot.len;
-@@ -5708,8 +5709,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -5708,8 +5747,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  		return -EINVAL;
  
  	/* Tell bootstrap uCode where to find the "Initialize" uCode
@@ -609869,7 +630454,7 @@
  	 *        after the "initialize" uCode has run, to point to
  	 *        runtime/protocol instructions and backup data cache. */
  	pinst = priv->ucode_init.p_addr;
-@@ -5717,42 +5718,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -5717,42 +5756,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  	inst_len = priv->ucode_init.len;
  	data_len = priv->ucode_init_data.len;
  
@@ -609925,7 +630510,7 @@
  		if (!(done & BSM_WR_CTRL_REG_BIT_START))
  			break;
  		udelay(10);
-@@ -5766,29 +5767,29 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -5766,29 +5805,29 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  
  	/* Enable future boot loads whenever power management unit triggers it
  	 *   (e.g. when powering back up after power-save shutdown) */
@@ -609963,7 +630548,7 @@
  	const struct firmware *ucode_raw;
  	/* firmware file name contains uCode/driver compatibility version */
  	const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
-@@ -5798,9 +5799,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5798,9 +5837,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
  	/* Ask kernel firmware_class module to get the boot firmware off disk.
  	 * request_firmware() is synchronous, file is in memory on return. */
@@ -609977,7 +630562,7 @@
  		goto error;
  	}
  
-@@ -5810,7 +5812,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5810,7 +5850,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	/* Make sure that we got at least our header! */
  	if (ucode_raw->size < sizeof(*ucode)) {
  		IWL_ERROR("File size way too small!\n");
@@ -609986,7 +630571,7 @@
  		goto err_release;
  	}
  
-@@ -5825,16 +5827,11 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5825,16 +5865,11 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	boot_size = le32_to_cpu(ucode->boot_size);
  
  	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
@@ -610008,7 +630593,7 @@
  
  	/* Verify size of file vs. image size info in file's header */
  	if (ucode_raw->size < sizeof(*ucode) +
-@@ -5843,43 +5840,40 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5843,43 +5878,40 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
  		IWL_DEBUG_INFO("uCode file size %d too small\n",
  			       (int)ucode_raw->size);
@@ -610068,7 +630653,7 @@
  		goto err_release;
  	}
  
-@@ -5889,66 +5883,54 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5889,66 +5921,54 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	 * 1) unmodified from disk
  	 * 2) backup cache for save/restore during power-downs */
  	priv->ucode_code.len = inst_size;
@@ -610160,7 +630745,7 @@
  	memcpy(priv->ucode_data.v_addr, src, len);
  	memcpy(priv->ucode_data_backup.v_addr, src, len);
  
-@@ -5956,8 +5938,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5956,8 +5976,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	if (init_size) {
  		src = &ucode->data[inst_size + data_size];
  		len = priv->ucode_init.len;
@@ -610171,7 +630756,7 @@
  		memcpy(priv->ucode_init.v_addr, src, len);
  	}
  
-@@ -5983,19 +5965,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -5983,19 +6003,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
   err_pci_alloc:
  	IWL_ERROR("failed to allocate pci memory\n");
@@ -610195,7 +630780,7 @@
   *
   * Tell initialization uCode where to find runtime uCode.
   *
-@@ -6003,7 +5985,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6003,7 +6023,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
   * We need to replace them to load runtime uCode inst and data,
   * and to save runtime data when powering down.
   */
@@ -610204,7 +630789,7 @@
  {
  	dma_addr_t pinst;
  	dma_addr_t pdata;
-@@ -6015,24 +5997,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+@@ -6015,24 +6035,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
  	pdata = priv->ucode_data_backup.p_addr;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -610235,7 +630820,7 @@
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
-@@ -6042,17 +6024,13 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+@@ -6042,17 +6062,13 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
  }
  
  /**
@@ -610256,7 +630841,7 @@
  {
  	/* Check alive response for "valid" sign from uCode */
  	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
-@@ -6065,7 +6043,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6065,7 +6081,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
  	 * This is a paranoid check, because we would not have gotten the
  	 * "initialize" alive if code weren't properly loaded.  */
@@ -610265,7 +630850,7 @@
  		/* Runtime instruction load was bad;
  		 * take it all the way back down so we can try again */
  		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
-@@ -6076,7 +6054,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6076,7 +6092,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  	 * load and launch runtime uCode, which will send us another "Alive"
  	 * notification. */
  	IWL_DEBUG_INFO("Initialization Alive received.\n");
@@ -610274,7 +630859,7 @@
  		/* Runtime instruction load won't happen;
  		 * take it all the way back down so we can try again */
  		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
-@@ -6090,11 +6068,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6090,11 +6106,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  
  
  /**
@@ -610289,7 +630874,7 @@
  {
  	int rc = 0;
  	int thermal_spin = 0;
-@@ -6112,30 +6090,30 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6112,30 +6128,30 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
  	 * This is a paranoid check, because we would not have gotten the
  	 * "runtime" alive if code weren't properly loaded.  */
@@ -610326,7 +630911,7 @@
  			thermal_spin++;
  			udelay(10);
  		}
-@@ -6146,68 +6124,49 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6146,68 +6162,40 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	} else
  		set_bit(STATUS_RF_KILL_HW, &priv->status);
  
@@ -610338,16 +630923,13 @@
  	clear_bit(STATUS_FW_ERROR, &priv->status);
  
 -	rc = iwl_init_channel_map(priv);
-+	rc = iwl3945_init_channel_map(priv);
- 	if (rc) {
- 		IWL_ERROR("initializing regulatory failed: %d\n", rc);
- 		return;
- 	}
- 
+-	if (rc) {
+-		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+-		return;
+-	}
+-
 -	iwl_init_geos(priv);
-+	iwl3945_init_geos(priv);
-+	iwl3945_reset_channel_flag(priv);
- 
+-
 -	if (iwl_is_rfkill(priv))
 +	if (iwl3945_is_rfkill(priv))
  		return;
@@ -610409,7 +630991,7 @@
  
  	/* At this point, the NIC is initialized and operational */
  	priv->notif_missed_beacons = 0;
-@@ -6216,9 +6175,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6216,9 +6204,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	iwl3945_reg_txpower_periodic(priv);
  
  	IWL_DEBUG_INFO("ALIVE processing complete.\n");
@@ -610421,7 +631003,7 @@
  
  	return;
  
-@@ -6226,9 +6186,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6226,9 +6215,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	queue_work(priv->workqueue, &priv->restart);
  }
  
@@ -610433,7 +631015,7 @@
  {
  	unsigned long flags;
  	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
-@@ -6241,7 +6201,7 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6241,7 +6230,7 @@ static void __iwl_down(struct iwl_priv *priv)
  	if (!exit_pending)
  		set_bit(STATUS_EXIT_PENDING, &priv->status);
  
@@ -610442,7 +631024,7 @@
  
  	/* Unblock any waiting calls */
  	wake_up_interruptible_all(&priv->wait_command_queue);
-@@ -6252,17 +6212,17 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6252,17 +6241,17 @@ static void __iwl_down(struct iwl_priv *priv)
  		clear_bit(STATUS_EXIT_PENDING, &priv->status);
  
  	/* stop and reset the on-board processor */
@@ -610464,7 +631046,7 @@
  		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
  					STATUS_RF_KILL_HW |
  			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-@@ -6284,51 +6244,50 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6284,51 +6273,50 @@ static void __iwl_down(struct iwl_priv *priv)
  				STATUS_FW_ERROR;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -610531,7 +631113,7 @@
  	int rc, i;
  
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-@@ -6339,7 +6298,19 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6339,7 +6327,19 @@ static int __iwl_up(struct iwl_priv *priv)
  	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
  		IWL_WARNING("Radio disabled by SW RF kill (module "
  			    "parameter)\n");
@@ -610552,7 +631134,7 @@
  	}
  
  	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-@@ -6347,41 +6318,45 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6347,41 +6347,45 @@ static int __iwl_up(struct iwl_priv *priv)
  		return -EIO;
  	}
  
@@ -610609,7 +631191,7 @@
  
  		if (rc) {
  			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
-@@ -6389,14 +6364,7 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6389,14 +6393,7 @@ static int __iwl_up(struct iwl_priv *priv)
  		}
  
  		/* start card; "initialize" will load runtime ucode */
@@ -610625,7 +631207,7 @@
  
  		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
  
-@@ -6404,7 +6372,7 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6404,7 +6401,7 @@ static int __iwl_up(struct iwl_priv *priv)
  	}
  
  	set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -610634,7 +631216,7 @@
  
  	/* tried to restart and config the device for as long as our
  	 * patience could withstand */
-@@ -6419,35 +6387,35 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6419,35 +6416,35 @@ static int __iwl_up(struct iwl_priv *priv)
   *
   *****************************************************************************/
  
@@ -610680,7 +631262,7 @@
  
  	wake_up_interruptible(&priv->wait_command_queue);
  
-@@ -6456,7 +6424,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
+@@ -6456,7 +6453,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
  
  	mutex_lock(&priv->mutex);
  
@@ -610689,7 +631271,7 @@
  		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
  			  "HW and/or SW RF Kill no longer active, restarting "
  			  "device\n");
-@@ -6477,10 +6445,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
+@@ -6477,10 +6474,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
  
  #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
  
@@ -610703,7 +631285,7 @@
  
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
  		return;
-@@ -6493,22 +6461,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
+@@ -6493,22 +6490,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
  			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
  
  		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -610733,7 +631315,7 @@
  	struct ieee80211_conf *conf = NULL;
  	u8 direct_mask;
  	int phymode;
-@@ -6517,7 +6485,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6517,7 +6514,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  
  	mutex_lock(&priv->mutex);
  
@@ -610742,7 +631324,7 @@
  		IWL_WARNING("request scan called when driver not ready.\n");
  		goto done;
  	}
-@@ -6546,7 +6514,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6546,7 +6543,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  		goto done;
  	}
  
@@ -610751,7 +631333,7 @@
  		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
  		goto done;
  	}
-@@ -6562,7 +6530,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6562,7 +6559,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	}
  
  	if (!priv->scan) {
@@ -610760,7 +631342,7 @@
  				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
  		if (!priv->scan) {
  			rc = -ENOMEM;
-@@ -6570,12 +6538,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6570,12 +6567,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
  		}
  	}
  	scan = priv->scan;
@@ -610775,7 +631357,7 @@
  		u16 interval = 0;
  		u32 extra;
  		u32 suspend_time = 100;
-@@ -6612,14 +6580,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6612,14 +6609,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	if (priv->one_direct_scan) {
  		IWL_DEBUG_SCAN
  		    ("Kicking off one direct scan for '%s'\n",
@@ -610792,16 +631374,18 @@
  		scan->direct_scan[0].id = WLAN_EID_SSID;
  		scan->direct_scan[0].len = priv->essid_len;
  		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-@@ -6630,7 +6598,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6630,8 +6627,8 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	/* We don't build a direct scan probe request; the uCode will do
  	 * that based on the direct_mask added to each channel entry */
  	scan->tx_cmd.len = cpu_to_le16(
 -		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+-			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
 +		iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
- 			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
++			IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
  	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
  	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
-@@ -6666,23 +6634,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
+ 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+@@ -6666,23 +6663,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	if (direct_mask)
  		IWL_DEBUG_SCAN
  		    ("Initiating direct scan for %s.\n",
@@ -610829,7 +631413,7 @@
  	if (rc)
  		goto done;
  
-@@ -6693,50 +6661,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6693,50 +6690,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	return;
  
   done:
@@ -610895,7 +631479,7 @@
  					     post_associate.work);
  
  	int rc = 0;
-@@ -6758,20 +6728,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -6758,20 +6757,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
  
  	mutex_lock(&priv->mutex);
  
@@ -610922,7 +631506,7 @@
  			      sizeof(priv->rxon_timing), &priv->rxon_timing);
  	if (rc)
  		IWL_WARNING("REPLY_RXON_TIMING failed - "
-@@ -6800,75 +6770,81 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -6800,75 +6799,81 @@ static void iwl_bg_post_associate(struct work_struct *data)
  
  	}
  
@@ -611025,7 +631609,7 @@
  	mutex_unlock(&priv->mutex);
  }
  
-@@ -6878,50 +6854,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
+@@ -6878,50 +6883,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
   *
   *****************************************************************************/
  
@@ -611167,7 +631751,7 @@
  
  	IWL_DEBUG_MAC80211("enter\n");
  
-@@ -6933,29 +6982,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -6933,29 +7011,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
  	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
  		     ctl->tx_rate);
  
@@ -611204,7 +631788,7 @@
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
-@@ -6966,106 +7015,108 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+@@ -6966,110 +7044,112 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
  		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
  	}
  
@@ -611345,7 +631929,12 @@
  {
  	int rc = 0;
  
-@@ -7077,12 +7128,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
+-	if (priv->status & STATUS_EXIT_PENDING)
++	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ 		return;
+ 
+ 	/* The following should be done only at AP bring up */
+@@ -7077,12 +7157,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
  
  		/* RXON - unassoc (to set timing command) */
  		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -611362,7 +631951,7 @@
  				sizeof(priv->rxon_timing), &priv->rxon_timing);
  		if (rc)
  			IWL_WARNING("REPLY_RXON_TIMING failed - "
-@@ -7112,20 +7163,21 @@ static void iwl_config_ap(struct iwl_priv *priv)
+@@ -7112,20 +7192,21 @@ static void iwl_config_ap(struct iwl_priv *priv)
  		}
  		/* restore RXON assoc */
  		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -611389,7 +631978,7 @@
  	DECLARE_MAC_BUF(mac);
  	unsigned long flags;
  	int rc;
-@@ -7142,9 +7194,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7142,9 +7223,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		return 0;
  	}
  
@@ -611402,7 +631991,7 @@
  	if (conf->bssid)
  		IWL_DEBUG_MAC80211("bssid: %s\n",
  				   print_mac(mac, conf->bssid));
-@@ -7161,8 +7215,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7161,8 +7244,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		return 0;
  	}
  
@@ -611413,7 +632002,7 @@
  		mutex_unlock(&priv->mutex);
  		return 0;
  	}
-@@ -7180,11 +7234,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7180,11 +7263,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		priv->ibss_beacon = conf->beacon;
  	}
  
@@ -611429,7 +632018,7 @@
  			IWL_WARNING("Aborted scan still in progress "
  				    "after 100ms\n");
  			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
-@@ -7200,20 +7257,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7200,20 +7286,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
  
  		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
@@ -611456,7 +632045,7 @@
  	spin_lock_irqsave(&priv->lock, flags);
  	if (!conf->ssid_len)
  		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-@@ -7229,34 +7287,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7229,34 +7316,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  	return 0;
  }
  
@@ -611503,7 +632092,7 @@
  		memset(priv->bssid, 0, ETH_ALEN);
  		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
  		priv->essid_len = 0;
-@@ -7264,22 +7323,20 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+@@ -7264,22 +7352,20 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
  	mutex_unlock(&priv->mutex);
  
  	IWL_DEBUG_MAC80211("leave\n");
@@ -611529,7 +632118,7 @@
  		rc = -EIO;
  		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
  		goto out_unlock;
-@@ -7291,17 +7348,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+@@ -7291,17 +7377,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
  		goto out_unlock;
  	}
  
@@ -611557,7 +632146,7 @@
  
  		priv->one_direct_scan = 1;
  		priv->direct_ssid_len = (u8)
-@@ -7310,7 +7371,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+@@ -7310,7 +7400,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
  	} else
  		priv->one_direct_scan = 0;
  
@@ -611566,7 +632155,7 @@
  
  	IWL_DEBUG_MAC80211("leave\n");
  
-@@ -7321,17 +7382,17 @@ out_unlock:
+@@ -7321,17 +7411,17 @@ out_unlock:
  	return rc;
  }
  
@@ -611587,7 +632176,7 @@
  		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
  		return -EOPNOTSUPP;
  	}
-@@ -7340,7 +7401,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7340,7 +7430,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  		/* only support pairwise keys */
  		return -EOPNOTSUPP;
  
@@ -611596,7 +632185,7 @@
  	if (sta_id == IWL_INVALID_STATION) {
  		DECLARE_MAC_BUF(mac);
  
-@@ -7351,24 +7412,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7351,24 +7441,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  
  	mutex_lock(&priv->mutex);
  
@@ -611628,7 +632217,7 @@
  			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
  		}
  		break;
-@@ -7382,18 +7443,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7382,18 +7472,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  	return rc;
  }
  
@@ -611652,7 +632241,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		return -EIO;
  	}
-@@ -7403,7 +7464,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+@@ -7403,7 +7493,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
  		return 0;
  	}
  
@@ -611661,7 +632250,7 @@
  	if (!priv->qos_data.qos_enable) {
  		priv->qos_data.qos_active = 0;
  		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
-@@ -7426,30 +7487,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+@@ -7426,30 +7516,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
  
  	mutex_lock(&priv->mutex);
  	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
@@ -611701,7 +632290,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		return -EIO;
  	}
-@@ -7459,7 +7520,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+@@ -7459,7 +7549,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
  	for (i = 0; i < AC_NUM; i++) {
  		txq = &priv->txq[i];
  		q = &txq->q;
@@ -611710,7 +632299,7 @@
  
  		stats->data[i].len = q->n_window - avail;
  		stats->data[i].limit = q->n_window - q->high_mark;
-@@ -7473,7 +7534,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+@@ -7473,7 +7563,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
  	return 0;
  }
  
@@ -611719,7 +632308,7 @@
  			     struct ieee80211_low_level_stats *stats)
  {
  	IWL_DEBUG_MAC80211("enter\n");
-@@ -7482,7 +7543,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+@@ -7482,7 +7572,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
  	return 0;
  }
  
@@ -611728,7 +632317,7 @@
  {
  	IWL_DEBUG_MAC80211("enter\n");
  	IWL_DEBUG_MAC80211("leave\n");
-@@ -7490,16 +7551,16 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+@@ -7490,16 +7580,16 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
  	return 0;
  }
  
@@ -611749,7 +632338,7 @@
  #endif
  	cancel_delayed_work(&priv->post_associate);
  
-@@ -7522,13 +7583,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+@@ -7522,13 +7612,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -611771,7 +632360,7 @@
  	}
  
  	/* Per mac80211.h: This is only used in IBSS mode... */
-@@ -7539,15 +7606,9 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+@@ -7539,15 +7635,9 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  		return;
  	}
  
@@ -611788,7 +632377,7 @@
  
  	mutex_unlock(&priv->mutex);
  
-@@ -7555,16 +7616,16 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+@@ -7555,16 +7645,16 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  
  }
  
@@ -611808,7 +632397,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		mutex_unlock(&priv->mutex);
  		return -EIO;
-@@ -7588,8 +7649,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -7588,8 +7678,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  	IWL_DEBUG_MAC80211("leave\n");
  	spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -611819,7 +632408,7 @@
  #endif
  
  	queue_work(priv->workqueue, &priv->post_associate.work);
-@@ -7605,7 +7666,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -7605,7 +7695,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
   *
   *****************************************************************************/
  
@@ -611828,7 +632417,7 @@
  
  /*
   * The following adds a new attribute to the sysfs representation
-@@ -7617,7 +7678,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -7617,7 +7707,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  
  static ssize_t show_debug_level(struct device_driver *d, char *buf)
  {
@@ -611837,7 +632426,7 @@
  }
  static ssize_t store_debug_level(struct device_driver *d,
  				 const char *buf, size_t count)
-@@ -7630,7 +7691,7 @@ static ssize_t store_debug_level(struct device_driver *d,
+@@ -7630,7 +7720,7 @@ static ssize_t store_debug_level(struct device_driver *d,
  		printk(KERN_INFO DRV_NAME
  		       ": %s is not in hex or decimal form.\n", buf);
  	else
@@ -611846,7 +632435,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -7638,7 +7699,7 @@ static ssize_t store_debug_level(struct device_driver *d,
+@@ -7638,7 +7728,7 @@ static ssize_t store_debug_level(struct device_driver *d,
  static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
  		   show_debug_level, store_debug_level);
  
@@ -611855,7 +632444,7 @@
  
  static ssize_t show_rf_kill(struct device *d,
  			    struct device_attribute *attr, char *buf)
-@@ -7649,7 +7710,7 @@ static ssize_t show_rf_kill(struct device *d,
+@@ -7649,7 +7739,7 @@ static ssize_t show_rf_kill(struct device *d,
  	 * 2 - HW based RF kill active
  	 * 3 - Both HW and SW based RF kill active
  	 */
@@ -611864,7 +632453,7 @@
  	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
  		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
  
-@@ -7660,10 +7721,10 @@ static ssize_t store_rf_kill(struct device *d,
+@@ -7660,10 +7750,10 @@ static ssize_t store_rf_kill(struct device *d,
  			     struct device_attribute *attr,
  			     const char *buf, size_t count)
  {
@@ -611877,7 +632466,7 @@
  	mutex_unlock(&priv->mutex);
  
  	return count;
-@@ -7674,12 +7735,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+@@ -7674,12 +7764,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
  static ssize_t show_temperature(struct device *d,
  				struct device_attribute *attr, char *buf)
  {
@@ -611893,7 +632482,7 @@
  }
  
  static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-@@ -7688,15 +7749,15 @@ static ssize_t show_rs_window(struct device *d,
+@@ -7688,15 +7778,15 @@ static ssize_t show_rs_window(struct device *d,
  			      struct device_attribute *attr,
  			      char *buf)
  {
@@ -611912,7 +632501,7 @@
  	return sprintf(buf, "%d\n", priv->user_txpower_limit);
  }
  
-@@ -7704,7 +7765,7 @@ static ssize_t store_tx_power(struct device *d,
+@@ -7704,7 +7794,7 @@ static ssize_t store_tx_power(struct device *d,
  			      struct device_attribute *attr,
  			      const char *buf, size_t count)
  {
@@ -611921,7 +632510,7 @@
  	char *p = (char *)buf;
  	u32 val;
  
-@@ -7713,7 +7774,7 @@ static ssize_t store_tx_power(struct device *d,
+@@ -7713,7 +7803,7 @@ static ssize_t store_tx_power(struct device *d,
  		printk(KERN_INFO DRV_NAME
  		       ": %s is not in decimal form.\n", buf);
  	else
@@ -611930,7 +632519,7 @@
  
  	return count;
  }
-@@ -7723,7 +7784,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+@@ -7723,7 +7813,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
  static ssize_t show_flags(struct device *d,
  			  struct device_attribute *attr, char *buf)
  {
@@ -611939,7 +632528,7 @@
  
  	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
  }
-@@ -7732,19 +7793,19 @@ static ssize_t store_flags(struct device *d,
+@@ -7732,19 +7822,19 @@ static ssize_t store_flags(struct device *d,
  			   struct device_attribute *attr,
  			   const char *buf, size_t count)
  {
@@ -611962,7 +632551,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -7757,7 +7818,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+@@ -7757,7 +7847,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
  static ssize_t show_filter_flags(struct device *d,
  				 struct device_attribute *attr, char *buf)
  {
@@ -611971,7 +632560,7 @@
  
  	return sprintf(buf, "0x%04X\n",
  		le32_to_cpu(priv->active_rxon.filter_flags));
-@@ -7767,20 +7828,20 @@ static ssize_t store_filter_flags(struct device *d,
+@@ -7767,20 +7857,20 @@ static ssize_t store_filter_flags(struct device *d,
  				  struct device_attribute *attr,
  				  const char *buf, size_t count)
  {
@@ -611995,7 +632584,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -7794,20 +7855,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+@@ -7794,20 +7884,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
  static ssize_t show_tune(struct device *d,
  			 struct device_attribute *attr, char *buf)
  {
@@ -612019,7 +632608,7 @@
  	char *p = (char *)buf;
  	u16 tune = simple_strtoul(p, &p, 0);
  	u8 phymode = (tune >> 8) & 0xff;
-@@ -7818,9 +7879,9 @@ static ssize_t store_tune(struct device *d,
+@@ -7818,9 +7908,9 @@ static ssize_t store_tune(struct device *d,
  	mutex_lock(&priv->mutex);
  	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
  	    (priv->phymode != phymode)) {
@@ -612031,7 +632620,7 @@
  		if (!ch_info) {
  			IWL_WARNING("Requested invalid phymode/channel "
  				    "combination: %d %d\n", phymode, channel);
-@@ -7829,18 +7890,18 @@ static ssize_t store_tune(struct device *d,
+@@ -7829,18 +7919,18 @@ static ssize_t store_tune(struct device *d,
  		}
  
  		/* Cancel any currently running scans... */
@@ -612055,7 +632644,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -7850,13 +7911,13 @@ static ssize_t store_tune(struct device *d,
+@@ -7850,13 +7940,13 @@ static ssize_t store_tune(struct device *d,
  
  static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
  
@@ -612072,7 +632661,7 @@
  	u32 size = sizeof(measure_report), len = 0, ofs = 0;
  	u8 *data = (u8 *) & measure_report;
  	unsigned long flags;
-@@ -7888,7 +7949,7 @@ static ssize_t store_measurement(struct device *d,
+@@ -7888,7 +7978,7 @@ static ssize_t store_measurement(struct device *d,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
  {
@@ -612081,7 +632670,7 @@
  	struct ieee80211_measurement_params params = {
  		.channel = le16_to_cpu(priv->active_rxon.channel),
  		.start_time = cpu_to_le64(priv->last_tsf),
-@@ -7914,19 +7975,19 @@ static ssize_t store_measurement(struct device *d,
+@@ -7914,19 +8004,19 @@ static ssize_t store_measurement(struct device *d,
  
  	IWL_DEBUG_INFO("Invoking measurement of type %d on "
  		       "channel %d (for '%s')\n", type, params.channel, buf);
@@ -612104,7 +632693,7 @@
  	unsigned long flags;
  	int i;
  
-@@ -7937,13 +7998,13 @@ static ssize_t show_rate(struct device *d,
+@@ -7937,13 +8027,13 @@ static ssize_t show_rate(struct device *d,
  		i = priv->stations[IWL_STA_ID].current_rate.s.rate;
  	spin_unlock_irqrestore(&priv->sta_lock, flags);
  
@@ -612121,7 +632710,7 @@
  }
  
  static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
-@@ -7952,7 +8013,7 @@ static ssize_t store_retry_rate(struct device *d,
+@@ -7952,7 +8042,7 @@ static ssize_t store_retry_rate(struct device *d,
  				struct device_attribute *attr,
  				const char *buf, size_t count)
  {
@@ -612130,7 +632719,7 @@
  
  	priv->retry_rate = simple_strtoul(buf, NULL, 0);
  	if (priv->retry_rate <= 0)
-@@ -7964,7 +8025,7 @@ static ssize_t store_retry_rate(struct device *d,
+@@ -7964,7 +8054,7 @@ static ssize_t store_retry_rate(struct device *d,
  static ssize_t show_retry_rate(struct device *d,
  			       struct device_attribute *attr, char *buf)
  {
@@ -612139,7 +632728,7 @@
  	return sprintf(buf, "%d", priv->retry_rate);
  }
  
-@@ -7975,14 +8036,14 @@ static ssize_t store_power_level(struct device *d,
+@@ -7975,14 +8065,14 @@ static ssize_t store_power_level(struct device *d,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
  {
@@ -612156,7 +632745,7 @@
  		rc = -EAGAIN;
  		goto out;
  	}
-@@ -7993,7 +8054,7 @@ static ssize_t store_power_level(struct device *d,
+@@ -7993,7 +8083,7 @@ static ssize_t store_power_level(struct device *d,
  		mode |= IWL_POWER_ENABLED;
  
  	if (mode != priv->power_mode) {
@@ -612165,7 +632754,7 @@
  		if (rc) {
  			IWL_DEBUG_MAC80211("failed setting power mode.\n");
  			goto out;
-@@ -8029,7 +8090,7 @@ static const s32 period_duration[] = {
+@@ -8029,7 +8119,7 @@ static const s32 period_duration[] = {
  static ssize_t show_power_level(struct device *d,
  				struct device_attribute *attr, char *buf)
  {
@@ -612174,7 +632763,7 @@
  	int level = IWL_POWER_LEVEL(priv->power_mode);
  	char *p = buf;
  
-@@ -8064,18 +8125,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+@@ -8064,18 +8154,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
  static ssize_t show_channels(struct device *d,
  			     struct device_attribute *attr, char *buf)
  {
@@ -612197,7 +632786,7 @@
  	if (hw_mode) {
  		channels = hw_mode->channels;
  		count = hw_mode->num_channels;
-@@ -8102,7 +8163,7 @@ static ssize_t show_channels(struct device *d,
+@@ -8102,7 +8192,7 @@ static ssize_t show_channels(struct device *d,
  			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
  			       "active/passive" : "passive only");
  
@@ -612206,7 +632795,7 @@
  	if (hw_mode) {
  		channels = hw_mode->channels;
  		count = hw_mode->num_channels;
-@@ -8138,17 +8199,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+@@ -8138,17 +8228,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
  static ssize_t show_statistics(struct device *d,
  			       struct device_attribute *attr, char *buf)
  {
@@ -612228,7 +632817,7 @@
  	mutex_unlock(&priv->mutex);
  
  	if (rc) {
-@@ -8176,9 +8237,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+@@ -8176,9 +8266,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
  static ssize_t show_antenna(struct device *d,
  			    struct device_attribute *attr, char *buf)
  {
@@ -612240,7 +632829,7 @@
  		return -EAGAIN;
  
  	return sprintf(buf, "%d\n", priv->antenna);
-@@ -8189,7 +8250,7 @@ static ssize_t store_antenna(struct device *d,
+@@ -8189,7 +8279,7 @@ static ssize_t store_antenna(struct device *d,
  			     const char *buf, size_t count)
  {
  	int ant;
@@ -612249,7 +632838,7 @@
  
  	if (count == 0)
  		return 0;
-@@ -8201,7 +8262,7 @@ static ssize_t store_antenna(struct device *d,
+@@ -8201,7 +8291,7 @@ static ssize_t store_antenna(struct device *d,
  
  	if ((ant >= 0) && (ant <= 2)) {
  		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
@@ -612258,7 +632847,7 @@
  	} else
  		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
  
-@@ -8214,8 +8275,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+@@ -8214,8 +8304,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
  static ssize_t show_status(struct device *d,
  			   struct device_attribute *attr, char *buf)
  {
@@ -612269,7 +632858,7 @@
  		return -EAGAIN;
  	return sprintf(buf, "0x%08x\n", (int)priv->status);
  }
-@@ -8229,7 +8290,7 @@ static ssize_t dump_error_log(struct device *d,
+@@ -8229,7 +8319,7 @@ static ssize_t dump_error_log(struct device *d,
  	char *p = (char *)buf;
  
  	if (p[0] == '1')
@@ -612278,7 +632867,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -8243,7 +8304,7 @@ static ssize_t dump_event_log(struct device *d,
+@@ -8243,7 +8333,7 @@ static ssize_t dump_event_log(struct device *d,
  	char *p = (char *)buf;
  
  	if (p[0] == '1')
@@ -612287,7 +632876,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -8256,34 +8317,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+@@ -8256,34 +8346,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
   *
   *****************************************************************************/
  
@@ -612340,7 +632929,7 @@
  
  	cancel_delayed_work_sync(&priv->init_alive_start);
  	cancel_delayed_work(&priv->scan_check);
-@@ -8292,14 +8353,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+@@ -8292,14 +8382,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
  	cancel_work_sync(&priv->beacon_update);
  }
  
@@ -612357,7 +632946,7 @@
  	&dev_attr_measurement.attr,
  #endif
  	&dev_attr_power_level.attr,
-@@ -8316,45 +8377,48 @@ static struct attribute *iwl_sysfs_entries[] = {
+@@ -8316,45 +8406,48 @@ static struct attribute *iwl_sysfs_entries[] = {
  	NULL
  };
  
@@ -612431,7 +633020,7 @@
  		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
  			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
  		err = -EINVAL;
-@@ -8363,7 +8427,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8363,7 +8456,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	/* mac80211 allocates memory for this device instance, including
  	 *   space for this driver's private structure */
@@ -612440,7 +633029,7 @@
  	if (hw == NULL) {
  		IWL_ERROR("Can not allocate network device\n");
  		err = -ENOMEM;
-@@ -8378,9 +8442,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8378,9 +8471,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	priv->hw = hw;
  
  	priv->pci_dev = pdev;
@@ -612455,7 +633044,7 @@
  	atomic_set(&priv->restrict_refcnt, 0);
  #endif
  	priv->retry_rate = 1;
-@@ -8399,6 +8465,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8399,6 +8494,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	/* Tell mac80211 our Tx characteristics */
  	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
  
@@ -612463,7 +633052,7 @@
  	hw->queues = 4;
  
  	spin_lock_init(&priv->lock);
-@@ -8419,7 +8486,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8419,7 +8515,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	pci_set_master(pdev);
  
@@ -612473,7 +633062,7 @@
  
  	priv->data_retry_limit = -1;
  	priv->ieee_channels = NULL;
-@@ -8438,9 +8506,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8438,9 +8535,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	err = pci_request_regions(pdev, DRV_NAME);
  	if (err)
  		goto out_pci_disable_device;
@@ -612485,7 +633074,7 @@
  	priv->hw_base = pci_iomap(pdev, 0, 0);
  	if (!priv->hw_base) {
  		err = -ENODEV;
-@@ -8453,7 +8523,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8453,7 +8552,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	/* Initialize module parameter values here */
  
@@ -612495,7 +633084,7 @@
  		set_bit(STATUS_RF_KILL_SW, &priv->status);
  		IWL_DEBUG_INFO("Radio disabled.\n");
  	}
-@@ -8488,78 +8559,82 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8488,78 +8588,99 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	       priv->is_abg ? "A" : "");
  
  	/* Device-specific setup */
@@ -612536,24 +633125,17 @@
 +	iwl3945_disable_interrupts(priv);
  
 -	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
--	if (err) {
++	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+ 	if (err) {
 -		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
 -		goto out_disable_msi;
--	}
--
++		IWL_ERROR("failed to create sysfs device attributes\n");
++		goto out_release_irq;
+ 	}
+ 
 -	mutex_lock(&priv->mutex);
 -
 -	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
-+	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
- 	if (err) {
- 		IWL_ERROR("failed to create sysfs device attributes\n");
--		mutex_unlock(&priv->mutex);
- 		goto out_release_irq;
- 	}
- 
--	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
--	 * ucode filename and max sizes are card-specific. */
--	err = iwl_read_ucode(priv);
 +	/* nic init */
 +	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 +                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
@@ -612569,9 +633151,9 @@
 +	/* Read the EEPROM */
 +	err = iwl3945_eeprom_init(priv);
  	if (err) {
--		IWL_ERROR("Could not read microcode: %d\n", err);
+-		IWL_ERROR("failed to create sysfs device attributes\n");
 -		mutex_unlock(&priv->mutex);
--		goto out_pci_alloc;
+-		goto out_release_irq;
 +		IWL_ERROR("Unable to init EEPROM\n");
 +		goto out_remove_sysfs;
  	}
@@ -612580,14 +633162,32 @@
 +	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
 +	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
  
+-	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+-	 * ucode filename and max sizes are card-specific. */
+-	err = iwl_read_ucode(priv);
++	err = iwl3945_init_channel_map(priv);
+ 	if (err) {
+-		IWL_ERROR("Could not read microcode: %d\n", err);
+-		mutex_unlock(&priv->mutex);
+-		goto out_pci_alloc;
++		IWL_ERROR("initializing regulatory failed: %d\n", err);
++		goto out_remove_sysfs;
+ 	}
+ 
 -	mutex_unlock(&priv->mutex);
--
++	err = iwl3945_init_geos(priv);
++	if (err) {
++		IWL_ERROR("initializing geos failed: %d\n", err);
++		goto out_free_channel_map;
++	}
++	iwl3945_reset_channel_flag(priv);
+ 
 -	IWL_DEBUG_INFO("Queing UP work.\n");
 +	iwl3945_rate_control_register(priv->hw);
 +	err = ieee80211_register_hw(priv->hw);
 +	if (err) {
 +		IWL_ERROR("Failed to register network device (error %d)\n", err);
-+		goto out_remove_sysfs;
++		goto out_free_geos;
 +	}
  
 -	queue_work(priv->workqueue, &priv->up);
@@ -612602,6 +633202,10 @@
 -	iwl_dealloc_ucode_pci(priv);
 -
 -	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
++ out_free_geos:
++	iwl3945_free_geos(priv);
++ out_free_channel_map:
++	iwl3945_free_channel_map(priv);
 + out_remove_sysfs:
 +	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
  
@@ -612617,7 +633221,7 @@
  
   out_iounmap:
  	pci_iounmap(pdev, priv->hw_base);
-@@ -8574,9 +8649,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8574,9 +8695,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	return err;
  }
  
@@ -612629,7 +633233,7 @@
  	struct list_head *p, *q;
  	int i;
  
-@@ -8587,43 +8662,41 @@ static void iwl_pci_remove(struct pci_dev *pdev)
+@@ -8587,52 +8708,48 @@ static void iwl_pci_remove(struct pci_dev *pdev)
  
  	set_bit(STATUS_EXIT_PENDING, &priv->status);
  
@@ -612683,7 +633287,18 @@
  	pci_iounmap(pdev, priv->hw_base);
  	pci_release_regions(pdev);
  	pci_disable_device(pdev);
-@@ -8642,93 +8715,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
+ 	pci_set_drvdata(pdev, NULL);
+ 
+-	kfree(priv->channel_info);
+-
+-	kfree(priv->ieee_channels);
+-	kfree(priv->ieee_rates);
++	iwl3945_free_channel_map(priv);
++	iwl3945_free_geos(priv);
+ 
+ 	if (priv->ibss_beacon)
+ 		dev_kfree_skb(priv->ibss_beacon);
+@@ -8642,93 +8759,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
  
  #ifdef CONFIG_PM
  
@@ -612691,13 +633306,13 @@
 +static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state)
  {
 -	struct iwl_priv *priv = pci_get_drvdata(pdev);
-+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
- 
+-
 -	set_bit(STATUS_IN_SUSPEND, &priv->status);
 -
 -	/* Take down the device; powers it off, etc. */
 -	iwl_down(priv);
--
++	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
+ 
 -	if (priv->mac80211_registered)
 -		ieee80211_stop_queues(priv->hw);
 +	if (priv->is_open) {
@@ -612789,7 +633404,7 @@
  	return 0;
  }
  
-@@ -8740,33 +8751,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
+@@ -8740,33 +8795,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
   *
   *****************************************************************************/
  
@@ -612834,7 +633449,7 @@
  		return ret;
  	}
  #endif
-@@ -8774,32 +8785,32 @@ static int __init iwl_init(void)
+@@ -8774,32 +8829,32 @@ static int __init iwl_init(void)
  	return ret;
  }
  
@@ -612881,7 +633496,7 @@
 +module_exit(iwl3945_exit);
 +module_init(iwl3945_init);
 diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
-index 15a45f4..c86da5c 100644
+index 15a45f4..bf3a60c 100644
 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
 +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
 @@ -27,16 +27,6 @@
@@ -614230,7 +634845,7 @@
  
  	return rc;
  }
-@@ -1569,22 +1634,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+@@ -1569,22 +1634,28 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
   *
   ******************************************************************************/
  
@@ -614240,6 +634855,12 @@
  	memcpy(mac, priv->eeprom.mac_address, 6);
  }
  
++static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
++{
++	iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
++		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
++}
++
  /**
 - * iwl_eeprom_init - read EEPROM contents
 + * iwl4965_eeprom_init - read EEPROM contents
@@ -614259,7 +634880,7 @@
  	u32 r;
  	int sz = sizeof(priv->eeprom);
  	int rc;
-@@ -1602,20 +1667,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
+@@ -1602,20 +1673,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
  		return -ENOENT;
  	}
  
@@ -614286,7 +634907,7 @@
  			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
  				break;
  			udelay(IWL_EEPROM_ACCESS_DELAY);
-@@ -1626,12 +1692,12 @@ int iwl_eeprom_init(struct iwl_priv *priv)
+@@ -1626,12 +1698,12 @@ int iwl_eeprom_init(struct iwl_priv *priv)
  			rc = -ETIMEDOUT;
  			goto done;
  		}
@@ -614301,7 +634922,7 @@
  	return rc;
  }
  
-@@ -1640,22 +1706,20 @@ done:
+@@ -1640,22 +1712,20 @@ done:
   * Misc. internal state and helper functions
   *
   ******************************************************************************/
@@ -614331,7 +634952,7 @@
  		      struct ieee80211_hdr *header, int group100)
  {
  	u32 to_us;
-@@ -1677,9 +1741,9 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1677,9 +1747,9 @@ void iwl_report_frame(struct iwl_priv *priv,
  	u8 agc;
  	u16 sig_avg;
  	u16 noise_diff;
@@ -614344,7 +634965,7 @@
  	u8 *data = IWL_RX_DATA(pkt);
  
  	/* MAC header */
-@@ -1755,11 +1819,11 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1755,11 +1825,11 @@ void iwl_report_frame(struct iwl_priv *priv,
  		else
  			title = "Frame";
  
@@ -614358,7 +634979,7 @@
  
  		/* print frame summary.
  		 * MAC addresses show just the last byte (for brevity),
-@@ -1781,25 +1845,25 @@ void iwl_report_frame(struct iwl_priv *priv,
+@@ -1781,25 +1851,25 @@ void iwl_report_frame(struct iwl_priv *priv,
  		}
  	}
  	if (print_dump)
@@ -614389,7 +635010,7 @@
  				    u16 basic_rate, int *left)
  {
  	u16 ret_rates = 0, bit;
-@@ -1810,7 +1874,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+@@ -1810,7 +1880,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
  		if (bit & supported_rate) {
  			ret_rates |= bit;
@@ -614398,7 +635019,7 @@
  				((bit & basic_rate) ? 0x80 : 0x00);
  			(*cnt)++;
  			(*left)--;
-@@ -1823,22 +1887,25 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+@@ -1823,22 +1893,25 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  	return ret_rates;
  }
  
@@ -614431,7 +635052,7 @@
  
  	/* Make sure there is enough space for the probe request,
  	 * two mandatory IEs and the data */
-@@ -1848,9 +1915,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1848,9 +1921,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	len += 24;
  
  	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
@@ -614443,7 +635064,7 @@
  	frame->seq_ctrl = 0;
  
  	/* fill in our indirect SSID IE */
-@@ -1888,17 +1955,19 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1888,17 +1961,19 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	*pos++ = WLAN_EID_SUPP_RATES;
  	*pos = 0;
  
@@ -614470,7 +635091,7 @@
  	active_rates &= ~ret_rates;
  
  	len += 2 + *pos;
-@@ -1914,25 +1983,22 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1914,25 +1989,22 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  	/* ... fill it in... */
  	*pos++ = WLAN_EID_EXT_SUPP_RATES;
  	*pos = 0;
@@ -614506,7 +635127,7 @@
  
   fill_end:
  	return (u16)len;
-@@ -1941,16 +2007,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+@@ -1941,16 +2013,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
  /*
   * QoS  support
  */
@@ -614529,7 +635150,7 @@
  {
  	u16 cw_min = 15;
  	u16 cw_max = 1023;
-@@ -2037,13 +2103,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
+@@ -2037,13 +2109,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -614544,7 +635165,7 @@
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
  		return;
  
-@@ -2057,23 +2120,28 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+@@ -2057,23 +2126,28 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
  	    !priv->qos_data.qos_cap.q_AP.txop_request)
  		priv->qos_data.def_qos_parm.qos_flags |=
  			QOS_PARAM_FLG_TXOP_TYPE_MSK;
@@ -614579,7 +635200,7 @@
  /*
   * Power management (not Tx power!) functions
   */
-@@ -2091,7 +2159,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+@@ -2091,7 +2165,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
  
  /* default power management (not Tx power) table values */
  /* for tim  0-10 */
@@ -614588,7 +635209,7 @@
  	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
-@@ -2101,7 +2169,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+@@ -2101,7 +2175,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
  };
  
  /* for tim > 10 */
@@ -614597,7 +635218,7 @@
  	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
  	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
  		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
-@@ -2114,11 +2182,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+@@ -2114,11 +2188,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
  		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
  };
  
@@ -614612,7 +635233,7 @@
  	u16 pci_pm;
  
  	IWL_DEBUG_POWER("Initialize power \n");
-@@ -2137,7 +2205,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
+@@ -2137,7 +2211,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
  	if (rc != 0)
  		return 0;
  	else {
@@ -614621,7 +635242,7 @@
  
  		IWL_DEBUG_POWER("adjust power command flags\n");
  
-@@ -2153,15 +2221,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
+@@ -2153,15 +2227,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
  	return rc;
  }
  
@@ -614641,7 +635262,7 @@
  
  	if (mode > IWL_POWER_INDEX_5) {
  		IWL_DEBUG_POWER("Error invalid power mode \n");
-@@ -2174,7 +2242,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
+@@ -2174,7 +2248,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
  	else
  		range = &pow_data->pwr_range_1[1];
  
@@ -614650,7 +635271,7 @@
  
  #ifdef IWL_MAC80211_DISABLE
  	if (priv->assoc_network != NULL) {
-@@ -2217,14 +2285,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
+@@ -2217,14 +2291,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
  	return rc;
  }
  
@@ -614669,7 +635290,7 @@
  	 * else user level */
  	switch (mode) {
  	case IWL_POWER_BATTERY:
-@@ -2240,9 +2308,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+@@ -2240,9 +2314,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
  
  	cmd.keep_alive_beacons = 0;
  
@@ -614681,7 +635302,7 @@
  
  	if (final_mode == IWL_POWER_MODE_CAM)
  		clear_bit(STATUS_POWER_PMI, &priv->status);
-@@ -2252,7 +2320,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+@@ -2252,7 +2326,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
  	return rc;
  }
  
@@ -614690,7 +635311,7 @@
  {
  	/* Filter incoming packets to determine if they are targeted toward
  	 * this network, discarding packets coming from ourselves */
-@@ -2282,7 +2350,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -2282,7 +2356,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  
  #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
  
@@ -614699,7 +635320,7 @@
  {
  	switch (status & TX_STATUS_MSK) {
  	case TX_STATUS_SUCCESS:
-@@ -2309,11 +2377,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
+@@ -2309,11 +2383,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
  }
  
  /**
@@ -614713,7 +635334,7 @@
  {
  	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
  		clear_bit(STATUS_SCANNING, &priv->status);
-@@ -2336,17 +2404,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
+@@ -2336,17 +2410,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
  }
  
  /**
@@ -614734,7 +635355,7 @@
  	if (ret && ms) {
  		mutex_unlock(&priv->mutex);
  		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
-@@ -2360,7 +2428,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+@@ -2360,7 +2434,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
  	return ret;
  }
  
@@ -614743,7 +635364,7 @@
  {
  	/* Reset ieee stats */
  
-@@ -2371,13 +2439,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
+@@ -2371,13 +2445,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
  	priv->last_frag_num = -1;
  	priv->last_packet_time = 0;
  
@@ -614759,7 +635380,7 @@
  {
  	u16 new_val = 0;
  	u16 beacon_factor = 0;
-@@ -2390,7 +2458,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+@@ -2390,7 +2464,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
  	return cpu_to_le16(new_val);
  }
  
@@ -614768,7 +635389,7 @@
  {
  	u64 interval_tm_unit;
  	u64 tsf, result;
-@@ -2420,14 +2488,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+@@ -2420,14 +2494,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
  			priv->rxon_timing.beacon_interval =
  				cpu_to_le16(beacon_int);
  			priv->rxon_timing.beacon_interval =
@@ -614785,7 +635406,7 @@
  		/* TODO: we need to get atim_window from upper stack
  		 * for now we set to 0 */
  		priv->rxon_timing.atim_window = 0;
-@@ -2446,14 +2514,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+@@ -2446,14 +2520,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
  		le16_to_cpu(priv->rxon_timing.atim_window));
  }
  
@@ -614802,7 +635423,7 @@
  		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
  		return -EIO;
  	}
-@@ -2480,9 +2548,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
+@@ -2480,9 +2554,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
  	return 0;
  }
  
@@ -614814,7 +635435,7 @@
  
  	if (hw_decrypt)
  		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
-@@ -2492,7 +2560,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+@@ -2492,7 +2566,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
  	return 0;
  }
  
@@ -614823,7 +635444,7 @@
  {
  	if (phymode == MODE_IEEE80211A) {
  		priv->staging_rxon.flags &=
-@@ -2500,7 +2568,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+@@ -2500,7 +2574,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
  		      | RXON_FLG_CCK_MSK);
  		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
  	} else {
@@ -614832,7 +635453,7 @@
  		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
  			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
  		else
-@@ -2516,11 +2584,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+@@ -2516,11 +2590,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
  }
  
  /*
@@ -614847,7 +635468,7 @@
  
  	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
  
-@@ -2557,7 +2625,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2557,7 +2631,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
  #endif
  
@@ -614856,7 +635477,7 @@
  				       le16_to_cpu(priv->staging_rxon.channel));
  
  	if (!ch_info)
-@@ -2577,7 +2645,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2577,7 +2651,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  	else
  		priv->phymode = MODE_IEEE80211G;
  
@@ -614865,7 +635486,7 @@
  
  	priv->staging_rxon.ofdm_basic_rates =
  	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-@@ -2593,15 +2661,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+@@ -2593,15 +2667,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
  	iwl4965_set_rxon_chain(priv);
  }
  
@@ -614884,7 +635505,7 @@
  			priv->phymode,
  			le16_to_cpu(priv->staging_rxon.channel));
  
-@@ -2612,32 +2677,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
+@@ -2612,32 +2683,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
  		}
  	}
  
@@ -614933,7 +635554,7 @@
  
  	switch (keyinfo->alg) {
  	case ALG_CCMP:
-@@ -2680,8 +2749,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+@@ -2680,8 +2755,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
  /*
   * handle build REPLY_TX command notification.
   */
@@ -614944,7 +635565,7 @@
  				  struct ieee80211_tx_control *ctrl,
  				  struct ieee80211_hdr *hdr,
  				  int is_unicast, u8 std_id)
-@@ -2703,6 +2772,10 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+@@ -2703,6 +2778,10 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
  		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
  	}
  
@@ -614955,7 +635576,7 @@
  	cmd->cmd.tx.sta_id = std_id;
  	if (ieee80211_get_morefrag(hdr))
  		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-@@ -2729,11 +2802,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+@@ -2729,11 +2808,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
  	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
  		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
  		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
@@ -614969,7 +635590,7 @@
  	} else
  		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
  
-@@ -2742,40 +2813,47 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+@@ -2742,40 +2819,47 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
  	cmd->cmd.tx.next_frame_len = 0;
  }
  
@@ -615027,7 +635648,7 @@
  
  		if (sta_id != IWL_INVALID_STATION)
  			return sta_id;
-@@ -2783,11 +2861,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+@@ -2783,11 +2867,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
  		IWL_DEBUG_DROP("Station %s not in station map. "
  			       "Defaulting to broadcast...\n",
  			       print_mac(mac, hdr->addr1));
@@ -615041,7 +635662,7 @@
  		return priv->hw_setting.bcast_sta_id;
  	}
  }
-@@ -2795,18 +2873,19 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+@@ -2795,18 +2879,19 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
  /*
   * start REPLY_TX command process
   */
@@ -615066,7 +635687,7 @@
  	u16 len, idx, len_org;
  	u8 id, hdr_len, unicast;
  	u8 sta_id;
-@@ -2818,13 +2897,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2818,13 +2903,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  	int rc;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -615083,7 +635704,7 @@
  		goto drop_unlock;
  	}
  
-@@ -2838,7 +2917,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2838,7 +2923,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  
  	fc = le16_to_cpu(hdr->frame_control);
  
@@ -615092,15 +635713,18 @@
  	if (ieee80211_is_auth(fc))
  		IWL_DEBUG_TX("Sending AUTH frame\n");
  	else if (ieee80211_is_assoc_request(fc))
-@@ -2847,16 +2926,19 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2847,16 +2932,21 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  		IWL_DEBUG_TX("Sending REASSOC frame\n");
  #endif
  
 -	if (!iwl_is_associated(priv) &&
-+	/* drop all data frame if we are not associated */
-+	if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
- 	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+-	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
 -		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
++	/* drop all data frame if we are not associated */
++	if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
++	   (!iwl4965_is_associated(priv) ||
++	    !priv->assoc_id ||
++	    !priv->assoc_station_added)) {
 +		IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
  		goto drop_unlock;
  	}
@@ -615115,7 +635739,7 @@
  	if (sta_id == IWL_INVALID_STATION) {
  		DECLARE_MAC_BUF(mac);
  
-@@ -2876,40 +2958,62 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2876,40 +2966,62 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  			(hdr->seq_ctrl &
  				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
  		seq_number += 0x10;
@@ -615191,7 +635815,7 @@
  
  	len_org = len;
  	len = (len + 3) & ~3;
-@@ -2919,36 +3023,53 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2919,36 +3031,53 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  	else
  		len_org = 0;
  
@@ -615255,7 +635879,7 @@
  
  	if (!ieee80211_get_morefrag(hdr)) {
  		txq->need_update = 1;
-@@ -2961,27 +3082,29 @@ static int iwl_tx_skb(struct iwl_priv *priv,
+@@ -2961,27 +3090,29 @@ static int iwl_tx_skb(struct iwl_priv *priv,
  		txq->need_update = 0;
  	}
  
@@ -615291,7 +635915,7 @@
  			spin_unlock_irqrestore(&priv->lock, flags);
  		}
  
-@@ -2996,13 +3119,13 @@ drop:
+@@ -2996,13 +3127,13 @@ drop:
  	return -1;
  }
  
@@ -615307,7 +635931,7 @@
  	if (!hw) {
  		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
  		return;
-@@ -3020,7 +3143,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -3020,7 +3151,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  		if ((rate->val < IWL_RATE_COUNT) &&
  		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
  			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
@@ -615316,7 +635940,7 @@
  				       (rate->flags & IEEE80211_RATE_BASIC) ?
  				       "*" : "");
  			priv->active_rate |= (1 << rate->val);
-@@ -3028,7 +3151,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -3028,7 +3159,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  				priv->active_rate_basic |= (1 << rate->val);
  		} else
  			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
@@ -615325,7 +635949,7 @@
  	}
  
  	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
-@@ -3057,7 +3180,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
+@@ -3057,7 +3188,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
  		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
  }
  
@@ -615334,7 +635958,7 @@
  {
  	unsigned long flags;
  
-@@ -3068,21 +3191,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -3068,21 +3199,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  			  disable_radio ? "OFF" : "ON");
  
  	if (disable_radio) {
@@ -615360,7 +635984,7 @@
  
  	clear_bit(STATUS_RF_KILL_SW, &priv->status);
  	spin_unlock_irqrestore(&priv->lock, flags);
-@@ -3091,9 +3214,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -3091,9 +3222,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  	msleep(10);
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -615373,7 +635997,7 @@
  	spin_unlock_irqrestore(&priv->lock, flags);
  
  	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-@@ -3106,7 +3229,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+@@ -3106,7 +3237,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
  	return;
  }
  
@@ -615382,7 +636006,7 @@
  			    u32 decrypt_res, struct ieee80211_rx_status *stats)
  {
  	u16 fc =
-@@ -3138,97 +3261,10 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+@@ -3138,97 +3269,10 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
  	}
  }
  
@@ -615481,7 +636105,7 @@
  {
  	u16 sc = le16_to_cpu(header->seq_ctrl);
  	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-@@ -3239,29 +3275,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3239,29 +3283,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  	switch (priv->iw_mode) {
  	case IEEE80211_IF_TYPE_IBSS:{
  		struct list_head *p;
@@ -615515,7 +636139,7 @@
  			return 0;
  		}
  		last_seq = &entry->seq_num;
-@@ -3295,7 +3328,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3295,7 +3336,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  	return 1;
  }
  
@@ -615524,7 +636148,7 @@
  
  #include "iwl-spectrum.h"
  
-@@ -3310,7 +3343,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+@@ -3310,7 +3351,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
   * the lower 3 bytes is the time in usec within one beacon interval
   */
  
@@ -615533,7 +636157,7 @@
  {
  	u32 quot;
  	u32 rem;
-@@ -3329,7 +3362,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+@@ -3329,7 +3370,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
   * the same as HW timer counter counting down
   */
  
@@ -615542,7 +636166,7 @@
  {
  	u32 base_low = base & BEACON_TIME_MASK_LOW;
  	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
-@@ -3348,13 +3381,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+@@ -3348,13 +3389,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
  	return cpu_to_le32(res);
  }
  
@@ -615560,7 +636184,7 @@
  		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
  		.data = (void *)&spectrum,
  		.meta.flags = CMD_WANT_SKB,
-@@ -3364,9 +3397,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3364,9 +3405,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  	int spectrum_resp_status;
  	int duration = le16_to_cpu(params->duration);
  
@@ -615572,7 +636196,7 @@
  			le64_to_cpu(params->start_time) - priv->last_tsf,
  			le16_to_cpu(priv->rxon_timing.beacon_interval));
  
-@@ -3379,9 +3412,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3379,9 +3420,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  	cmd.len = sizeof(spectrum);
  	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
  
@@ -615584,7 +636208,7 @@
  				add_time,
  				le16_to_cpu(priv->rxon_timing.beacon_interval));
  	else
-@@ -3394,11 +3427,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3394,11 +3435,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
  		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
  
@@ -615598,7 +636222,7 @@
  	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
  		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
  		rc = -EIO;
-@@ -3428,8 +3461,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
+@@ -3428,8 +3469,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
  }
  #endif
  
@@ -615609,7 +636233,7 @@
  {
  
  	tx_sta->status.ack_signal = 0;
-@@ -3448,41 +3481,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+@@ -3448,41 +3489,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
  }
  
  /**
@@ -615667,7 +636291,7 @@
  			(txq_id != IWL_CMD_QUEUE_NUM) &&
  			priv->mac80211_registered)
  		ieee80211_wake_queue(priv->hw, txq_id);
-@@ -3491,7 +3524,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+@@ -3491,7 +3532,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
  	return nfreed;
  }
  
@@ -615676,7 +636300,7 @@
  {
  	status &= TX_STATUS_MSK;
  	return (status == TX_STATUS_SUCCESS)
-@@ -3503,22 +3536,22 @@ static int iwl_is_tx_success(u32 status)
+@@ -3503,22 +3544,22 @@ static int iwl_is_tx_success(u32 status)
   * Generic RX handler implementations
   *
   ******************************************************************************/
@@ -615705,7 +636329,7 @@
  {
  	if (priv->txq[txq_id].txb[idx].skb[0])
  		return (struct ieee80211_hdr *)priv->txq[txq_id].
-@@ -3526,16 +3559,20 @@ static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
+@@ -3526,16 +3567,20 @@ static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
  	return NULL;
  }
  
@@ -615730,7 +636354,7 @@
  				      u16 start_idx)
  {
  	u32 status;
-@@ -3547,15 +3584,17 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+@@ -3547,15 +3592,17 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
  	u16 seq;
  
  	if (agg->wait_for_ba)
@@ -615750,7 +636374,7 @@
  		status = le32_to_cpu(frame_status[0]);
  
  		txq_id = agg->txq_id;
-@@ -3564,28 +3603,30 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+@@ -3564,28 +3611,30 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
  		IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
  				   agg->frame_count, agg->start_idx);
  
@@ -615785,7 +636409,7 @@
  		for (i = 0; i < agg->frame_count; i++) {
  			u16 sc;
  			status = le32_to_cpu(frame_status[i]);
-@@ -3600,7 +3641,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+@@ -3600,7 +3649,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
  			IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
  					   agg->frame_count, txq_id, idx);
  
@@ -615794,7 +636418,7 @@
  
  			sc = le16_to_cpu(hdr->seq_ctrl);
  			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-@@ -3649,19 +3690,22 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+@@ -3649,19 +3698,22 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
  #endif
  #endif
  
@@ -615824,7 +636448,7 @@
  	int tid, sta_id;
  #endif
  #endif
-@@ -3669,18 +3713,18 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
+@@ -3669,18 +3721,18 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
  	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
  		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
  			  "is out of range [0-%d] %d %d\n", txq_id,
@@ -615850,7 +636474,7 @@
  		__le16 *qc = ieee80211_get_qos_ctrl(hdr);
  
  		if (qc == NULL) {
-@@ -3690,7 +3734,7 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
+@@ -3690,7 +3742,7 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
  
  		tid = le16_to_cpu(*qc) & 0xf;
  
@@ -615859,7 +636483,7 @@
  		if (unlikely(sta_id == IWL_INVALID_STATION)) {
  			IWL_ERROR("Station not known for\n");
  			return;
-@@ -3701,20 +3745,20 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
+@@ -3701,20 +3753,20 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
  		iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
  
  		if ((tx_resp->frame_count == 1) &&
@@ -615887,7 +636511,7 @@
  
  	tx_status->retry_count = tx_resp->failure_frame;
  	tx_status->queue_number = status;
-@@ -3722,35 +3766,35 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
+@@ -3722,35 +3774,35 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
  	tx_status->queue_length |= tx_resp->failure_rts;
  
  	tx_status->flags =
@@ -615935,7 +636559,7 @@
  	struct delayed_work *pwork;
  
  	palive = &pkt->u.alive_frame;
-@@ -3764,12 +3808,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
+@@ -3764,12 +3816,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
  		IWL_DEBUG_INFO("Initialization Alive received.\n");
  		memcpy(&priv->card_alive_init,
  		       &pkt->u.alive_frame,
@@ -615950,7 +636574,7 @@
  		pwork = &priv->alive_start;
  	}
  
-@@ -3782,19 +3826,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
+@@ -3782,19 +3834,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
  		IWL_WARNING("uCode did not respond OK.\n");
  }
  
@@ -615976,7 +636600,7 @@
  
  	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
  		"seq 0x%04X ser 0x%08X\n",
-@@ -3807,23 +3851,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
+@@ -3807,23 +3859,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
  
  #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
  
@@ -616009,7 +636633,7 @@
  
  	if (!report->state) {
  		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
-@@ -3836,35 +3880,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+@@ -3836,35 +3888,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
  #endif
  }
  
@@ -616058,7 +636682,7 @@
  
  	if (!beacon) {
  		IWL_ERROR("update beacon failed\n");
-@@ -3879,16 +3923,16 @@ static void iwl_bg_beacon_update(struct work_struct *work)
+@@ -3879,16 +3931,16 @@ static void iwl_bg_beacon_update(struct work_struct *work)
  	priv->ibss_beacon = beacon;
  	mutex_unlock(&priv->mutex);
  
@@ -616082,7 +636706,7 @@
  
  	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
  		"tsf %d %d rate %d\n",
-@@ -3905,25 +3949,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+@@ -3905,25 +3957,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
  }
  
  /* Service response to REPLY_SCAN_CMD (0x80) */
@@ -616119,7 +636743,7 @@
  	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
  	IWL_DEBUG_SCAN("Scan start: "
  		       "%d [802.11%s] "
-@@ -3935,12 +3979,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+@@ -3935,12 +3987,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
  }
  
  /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -616137,7 +636761,7 @@
  
  	IWL_DEBUG_SCAN("Scan ch.res: "
  		       "%d [802.11%s] "
-@@ -3956,14 +4000,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+@@ -3956,14 +4008,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
  					(priv->last_scan_jiffies, jiffies)));
  
  	priv->last_scan_jiffies = jiffies;
@@ -616157,7 +636781,7 @@
  
  	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
  		       scan_notif->scanned_channels,
-@@ -3998,6 +4043,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+@@ -3998,6 +4051,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
  	}
  
  	priv->last_scan_jiffies = jiffies;
@@ -616165,7 +636789,7 @@
  	IWL_DEBUG_INFO("Setting scan to off\n");
  
  	clear_bit(STATUS_SCANNING, &priv->status);
-@@ -4016,10 +4062,10 @@ reschedule:
+@@ -4016,10 +4070,10 @@ reschedule:
  
  /* Handle notification from uCode that card's power state is changing
   * due to software, hardware, or critical temperature RFKILL */
@@ -616179,7 +636803,7 @@
  	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
  	unsigned long status = priv->status;
  
-@@ -4030,35 +4076,35 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -4030,35 +4084,35 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
  		     RF_CARD_DISABLED)) {
  
@@ -616227,7 +636851,7 @@
  		}
  	}
  
-@@ -4074,7 +4120,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -4074,7 +4128,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  		clear_bit(STATUS_RF_KILL_SW, &priv->status);
  
  	if (!(flags & RXON_CARD_DISABLED))
@@ -616236,7 +636860,7 @@
  
  	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
  	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
-@@ -4086,7 +4132,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -4086,7 +4140,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  }
  
  /**
@@ -616245,7 +636869,7 @@
   *
   * Setup the RX handlers for each of the reply types sent from the uCode
   * to the host.
-@@ -4094,61 +4140,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+@@ -4094,61 +4148,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
   * This function chains into the hardware specific files for them to setup
   * any hardware specific handlers as well.
   */
@@ -616336,7 +636960,7 @@
  
  	/* If a Tx command is being handled and it isn't in the actual
  	 * command queue then there a command routing bug has been introduced
-@@ -4169,7 +4212,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -4169,7 +4220,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
  		rxb->skb = NULL;
  
@@ -616345,7 +636969,7 @@
  
  	if (!(cmd->meta.flags & CMD_ASYNC)) {
  		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-@@ -4181,9 +4224,11 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -4181,9 +4232,11 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  /*
   * Rx theory of operation
   *
@@ -616360,7 +636984,7 @@
   *
   * Rx Queue Indexes
   * The host/firmware share two index registers for managing the Rx buffers.
-@@ -4199,10 +4244,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -4199,10 +4252,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   * The queue is empty (no good data) if WRITE = READ - 1, and is full if
   * WRITE = READ.
   *
@@ -616373,7 +636997,7 @@
   * and fire the RX interrupt.  The driver can then query the READ index and
   * process as many packets as possible, moving the WRITE index forward as it
   * resets the Rx queue buffers with new memory.
-@@ -4210,8 +4255,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -4210,8 +4263,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   * The management in the driver is as follows:
   * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
   *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
@@ -616384,7 +637008,7 @@
   *   iwl->rxq is replenished and the READ INDEX is updated (updating the
   *   'processed' and 'read' driver indexes as well)
   * + A received packet is processed and handed to the kernel network stack,
-@@ -4224,28 +4269,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+@@ -4224,28 +4277,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
   *
   * Driver sequence:
   *
@@ -616422,7 +637046,7 @@
  {
  	int s = q->read - q->write;
  	if (s <= 0)
-@@ -4258,15 +4303,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+@@ -4258,15 +4311,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
  }
  
  /**
@@ -616440,7 +637064,7 @@
  {
  	u32 reg = 0;
  	int rc = 0;
-@@ -4277,24 +4316,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+@@ -4277,24 +4324,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
  	if (q->need_update == 0)
  		goto exit_unlock;
  
@@ -616476,7 +637100,7 @@
  
  
  	q->need_update = 0;
-@@ -4305,11 +4349,9 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+@@ -4305,11 +4357,9 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
  }
  
  /**
@@ -616490,7 +637114,7 @@
  					  dma_addr_t dma_addr)
  {
  	return cpu_to_le32((u32)(dma_addr >> 8));
-@@ -4317,31 +4359,34 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+@@ -4317,31 +4367,34 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
  
  
  /**
@@ -616534,7 +637158,7 @@
  		rxq->queue[rxq->write] = rxb;
  		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
  		rxq->free_count--;
-@@ -4353,13 +4398,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
+@@ -4353,13 +4406,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
  		queue_work(priv->workqueue, &priv->rx_replenish);
  
  
@@ -616551,7 +637175,7 @@
  		if (rc)
  			return rc;
  	}
-@@ -4368,26 +4414,28 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
+@@ -4368,26 +4422,28 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
  }
  
  /**
@@ -616589,7 +637213,7 @@
  		if (!rxb->skb) {
  			if (net_ratelimit())
  				printk(KERN_CRIT DRV_NAME
-@@ -4399,32 +4447,55 @@ void iwl_rx_replenish(void *data)
+@@ -4399,32 +4455,55 @@ void iwl_rx_replenish(void *data)
  		}
  		priv->alloc_rxb_skb++;
  		list_del(element);
@@ -616650,7 +637274,7 @@
  			dev_kfree_skb(rxq->pool[i].skb);
  		}
  	}
-@@ -4434,21 +4505,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+@@ -4434,21 +4513,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
  	rxq->bd = NULL;
  }
  
@@ -616678,7 +637302,7 @@
  	/* Set us so that we have processed and used all buffers, but have
  	 * not restocked the Rx queue with fresh buffers */
  	rxq->read = rxq->write = 0;
-@@ -4457,7 +4532,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
+@@ -4457,7 +4540,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
  	return 0;
  }
  
@@ -616687,7 +637311,7 @@
  {
  	unsigned long flags;
  	int i;
-@@ -4471,7 +4546,8 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+@@ -4471,7 +4554,8 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
  		if (rxq->pool[i].skb != NULL) {
  			pci_unmap_single(priv->pci_dev,
  					 rxq->pool[i].dma_addr,
@@ -616697,7 +637321,7 @@
  			priv->alloc_rxb_skb--;
  			dev_kfree_skb(rxq->pool[i].skb);
  			rxq->pool[i].skb = NULL;
-@@ -4504,7 +4580,7 @@ static u8 ratio2dB[100] = {
+@@ -4504,7 +4588,7 @@ static u8 ratio2dB[100] = {
  /* Calculates a relative dB value from a ratio of linear
   *   (i.e. not dB) signal levels.
   * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
@@ -616706,7 +637330,7 @@
  {
  	/* 1000:1 or higher just report as 60 dB */
  	if (sig_ratio >= 1000)
-@@ -4530,7 +4606,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
+@@ -4530,7 +4614,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
  /* Calculate an indication of rx signal quality (a percentage, not dBm!).
   * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
   *   about formulas used below. */
@@ -616715,7 +637339,7 @@
  {
  	int sig_qual;
  	int degradation = PERFECT_RSSI - rssi_dbm;
-@@ -4565,32 +4641,39 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+@@ -4565,32 +4649,39 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
  }
  
  /**
@@ -616762,7 +637386,7 @@
  		 * then a bug has been introduced in the queue refilling
  		 * routines -- catch it here */
  		BUG_ON(rxb == NULL);
-@@ -4598,9 +4681,9 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4598,9 +4689,9 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		rxq->queue[i] = NULL;
  
  		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
@@ -616774,7 +637398,7 @@
  
  		/* Reclaim a command buffer only if this packet is a response
  		 *   to a (driver-originated) command.
-@@ -4617,7 +4700,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4617,7 +4708,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  
  		/* Based on type of command response or notification,
  		 *   handle those that need handling via function in
@@ -616783,7 +637407,7 @@
  		if (priv->rx_handlers[pkt->hdr.cmd]) {
  			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
  				"r = %d, i = %d, %s, 0x%02x\n", r, i,
-@@ -4632,11 +4715,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4632,11 +4723,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		}
  
  		if (reclaim) {
@@ -616798,7 +637422,7 @@
  			else
  				IWL_WARNING("Claim null rxb?\n");
  		}
-@@ -4651,20 +4734,34 @@ static void iwl_rx_handle(struct iwl_priv *priv)
+@@ -4651,20 +4742,34 @@ static void iwl_rx_handle(struct iwl_priv *priv)
  		}
  
  		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
@@ -616837,7 +637461,7 @@
  {
  	u32 reg = 0;
  	int rc = 0;
-@@ -4678,41 +4775,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+@@ -4678,41 +4783,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
  		/* wake up nic if it's powered down ...
  		 * uCode will wake up, and interrupt us again, so next
  		 * time we'll skip this part. */
@@ -616890,7 +637514,7 @@
  	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
  	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
  	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
-@@ -4729,24 +4826,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+@@ -4729,24 +4834,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
  }
  #endif
  
@@ -616921,7 +637545,7 @@
  	IWL_DEBUG_ISR("Disabled interrupts\n");
  }
  
-@@ -4773,7 +4870,7 @@ static const char *desc_lookup(int i)
+@@ -4773,7 +4878,7 @@ static const char *desc_lookup(int i)
  #define ERROR_START_OFFSET  (1 * sizeof(u32))
  #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
  
@@ -616930,7 +637554,7 @@
  {
  	u32 data2, line;
  	u32 desc, time, count, base, data1;
-@@ -4782,18 +4879,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4782,18 +4887,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  
  	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
  
@@ -616952,7 +637576,7 @@
  
  	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
  		IWL_ERROR("Start IWL Error Log Dump:\n");
-@@ -4801,15 +4898,15 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4801,15 +4906,15 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  			  priv->status, priv->config, count);
  	}
  
@@ -616977,7 +637601,7 @@
  
  	IWL_ERROR("Desc               Time       "
  		  "data1      data2      line\n");
-@@ -4819,17 +4916,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+@@ -4819,17 +4924,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
  	IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
  		  ilink1, ilink2);
  
@@ -616999,7 +637623,7 @@
  				u32 num_events, u32 mode)
  {
  	u32 i;
-@@ -4853,21 +4950,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+@@ -4853,21 +4958,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
  	/* "time" is actually "data" for mode 0 (no timestamp).
  	 * place event id # at far right for easier visual parsing. */
  	for (i = 0; i < num_events; i++) {
@@ -617025,7 +637649,7 @@
  {
  	int rc;
  	u32 base;       /* SRAM byte address of event log header */
-@@ -4878,29 +4975,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+@@ -4878,29 +4983,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
  	u32 size;       /* # entries that we'll print */
  
  	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
@@ -617062,7 +637686,7 @@
  		return;
  	}
  
-@@ -4910,31 +5007,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+@@ -4910,31 +5015,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
  	/* if uCode has wrapped back to top of log, start at the oldest entry,
  	 * i.e the next one that uCode would fill. */
  	if (num_wraps)
@@ -617105,7 +637729,7 @@
  	}
  #endif
  
-@@ -4948,7 +5045,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
+@@ -4948,7 +5053,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
  		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
  			  "Restarting adapter due to uCode error.\n");
  
@@ -617114,7 +637738,7 @@
  			memcpy(&priv->recovery_rxon, &priv->active_rxon,
  			       sizeof(priv->recovery_rxon));
  			priv->error_recovering = 1;
-@@ -4957,16 +5054,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
+@@ -4957,16 +5062,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
  	}
  }
  
@@ -617134,7 +637758,7 @@
  
  	spin_lock_irqsave(&priv->lock, flags);
  	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
-@@ -4974,12 +5071,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
+@@ -4974,12 +5079,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -617149,7 +637773,7 @@
  	u32 inta_mask;
  #endif
  
-@@ -4988,18 +5085,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -4988,18 +5093,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	/* Ack/clear/reset pending uCode interrupts.
  	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
  	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
@@ -617176,7 +637800,7 @@
  		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
  			      inta, inta_mask, inta_fh);
  	}
-@@ -5019,9 +5117,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5019,9 +5125,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
  
  		/* Tell the device to stop sending interrupts */
@@ -617188,7 +637812,7 @@
  
  		handled |= CSR_INT_BIT_HW_ERR;
  
-@@ -5030,8 +5128,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5030,11 +5136,12 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  		return;
  	}
  
@@ -617197,11 +637821,20 @@
 +#ifdef CONFIG_IWL4965_DEBUG
 +	if (iwl4965_debug_level & (IWL_DL_ISR)) {
  		/* NIC fires this, but we don't use it, redundant with WAKEUP */
- 		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
- 			IWL_DEBUG_ISR("Microcode started or stopped.\n");
-@@ -5044,10 +5142,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+-		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+-			IWL_DEBUG_ISR("Microcode started or stopped.\n");
++		if (inta & CSR_INT_BIT_SCD)
++			IWL_DEBUG_ISR("Scheduler finished to transmit "
++				      "the frame/frames.\n");
+ 
+ 		/* Alive notification via Rx interrupt will do the real work */
+ 		if (inta & CSR_INT_BIT_ALIVE)
+@@ -5042,12 +5149,12 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+ 	}
+ #endif
  	/* Safely ignore these bits for debug checks below */
- 	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+-	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
++	inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
  
 -	/* HW RF KILL switch toggled (4965 only) */
 +	/* HW RF KILL switch toggled */
@@ -617212,7 +637845,7 @@
  				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
  			hw_rf_kill = 1;
  
-@@ -5067,7 +5165,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5067,7 +5174,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  		handled |= CSR_INT_BIT_RF_KILL;
  	}
  
@@ -617221,7 +637854,7 @@
  	if (inta & CSR_INT_BIT_CT_KILL) {
  		IWL_ERROR("Microcode CT kill error detected.\n");
  		handled |= CSR_INT_BIT_CT_KILL;
-@@ -5077,20 +5175,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5077,20 +5184,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	if (inta & CSR_INT_BIT_SW_ERR) {
  		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
  			  inta);
@@ -617250,7 +637883,7 @@
  
  		handled |= CSR_INT_BIT_WAKEUP;
  	}
-@@ -5099,7 +5197,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5099,7 +5206,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	 * Rx "responses" (frame-received notification), and other
  	 * notifications from uCode come through here*/
  	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
@@ -617259,7 +637892,7 @@
  		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
  	}
  
-@@ -5118,13 +5216,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5118,13 +5225,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	}
  
  	/* Re-enable all interrupts */
@@ -617279,7 +637912,7 @@
  		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
  			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
  	}
-@@ -5132,9 +5230,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
+@@ -5132,9 +5239,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
  	spin_unlock_irqrestore(&priv->lock, flags);
  }
  
@@ -617291,7 +637924,7 @@
  	u32 inta, inta_mask;
  	u32 inta_fh;
  	if (!priv)
-@@ -5146,12 +5244,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
+@@ -5146,12 +5253,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
  	 *    back-to-back ISRs and sporadic interrupts from our NIC.
  	 * If we have something to service, the tasklet will re-enable ints.
  	 * If we *don't* have something, we'll re-enable before leaving here. */
@@ -617308,16 +637941,21 @@
  
  	/* Ignore interrupt if there's nothing in NIC to service.
  	 * This may be due to IRQ shared with another device,
-@@ -5171,7 +5269,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
+@@ -5171,8 +5278,11 @@ static irqreturn_t iwl_isr(int irq, void *data)
  	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
  		      inta, inta_mask, inta_fh);
  
 -	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+-	tasklet_schedule(&priv->irq_tasklet);
++	inta &= ~CSR_INT_BIT_SCD;
++
 +	/* iwl4965_irq_tasklet() will service interrupts and re-enable them */
- 	tasklet_schedule(&priv->irq_tasklet);
++	if (likely(inta || inta_fh))
++		tasklet_schedule(&priv->irq_tasklet);
  
   unplugged:
-@@ -5180,18 +5278,18 @@ static irqreturn_t iwl_isr(int irq, void *data)
+ 	spin_unlock(&priv->lock);
+@@ -5180,18 +5290,18 @@ static irqreturn_t iwl_isr(int irq, void *data)
  
   none:
  	/* re-enable interrupts here since we don't have anything to service. */
@@ -617339,7 +637977,7 @@
   * definition below maps to physical channel 42 in the 5.2GHz spectrum.
   * The specific geography and calibration information for that channel
   * is contained in the eeprom map itself.
-@@ -5217,76 +5315,77 @@ static irqreturn_t iwl_isr(int irq, void *data)
+@@ -5217,76 +5327,77 @@ static irqreturn_t iwl_isr(int irq, void *data)
   *********************************************************************/
  
  /* 2.4 GHz */
@@ -617445,7 +638083,7 @@
  		break;
  	default:
  		BUG();
-@@ -5294,7 +5393,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+@@ -5294,7 +5405,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
  	}
  }
  
@@ -617459,7 +638097,7 @@
  						    int phymode, u16 channel)
  {
  	int i;
-@@ -5321,13 +5425,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+@@ -5321,13 +5437,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
  #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
  			    ? # x " " : "")
  
@@ -617479,7 +638117,7 @@
  
  	if (priv->channel_count) {
  		IWL_DEBUG_INFO("Channel map already initialized.\n");
-@@ -5343,15 +5450,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5343,15 +5462,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
  
  	priv->channel_count =
@@ -617501,7 +638139,7 @@
  				     priv->channel_count, GFP_KERNEL);
  	if (!priv->channel_info) {
  		IWL_ERROR("Could not allocate channel_info\n");
-@@ -5366,7 +5473,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5366,7 +5485,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  	 * what just in the EEPROM) */
  	for (band = 1; band <= 5; band++) {
  
@@ -617510,7 +638148,7 @@
  					&eeprom_ch_info, &eeprom_ch_index);
  
  		/* Loop through each band adding each of the channels */
-@@ -5430,14 +5537,17 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5430,14 +5549,17 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  		}
  	}
  
@@ -617529,7 +638167,7 @@
  		/* Loop through each band adding each of the channels */
  		for (ch = 0; ch < eeprom_ch_count; ch++) {
  
-@@ -5449,11 +5559,13 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5449,11 +5571,13 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  			else
  				fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
  
@@ -617543,7 +638181,23 @@
  			iwl4965_set_fat_chan_info(priv, phymode,
  						  (eeprom_ch_index[ch] + 4),
  						  &(eeprom_ch_info[ch]),
-@@ -5487,7 +5599,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+@@ -5464,6 +5588,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
+ 	return 0;
+ }
+ 
++/*
++ * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map
++ */
++static void iwl4965_free_channel_map(struct iwl4965_priv *priv)
++{
++	kfree(priv->channel_info);
++	priv->channel_count = 0;
++}
++
+ /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+  * sending probe req.  This should be set long enough to hear probe responses
+  * from more than one AP.  */
+@@ -5487,7 +5620,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
  #define IWL_PASSIVE_DWELL_BASE      (100)
  #define IWL_CHANNEL_TUNE_TIME       5
  
@@ -617552,7 +638206,7 @@
  {
  	if (phymode == MODE_IEEE80211A)
  		return IWL_ACTIVE_DWELL_TIME_52;
-@@ -5495,14 +5607,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+@@ -5495,14 +5628,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
  		return IWL_ACTIVE_DWELL_TIME_24;
  }
  
@@ -617570,7 +638224,7 @@
  		/* If we're associated, we clamp the maximum passive
  		 * dwell time to be 98% of the beacon interval (minus
  		 * 2 * channel tune time) */
-@@ -5518,30 +5630,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+@@ -5518,30 +5651,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
  	return passive;
  }
  
@@ -617608,7 +638262,7 @@
  				IWL_DEBUG_SCAN
  				    ("Skipping current channel %d\n",
  				     le16_to_cpu(priv->active_rxon.channel));
-@@ -5552,7 +5664,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5552,7 +5685,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  
  		scan_ch->channel = channels[i].chan;
  
@@ -617618,7 +638272,7 @@
  		if (!is_channel_valid(ch_info)) {
  			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
  				       scan_ch->channel);
-@@ -5574,7 +5687,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5574,7 +5708,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  		scan_ch->active_dwell = cpu_to_le16(active_dwell);
  		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
  
@@ -617627,7 +638281,7 @@
  		scan_ch->tpc.dsp_atten = 110;
  		/* scan_pwr_info->tpc.dsp_atten; */
  
-@@ -5584,8 +5697,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5584,8 +5718,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  		else {
  			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
  			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
@@ -617638,7 +638292,7 @@
  			 */
  		}
  
-@@ -5603,7 +5716,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+@@ -5603,7 +5737,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
  	return added;
  }
  
@@ -617647,7 +638301,7 @@
  {
  	int i, j;
  	for (i = 0; i < 3; i++) {
-@@ -5613,13 +5726,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
+@@ -5613,13 +5747,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
  	}
  }
  
@@ -617663,7 +638317,7 @@
  		rates[i].val = i; /* Rate scaling will work on indexes */
  		rates[i].val2 = i;
  		rates[i].flags = IEEE80211_RATE_SUPPORTED;
-@@ -5631,7 +5744,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
+@@ -5631,7 +5765,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
  			 * If CCK 1M then set rate flag to CCK else CCK_2
  			 * which is CCK | PREAMBLE2
  			 */
@@ -617672,7 +638326,7 @@
  				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
  		}
  
-@@ -5639,16 +5752,14 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
+@@ -5639,16 +5773,14 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
  		if (IWL_BASIC_RATES_MASK & (1 << i))
  			rates[i].flags |= IEEE80211_RATE_BASIC;
  	}
@@ -617692,7 +638346,7 @@
  	struct ieee80211_hw_mode *modes;
  	struct ieee80211_channel *channels;
  	struct ieee80211_channel *geo_ch;
-@@ -5658,10 +5769,8 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5658,10 +5790,8 @@ static int iwl_init_geos(struct iwl_priv *priv)
  		A = 0,
  		B = 1,
  		G = 2,
@@ -617704,7 +638358,7 @@
  
  	if (priv->modes) {
  		IWL_DEBUG_INFO("Geography modes already initialized.\n");
-@@ -5696,11 +5805,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5696,11 +5826,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
  
  	/* 5.2GHz channels start after the 2.4GHz channels */
  	modes[A].mode = MODE_IEEE80211A;
@@ -617720,7 +638374,7 @@
  
  	modes[B].mode = MODE_IEEE80211B;
  	modes[B].channels = channels;
-@@ -5713,23 +5825,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5713,23 +5846,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
  	modes[G].rates = rates;
  	modes[G].num_rates = 12;	/* OFDM & CCK */
  	modes[G].num_channels = 0;
@@ -617748,7 +638402,7 @@
  
  	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
  		ch = &priv->channel_info[i];
-@@ -5744,11 +5847,9 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5744,11 +5868,9 @@ static int iwl_init_geos(struct iwl_priv *priv)
  
  		if (is_channel_a_band(ch)) {
  			geo_ch = &modes[A].channels[modes[A].num_channels++];
@@ -617760,7 +638414,24 @@
  		}
  
  		geo_ch->freq = ieee80211chan2mhz(ch->channel);
-@@ -5814,57 +5915,22 @@ static int iwl_init_geos(struct iwl_priv *priv)
+@@ -5808,63 +5930,39 @@ static int iwl_init_geos(struct iwl_priv *priv)
+ 	return 0;
+ }
+ 
++/*
++ * iwl4965_free_geos - undo allocations in iwl4965_init_geos
++ */
++static void iwl4965_free_geos(struct iwl4965_priv *priv)
++{
++	kfree(priv->modes);
++	kfree(priv->ieee_channels);
++	kfree(priv->ieee_rates);
++	clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
++}
++
+ /******************************************************************************
+  *
+  * uCode download functions
   *
   ******************************************************************************/
  
@@ -617828,7 +638499,7 @@
  {
  	u32 val;
  	u32 save_len = len;
-@@ -5873,18 +5939,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+@@ -5873,18 +5971,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
  
  	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
  
@@ -617850,7 +638521,7 @@
  		if (val != le32_to_cpu(*image)) {
  			IWL_ERROR("uCode INST section is invalid at "
  				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
-@@ -5896,7 +5962,7 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+@@ -5896,7 +5994,7 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
  		}
  	}
  
@@ -617859,7 +638530,7 @@
  
  	if (!errcnt)
  		IWL_DEBUG_INFO
-@@ -5907,11 +5973,11 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+@@ -5907,11 +6005,11 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
  
  
  /**
@@ -617873,7 +638544,7 @@
  {
  	u32 val;
  	int rc = 0;
-@@ -5920,7 +5986,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5920,7 +6018,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  
  	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
  
@@ -617882,7 +638553,7 @@
  	if (rc)
  		return rc;
  
-@@ -5928,9 +5994,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5928,9 +6026,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  		/* read data comes through single port, auto-incr addr */
  		/* NOTE: Use the debugless read so we don't flood kernel log
  		 * if IWL_DL_IO is set */
@@ -617894,7 +638565,7 @@
  		if (val != le32_to_cpu(*image)) {
  #if 0 /* Enable this if you want to see details */
  			IWL_ERROR("uCode INST section is invalid at "
-@@ -5944,17 +6010,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+@@ -5944,17 +6042,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
  		}
  	}
  
@@ -617915,7 +638586,7 @@
  {
  	__le32 *image;
  	u32 len;
-@@ -5963,7 +6029,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5963,7 +6061,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try bootstrap */
  	image = (__le32 *)priv->ucode_boot.v_addr;
  	len = priv->ucode_boot.len;
@@ -617924,7 +638595,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
  		return 0;
-@@ -5972,7 +6038,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5972,7 +6070,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try initialize */
  	image = (__le32 *)priv->ucode_init.v_addr;
  	len = priv->ucode_init.len;
@@ -617933,7 +638604,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
  		return 0;
-@@ -5981,7 +6047,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5981,7 +6079,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  	/* Try runtime/protocol */
  	image = (__le32 *)priv->ucode_code.v_addr;
  	len = priv->ucode_code.len;
@@ -617942,7 +638613,7 @@
  	if (rc == 0) {
  		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
  		return 0;
-@@ -5989,18 +6055,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
+@@ -5989,18 +6087,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
  
  	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
  
@@ -617966,7 +638637,7 @@
  {
  	__le32 *image = priv->ucode_boot.v_addr;
  	u32 len = priv->ucode_boot.len;
-@@ -6010,11 +6077,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -6010,11 +6109,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  	IWL_DEBUG_INFO("Begin verify bsm\n");
  
  	/* verify BSM SRAM contents */
@@ -617980,7 +638651,7 @@
  		if (val != le32_to_cpu(*image)) {
  			IWL_ERROR("BSM uCode verification failed at "
  				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
-@@ -6031,7 +6098,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -6031,7 +6130,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  }
  
  /**
@@ -617989,7 +638660,7 @@
   *
   * BSM operation:
   *
-@@ -6062,7 +6129,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
+@@ -6062,7 +6161,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
   * the runtime uCode instructions and the backup data cache into SRAM,
   * and re-launches the runtime uCode from where it left off.
   */
@@ -617998,7 +638669,7 @@
  {
  	__le32 *image = priv->ucode_boot.v_addr;
  	u32 len = priv->ucode_boot.len;
-@@ -6082,8 +6149,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -6082,8 +6181,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  		return -EINVAL;
  
  	/* Tell bootstrap uCode where to find the "Initialize" uCode
@@ -618009,7 +638680,7 @@
  	 *        after the "initialize" uCode has run, to point to
  	 *        runtime/protocol instructions and backup data cache. */
  	pinst = priv->ucode_init.p_addr >> 4;
-@@ -6091,42 +6158,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -6091,42 +6190,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  	inst_len = priv->ucode_init.len;
  	data_len = priv->ucode_init_data.len;
  
@@ -618065,7 +638736,7 @@
  		if (!(done & BSM_WR_CTRL_REG_BIT_START))
  			break;
  		udelay(10);
-@@ -6140,29 +6207,30 @@ static int iwl_load_bsm(struct iwl_priv *priv)
+@@ -6140,29 +6239,30 @@ static int iwl_load_bsm(struct iwl_priv *priv)
  
  	/* Enable future boot loads whenever power management unit triggers it
  	 *   (e.g. when powering back up after power-save shutdown) */
@@ -618104,7 +638775,7 @@
  	const struct firmware *ucode_raw;
  	const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
  	u8 *src;
-@@ -6171,9 +6239,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6171,9 +6271,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
  	/* Ask kernel firmware_class module to get the boot firmware off disk.
  	 * request_firmware() is synchronous, file is in memory on return. */
@@ -618118,7 +638789,7 @@
  		goto error;
  	}
  
-@@ -6183,7 +6252,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6183,7 +6284,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	/* Make sure that we got at least our header! */
  	if (ucode_raw->size < sizeof(*ucode)) {
  		IWL_ERROR("File size way too small!\n");
@@ -618127,7 +638798,7 @@
  		goto err_release;
  	}
  
-@@ -6216,43 +6285,43 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6216,43 +6317,43 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
  		IWL_DEBUG_INFO("uCode file size %d too small\n",
  			       (int)ucode_raw->size);
@@ -618187,7 +638858,7 @@
  		goto err_release;
  	}
  
-@@ -6262,66 +6331,50 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6262,66 +6363,50 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	 * 1) unmodified from disk
  	 * 2) backup cache for save/restore during power-downs */
  	priv->ucode_code.len = inst_size;
@@ -618276,7 +638947,7 @@
  	memcpy(priv->ucode_data.v_addr, src, len);
  	memcpy(priv->ucode_data_backup.v_addr, src, len);
  
-@@ -6329,8 +6382,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6329,8 +6414,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	if (init_size) {
  		src = &ucode->data[inst_size + data_size];
  		len = priv->ucode_init.len;
@@ -618287,7 +638958,7 @@
  		memcpy(priv->ucode_init.v_addr, src, len);
  	}
  
-@@ -6338,16 +6391,15 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6338,16 +6423,15 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  	if (init_data_size) {
  		src = &ucode->data[inst_size + data_size + init_size];
  		len = priv->ucode_init_data.len;
@@ -618307,7 +638978,7 @@
  	memcpy(priv->ucode_boot.v_addr, src, len);
  
  	/* We have our copies now, allow OS release its copies */
-@@ -6356,19 +6408,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6356,19 +6440,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  
   err_pci_alloc:
  	IWL_ERROR("failed to allocate pci memory\n");
@@ -618331,7 +639002,7 @@
   *
   * Tell initialization uCode where to find runtime uCode.
   *
-@@ -6376,7 +6428,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
+@@ -6376,7 +6460,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
   * We need to replace them to load runtime uCode inst and data,
   * and to save runtime data when powering down.
   */
@@ -618340,7 +639011,7 @@
  {
  	dma_addr_t pinst;
  	dma_addr_t pdata;
-@@ -6388,24 +6440,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+@@ -6388,24 +6472,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
  	pdata = priv->ucode_data_backup.p_addr >> 4;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -618371,7 +639042,7 @@
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
-@@ -6415,7 +6467,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+@@ -6415,7 +6499,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
  }
  
  /**
@@ -618380,7 +639051,7 @@
   *
   * Called after REPLY_ALIVE notification received from "initialize" uCode.
   *
-@@ -6425,7 +6477,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+@@ -6425,7 +6509,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
   *
   * Tell "initialize" uCode to go ahead and load the runtime uCode.
  */
@@ -618389,7 +639060,7 @@
  {
  	/* Check alive response for "valid" sign from uCode */
  	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
-@@ -6438,7 +6490,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6438,7 +6522,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
  	 * This is a paranoid check, because we would not have gotten the
  	 * "initialize" alive if code weren't properly loaded.  */
@@ -618398,7 +639069,7 @@
  		/* Runtime instruction load was bad;
  		 * take it all the way back down so we can try again */
  		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
-@@ -6452,7 +6504,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6452,7 +6536,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  	 * load and launch runtime uCode, which will send us another "Alive"
  	 * notification. */
  	IWL_DEBUG_INFO("Initialization Alive received.\n");
@@ -618407,7 +639078,7 @@
  		/* Runtime instruction load won't happen;
  		 * take it all the way back down so we can try again */
  		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
-@@ -6466,11 +6518,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
+@@ -6466,11 +6550,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
  
  
  /**
@@ -618422,7 +639093,7 @@
  {
  	int rc = 0;
  
-@@ -6486,14 +6538,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6486,14 +6570,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
  	 * This is a paranoid check, because we would not have gotten the
  	 * "runtime" alive if code weren't properly loaded.  */
@@ -618439,7 +639110,7 @@
  
  	rc = iwl4965_alive_notify(priv);
  	if (rc) {
-@@ -6502,78 +6554,61 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6502,78 +6586,52 @@ static void iwl_alive_start(struct iwl_priv *priv)
  		goto restart;
  	}
  
@@ -618451,20 +639122,17 @@
  	clear_bit(STATUS_FW_ERROR, &priv->status);
  
 -	rc = iwl_init_channel_map(priv);
-+	rc = iwl4965_init_channel_map(priv);
- 	if (rc) {
- 		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+-	if (rc) {
+-		IWL_ERROR("initializing regulatory failed: %d\n", rc);
++	if (iwl4965_is_rfkill(priv))
  		return;
- 	}
- 
+-	}
+-
 -	iwl_init_geos(priv);
-+	iwl4965_init_geos(priv);
-+	iwl4965_reset_channel_flag(priv);
- 
+-
 -	if (iwl_is_rfkill(priv))
-+	if (iwl4965_is_rfkill(priv))
- 		return;
- 
+-		return;
+-
 -	if (!priv->mac80211_registered) {
 -		/* Unlock so any user space entry points can call back into
 -		 * the driver without a deadlock... */
@@ -618480,7 +639148,7 @@
 -				  "device (error %d)\n", rc);
 -			return;
 -		}
--
+ 
 -		priv->mac80211_registered = 1;
 -
 -		iwl_reset_channel_flag(priv);
@@ -618535,7 +639203,7 @@
  
  	return;
  
-@@ -6581,9 +6616,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
+@@ -6581,9 +6639,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
  	queue_work(priv->workqueue, &priv->restart);
  }
  
@@ -618547,7 +639215,7 @@
  {
  	unsigned long flags;
  	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
-@@ -6596,7 +6631,7 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6596,7 +6654,7 @@ static void __iwl_down(struct iwl_priv *priv)
  	if (!exit_pending)
  		set_bit(STATUS_EXIT_PENDING, &priv->status);
  
@@ -618556,7 +639224,7 @@
  
  	/* Unblock any waiting calls */
  	wake_up_interruptible_all(&priv->wait_command_queue);
-@@ -6607,17 +6642,17 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6607,17 +6665,17 @@ static void __iwl_down(struct iwl_priv *priv)
  		clear_bit(STATUS_EXIT_PENDING, &priv->status);
  
  	/* stop and reset the on-board processor */
@@ -618578,7 +639246,7 @@
  		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
  					STATUS_RF_KILL_HW |
  			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-@@ -6639,53 +6674,52 @@ static void __iwl_down(struct iwl_priv *priv)
+@@ -6639,53 +6697,52 @@ static void __iwl_down(struct iwl_priv *priv)
  				STATUS_FW_ERROR;
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -618648,7 +639316,7 @@
  
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
  		IWL_WARNING("Exit pending; will not bring the NIC up\n");
-@@ -6695,7 +6729,19 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6695,7 +6752,19 @@ static int __iwl_up(struct iwl_priv *priv)
  	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
  		IWL_WARNING("Radio disabled by SW RF kill (module "
  			    "parameter)\n");
@@ -618669,7 +639337,7 @@
  	}
  
  	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-@@ -6703,53 +6749,45 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6703,53 +6772,45 @@ static int __iwl_up(struct iwl_priv *priv)
  		return -EIO;
  	}
  
@@ -618707,15 +639375,15 @@
  	 * data SRAM for a clean start when the runtime program first loads. */
  	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
 -			priv->ucode_data.len);
-+	       priv->ucode_data.len);
- 
+-
 -	/* If platform's RF_KILL switch is set to KILL,
 -	 * wait for BIT_INT_RF_KILL interrupt before loading uCode
 -	 * and getting things started */
 -	if (!(iwl_read32(priv, CSR_GP_CNTRL) &
 -				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
 -		hw_rf_kill = 1;
--
++	       priv->ucode_data.len);
+ 
 -	if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
 -		IWL_WARNING("Radio disabled by HW RF Kill switch\n");
 +	/* We return success when we resume from suspend and rf_kill is on. */
@@ -618736,7 +639404,7 @@
  
  		if (rc) {
  			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
-@@ -6757,14 +6795,7 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6757,14 +6818,7 @@ static int __iwl_up(struct iwl_priv *priv)
  		}
  
  		/* start card; "initialize" will load runtime ucode */
@@ -618752,7 +639420,7 @@
  
  		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
  
-@@ -6772,7 +6803,7 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6772,7 +6826,7 @@ static int __iwl_up(struct iwl_priv *priv)
  	}
  
  	set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -618761,7 +639429,7 @@
  
  	/* tried to restart and config the device for as long as our
  	 * patience could withstand */
-@@ -6787,35 +6818,35 @@ static int __iwl_up(struct iwl_priv *priv)
+@@ -6787,35 +6841,35 @@ static int __iwl_up(struct iwl_priv *priv)
   *
   *****************************************************************************/
  
@@ -618807,7 +639475,7 @@
  
  	wake_up_interruptible(&priv->wait_command_queue);
  
-@@ -6824,7 +6855,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
+@@ -6824,7 +6878,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
  
  	mutex_lock(&priv->mutex);
  
@@ -618816,7 +639484,7 @@
  		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
  			  "HW and/or SW RF Kill no longer active, restarting "
  			  "device\n");
-@@ -6845,10 +6876,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
+@@ -6845,10 +6899,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
  
  #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
  
@@ -618830,7 +639498,7 @@
  
  	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
  		return;
-@@ -6861,22 +6892,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
+@@ -6861,22 +6915,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
  			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
  
  		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -618860,7 +639528,7 @@
  	struct ieee80211_conf *conf = NULL;
  	u8 direct_mask;
  	int phymode;
-@@ -6885,7 +6916,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6885,7 +6939,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  
  	mutex_lock(&priv->mutex);
  
@@ -618869,7 +639537,7 @@
  		IWL_WARNING("request scan called when driver not ready.\n");
  		goto done;
  	}
-@@ -6914,7 +6945,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6914,7 +6968,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  		goto done;
  	}
  
@@ -618878,7 +639546,7 @@
  		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
  		goto done;
  	}
-@@ -6930,7 +6961,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6930,7 +6984,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	}
  
  	if (!priv->scan) {
@@ -618887,7 +639555,7 @@
  				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
  		if (!priv->scan) {
  			rc = -ENOMEM;
-@@ -6938,12 +6969,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6938,12 +6992,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
  		}
  	}
  	scan = priv->scan;
@@ -618902,7 +639570,7 @@
  		u16 interval = 0;
  		u32 extra;
  		u32 suspend_time = 100;
-@@ -6973,14 +7004,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6973,14 +7027,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	if (priv->one_direct_scan) {
  		IWL_DEBUG_SCAN
  		    ("Kicking off one direct scan for '%s'\n",
@@ -618919,16 +639587,18 @@
  		scan->direct_scan[0].id = WLAN_EID_SSID;
  		scan->direct_scan[0].len = priv->essid_len;
  		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-@@ -6991,7 +7022,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -6991,8 +7045,8 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	/* We don't build a direct scan probe request; the uCode will do
  	 * that based on the direct_mask added to each channel entry */
  	scan->tx_cmd.len = cpu_to_le16(
 -		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+-			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
 +		iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
- 			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
++			IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
  	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
  	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
-@@ -7005,7 +7036,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+ 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+@@ -7005,7 +7059,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	case 2:
  		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
  		scan->tx_cmd.rate_n_flags =
@@ -618937,7 +639607,7 @@
  				RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
  
  		scan->good_CRC_th = 0;
-@@ -7014,7 +7045,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -7014,7 +7068,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
  
  	case 1:
  		scan->tx_cmd.rate_n_flags =
@@ -618946,7 +639616,7 @@
  				RATE_MCS_ANT_B_MSK);
  		scan->good_CRC_th = IWL_GOOD_CRC_TH;
  		phymode = MODE_IEEE80211A;
-@@ -7041,23 +7072,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -7041,23 +7095,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	if (direct_mask)
  		IWL_DEBUG_SCAN
  		    ("Initiating direct scan for %s.\n",
@@ -618974,7 +639644,7 @@
  	if (rc)
  		goto done;
  
-@@ -7068,50 +7099,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
+@@ -7068,50 +7122,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
  	return;
  
   done:
@@ -619040,7 +639710,7 @@
  					     post_associate.work);
  
  	int rc = 0;
-@@ -7133,20 +7166,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -7133,20 +7189,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
  
  	mutex_lock(&priv->mutex);
  
@@ -619067,7 +639737,7 @@
  			      sizeof(priv->rxon_timing), &priv->rxon_timing);
  	if (rc)
  		IWL_WARNING("REPLY_RXON_TIMING failed - "
-@@ -7154,15 +7187,10 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -7154,15 +7210,10 @@ static void iwl_bg_post_associate(struct work_struct *data)
  
  	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
  
@@ -619087,7 +639757,7 @@
  	iwl4965_set_rxon_chain(priv);
  	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
  
-@@ -7185,22 +7213,22 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -7185,22 +7236,22 @@ static void iwl_bg_post_associate(struct work_struct *data)
  
  	}
  
@@ -619117,7 +639787,7 @@
  
  		break;
  
-@@ -7210,55 +7238,61 @@ static void iwl_bg_post_associate(struct work_struct *data)
+@@ -7210,55 +7261,61 @@ static void iwl_bg_post_associate(struct work_struct *data)
  		break;
  	}
  
@@ -619194,7 +639864,7 @@
  	mutex_unlock(&priv->mutex);
  }
  
-@@ -7268,50 +7302,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
+@@ -7268,50 +7325,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
   *
   *****************************************************************************/
  
@@ -619336,7 +640006,7 @@
  
  	IWL_DEBUG_MAC80211("enter\n");
  
-@@ -7323,29 +7430,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -7323,29 +7453,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
  	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
  		     ctl->tx_rate);
  
@@ -619362,9 +640032,10 @@
  
 -	if (priv->interface_id) {
 -		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+-		return 0;
 +	if (priv->vif) {
 +		IWL_DEBUG_MAC80211("leave - vif != NULL\n");
- 		return 0;
++		return -EOPNOTSUPP;
  	}
  
  	spin_lock_irqsave(&priv->lock, flags);
@@ -619373,7 +640044,7 @@
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
-@@ -7355,58 +7462,62 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+@@ -7355,58 +7485,62 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
  		IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
  		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
  	}
@@ -619452,7 +640123,7 @@
  	/* if we are switching fron ht to 2.4 clear flags
  	 * from any ht related info since 2.4 does not
  	 * support ht */
-@@ -7416,57 +7527,56 @@ static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+@@ -7416,61 +7550,60 @@ static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
  #endif
  	)
  		priv->staging_rxon.flags = 0;
@@ -619527,7 +640198,12 @@
  {
  	int rc = 0;
  
-@@ -7478,12 +7588,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
+-	if (priv->status & STATUS_EXIT_PENDING)
++	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ 		return;
+ 
+ 	/* The following should be done only at AP bring up */
+@@ -7478,12 +7611,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
  
  		/* RXON - unassoc (to set timing command) */
  		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
@@ -619544,7 +640220,7 @@
  				sizeof(priv->rxon_timing), &priv->rxon_timing);
  		if (rc)
  			IWL_WARNING("REPLY_RXON_TIMING failed - "
-@@ -7515,23 +7625,24 @@ static void iwl_config_ap(struct iwl_priv *priv)
+@@ -7515,23 +7648,24 @@ static void iwl_config_ap(struct iwl_priv *priv)
  		}
  		/* restore RXON assoc */
  		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -619576,7 +640252,7 @@
  	DECLARE_MAC_BUF(mac);
  	unsigned long flags;
  	int rc;
-@@ -7546,9 +7657,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7546,9 +7680,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		return 0;
  	}
  
@@ -619589,7 +640265,7 @@
  	if (conf->bssid)
  		IWL_DEBUG_MAC80211("bssid: %s\n",
  				   print_mac(mac, conf->bssid));
-@@ -7565,8 +7678,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7565,8 +7701,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		return 0;
  	}
  
@@ -619600,7 +640276,7 @@
  		mutex_unlock(&priv->mutex);
  		return 0;
  	}
-@@ -7584,11 +7697,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7584,11 +7720,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		priv->ibss_beacon = conf->beacon;
  	}
  
@@ -619616,7 +640292,7 @@
  			IWL_WARNING("Aborted scan still in progress "
  				    "after 100ms\n");
  			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
-@@ -7604,20 +7720,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7604,20 +7743,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
  
  		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
@@ -619643,7 +640319,7 @@
  	spin_lock_irqsave(&priv->lock, flags);
  	if (!conf->ssid_len)
  		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-@@ -7633,34 +7750,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+@@ -7633,34 +7773,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
  	return 0;
  }
  
@@ -619690,7 +640366,7 @@
  		memset(priv->bssid, 0, ETH_ALEN);
  		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
  		priv->essid_len = 0;
-@@ -7671,19 +7789,50 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+@@ -7671,19 +7812,50 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
  
  }
  
@@ -619745,7 +640421,7 @@
  		rc = -EIO;
  		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
  		goto out_unlock;
-@@ -7695,17 +7844,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+@@ -7695,17 +7867,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
  		goto out_unlock;
  	}
  
@@ -619773,7 +640449,7 @@
  
  		priv->one_direct_scan = 1;
  		priv->direct_ssid_len = (u8)
-@@ -7714,7 +7867,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+@@ -7714,7 +7890,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
  	} else
  		priv->one_direct_scan = 0;
  
@@ -619782,7 +640458,7 @@
  
  	IWL_DEBUG_MAC80211("leave\n");
  
-@@ -7725,18 +7878,18 @@ out_unlock:
+@@ -7725,18 +7901,18 @@ out_unlock:
  	return rc;
  }
  
@@ -619804,7 +640480,7 @@
  		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
  		return -EOPNOTSUPP;
  	}
-@@ -7745,7 +7898,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7745,7 +7921,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  		/* only support pairwise keys */
  		return -EOPNOTSUPP;
  
@@ -619813,7 +640489,7 @@
  	if (sta_id == IWL_INVALID_STATION) {
  		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
  				   print_mac(mac, addr));
-@@ -7754,24 +7907,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7754,24 +7930,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  
  	mutex_lock(&priv->mutex);
  
@@ -619845,7 +640521,7 @@
  			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
  		}
  		break;
-@@ -7785,18 +7938,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+@@ -7785,18 +7961,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
  	return rc;
  }
  
@@ -619869,7 +640545,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		return -EIO;
  	}
-@@ -7806,7 +7959,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+@@ -7806,7 +7982,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
  		return 0;
  	}
  
@@ -619878,7 +640554,7 @@
  	if (!priv->qos_data.qos_enable) {
  		priv->qos_data.qos_active = 0;
  		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
-@@ -7829,30 +7982,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+@@ -7829,30 +8005,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
  
  	mutex_lock(&priv->mutex);
  	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
@@ -619918,7 +640594,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		return -EIO;
  	}
-@@ -7862,7 +8015,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+@@ -7862,7 +8038,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
  	for (i = 0; i < AC_NUM; i++) {
  		txq = &priv->txq[i];
  		q = &txq->q;
@@ -619927,7 +640603,7 @@
  
  		stats->data[i].len = q->n_window - avail;
  		stats->data[i].limit = q->n_window - q->high_mark;
-@@ -7876,7 +8029,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+@@ -7876,7 +8052,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
  	return 0;
  }
  
@@ -619936,7 +640612,7 @@
  			     struct ieee80211_low_level_stats *stats)
  {
  	IWL_DEBUG_MAC80211("enter\n");
-@@ -7885,7 +8038,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+@@ -7885,7 +8061,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
  	return 0;
  }
  
@@ -619945,7 +640621,7 @@
  {
  	IWL_DEBUG_MAC80211("enter\n");
  	IWL_DEBUG_MAC80211("leave\n");
-@@ -7893,35 +8046,35 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+@@ -7893,35 +8069,35 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
  	return 0;
  }
  
@@ -619991,7 +640667,7 @@
  #endif
  
  	cancel_delayed_work(&priv->post_associate);
-@@ -7946,13 +8099,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+@@ -7946,13 +8122,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  
  	spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -620013,7 +640689,7 @@
  	}
  
  	/* Per mac80211.h: This is only used in IBSS mode... */
-@@ -7963,32 +8122,25 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+@@ -7963,32 +8145,25 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
  		return;
  	}
  
@@ -620050,7 +640726,7 @@
  		IWL_DEBUG_MAC80211("leave - RF not ready\n");
  		mutex_unlock(&priv->mutex);
  		return -EIO;
-@@ -8012,8 +8164,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -8012,8 +8187,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  	IWL_DEBUG_MAC80211("leave\n");
  	spin_unlock_irqrestore(&priv->lock, flags);
  
@@ -620061,7 +640737,7 @@
  #endif
  
  	queue_work(priv->workqueue, &priv->post_associate.work);
-@@ -8023,133 +8175,62 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -8023,133 +8198,62 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  	return 0;
  }
  
@@ -620237,7 +640913,7 @@
  	iwl4965_set_rxon_chain(priv);
  
  	if (priv && priv->assoc_id &&
-@@ -8164,58 +8245,33 @@ static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
+@@ -8164,58 +8268,33 @@ static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
  		spin_unlock_irqrestore(&priv->lock, flags);
  	}
  
@@ -620261,7 +640937,9 @@
 -
 -	memset(&cap, 0, sizeof(union ht_cap_info));
 -	memset(&param_info, 0, sizeof(union ht_param_info));
--
++	struct ieee80211_conf *conf = &hw->conf;
++	struct ieee80211_hw_mode *mode = conf->mode;
+ 
 -	cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
 -	cap.green_field = 1;
 -	cap.short_GI20 = 1;
@@ -620273,9 +640951,7 @@
 -	param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
 -	ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
 -	ht_cap->mac_ht_params_info = (u8) param_info.val;
-+	struct ieee80211_conf *conf = &hw->conf;
-+	struct ieee80211_hw_mode *mode = conf->mode;
- 
+-
 -	ht_cap->supported_mcs_set[0] = 0xff;
 -	ht_cap->supported_mcs_set[1] = 0xff;
 -	ht_cap->supported_mcs_set[4] =
@@ -620317,7 +640993,7 @@
  
  /*****************************************************************************
   *
-@@ -8223,7 +8279,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
+@@ -8223,7 +8302,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
   *
   *****************************************************************************/
  
@@ -620326,7 +641002,7 @@
  
  /*
   * The following adds a new attribute to the sysfs representation
-@@ -8235,7 +8291,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
+@@ -8235,7 +8314,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
  
  static ssize_t show_debug_level(struct device_driver *d, char *buf)
  {
@@ -620335,7 +641011,7 @@
  }
  static ssize_t store_debug_level(struct device_driver *d,
  				 const char *buf, size_t count)
-@@ -8248,7 +8304,7 @@ static ssize_t store_debug_level(struct device_driver *d,
+@@ -8248,7 +8327,7 @@ static ssize_t store_debug_level(struct device_driver *d,
  		printk(KERN_INFO DRV_NAME
  		       ": %s is not in hex or decimal form.\n", buf);
  	else
@@ -620344,7 +641020,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -8256,7 +8312,7 @@ static ssize_t store_debug_level(struct device_driver *d,
+@@ -8256,7 +8335,7 @@ static ssize_t store_debug_level(struct device_driver *d,
  static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
  		   show_debug_level, store_debug_level);
  
@@ -620353,7 +641029,7 @@
  
  static ssize_t show_rf_kill(struct device *d,
  			    struct device_attribute *attr, char *buf)
-@@ -8267,7 +8323,7 @@ static ssize_t show_rf_kill(struct device *d,
+@@ -8267,7 +8346,7 @@ static ssize_t show_rf_kill(struct device *d,
  	 * 2 - HW based RF kill active
  	 * 3 - Both HW and SW based RF kill active
  	 */
@@ -620362,7 +641038,7 @@
  	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
  		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
  
-@@ -8278,10 +8334,10 @@ static ssize_t store_rf_kill(struct device *d,
+@@ -8278,10 +8357,10 @@ static ssize_t store_rf_kill(struct device *d,
  			     struct device_attribute *attr,
  			     const char *buf, size_t count)
  {
@@ -620375,7 +641051,7 @@
  	mutex_unlock(&priv->mutex);
  
  	return count;
-@@ -8292,12 +8348,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+@@ -8292,12 +8371,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
  static ssize_t show_temperature(struct device *d,
  				struct device_attribute *attr, char *buf)
  {
@@ -620391,7 +641067,7 @@
  }
  
  static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-@@ -8306,15 +8362,15 @@ static ssize_t show_rs_window(struct device *d,
+@@ -8306,15 +8385,15 @@ static ssize_t show_rs_window(struct device *d,
  			      struct device_attribute *attr,
  			      char *buf)
  {
@@ -620410,7 +641086,7 @@
  	return sprintf(buf, "%d\n", priv->user_txpower_limit);
  }
  
-@@ -8322,7 +8378,7 @@ static ssize_t store_tx_power(struct device *d,
+@@ -8322,7 +8401,7 @@ static ssize_t store_tx_power(struct device *d,
  			      struct device_attribute *attr,
  			      const char *buf, size_t count)
  {
@@ -620419,7 +641095,7 @@
  	char *p = (char *)buf;
  	u32 val;
  
-@@ -8331,7 +8387,7 @@ static ssize_t store_tx_power(struct device *d,
+@@ -8331,7 +8410,7 @@ static ssize_t store_tx_power(struct device *d,
  		printk(KERN_INFO DRV_NAME
  		       ": %s is not in decimal form.\n", buf);
  	else
@@ -620428,7 +641104,7 @@
  
  	return count;
  }
-@@ -8341,7 +8397,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+@@ -8341,7 +8420,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
  static ssize_t show_flags(struct device *d,
  			  struct device_attribute *attr, char *buf)
  {
@@ -620437,7 +641113,7 @@
  
  	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
  }
-@@ -8350,19 +8406,19 @@ static ssize_t store_flags(struct device *d,
+@@ -8350,19 +8429,19 @@ static ssize_t store_flags(struct device *d,
  			   struct device_attribute *attr,
  			   const char *buf, size_t count)
  {
@@ -620460,7 +641136,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -8375,7 +8431,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+@@ -8375,7 +8454,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
  static ssize_t show_filter_flags(struct device *d,
  				 struct device_attribute *attr, char *buf)
  {
@@ -620469,7 +641145,7 @@
  
  	return sprintf(buf, "0x%04X\n",
  		le32_to_cpu(priv->active_rxon.filter_flags));
-@@ -8385,20 +8441,20 @@ static ssize_t store_filter_flags(struct device *d,
+@@ -8385,20 +8464,20 @@ static ssize_t store_filter_flags(struct device *d,
  				  struct device_attribute *attr,
  				  const char *buf, size_t count)
  {
@@ -620493,7 +641169,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -8412,20 +8468,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+@@ -8412,20 +8491,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
  static ssize_t show_tune(struct device *d,
  			 struct device_attribute *attr, char *buf)
  {
@@ -620517,7 +641193,7 @@
  	char *p = (char *)buf;
  	u16 tune = simple_strtoul(p, &p, 0);
  	u8 phymode = (tune >> 8) & 0xff;
-@@ -8436,9 +8492,9 @@ static ssize_t store_tune(struct device *d,
+@@ -8436,9 +8515,9 @@ static ssize_t store_tune(struct device *d,
  	mutex_lock(&priv->mutex);
  	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
  	    (priv->phymode != phymode)) {
@@ -620529,7 +641205,7 @@
  		if (!ch_info) {
  			IWL_WARNING("Requested invalid phymode/channel "
  				    "combination: %d %d\n", phymode, channel);
-@@ -8447,18 +8503,18 @@ static ssize_t store_tune(struct device *d,
+@@ -8447,18 +8526,18 @@ static ssize_t store_tune(struct device *d,
  		}
  
  		/* Cancel any currently running scans... */
@@ -620553,7 +641229,7 @@
  		}
  	}
  	mutex_unlock(&priv->mutex);
-@@ -8468,13 +8524,13 @@ static ssize_t store_tune(struct device *d,
+@@ -8468,13 +8547,13 @@ static ssize_t store_tune(struct device *d,
  
  static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
  
@@ -620570,7 +641246,7 @@
  	u32 size = sizeof(measure_report), len = 0, ofs = 0;
  	u8 *data = (u8 *) & measure_report;
  	unsigned long flags;
-@@ -8506,7 +8562,7 @@ static ssize_t store_measurement(struct device *d,
+@@ -8506,7 +8585,7 @@ static ssize_t store_measurement(struct device *d,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
  {
@@ -620579,7 +641255,7 @@
  	struct ieee80211_measurement_params params = {
  		.channel = le16_to_cpu(priv->active_rxon.channel),
  		.start_time = cpu_to_le64(priv->last_tsf),
-@@ -8532,20 +8588,20 @@ static ssize_t store_measurement(struct device *d,
+@@ -8532,20 +8611,20 @@ static ssize_t store_measurement(struct device *d,
  
  	IWL_DEBUG_INFO("Invoking measurement of type %d on "
  		       "channel %d (for '%s')\n", type, params.channel, buf);
@@ -620603,7 +641279,7 @@
  
  	priv->retry_rate = simple_strtoul(buf, NULL, 0);
  	if (priv->retry_rate <= 0)
-@@ -8557,7 +8613,7 @@ static ssize_t store_retry_rate(struct device *d,
+@@ -8557,7 +8636,7 @@ static ssize_t store_retry_rate(struct device *d,
  static ssize_t show_retry_rate(struct device *d,
  			       struct device_attribute *attr, char *buf)
  {
@@ -620612,7 +641288,7 @@
  	return sprintf(buf, "%d", priv->retry_rate);
  }
  
-@@ -8568,14 +8624,14 @@ static ssize_t store_power_level(struct device *d,
+@@ -8568,14 +8647,14 @@ static ssize_t store_power_level(struct device *d,
  				 struct device_attribute *attr,
  				 const char *buf, size_t count)
  {
@@ -620629,7 +641305,7 @@
  		rc = -EAGAIN;
  		goto out;
  	}
-@@ -8586,7 +8642,7 @@ static ssize_t store_power_level(struct device *d,
+@@ -8586,7 +8665,7 @@ static ssize_t store_power_level(struct device *d,
  		mode |= IWL_POWER_ENABLED;
  
  	if (mode != priv->power_mode) {
@@ -620638,7 +641314,7 @@
  		if (rc) {
  			IWL_DEBUG_MAC80211("failed setting power mode.\n");
  			goto out;
-@@ -8622,7 +8678,7 @@ static const s32 period_duration[] = {
+@@ -8622,7 +8701,7 @@ static const s32 period_duration[] = {
  static ssize_t show_power_level(struct device *d,
  				struct device_attribute *attr, char *buf)
  {
@@ -620647,7 +641323,7 @@
  	int level = IWL_POWER_LEVEL(priv->power_mode);
  	char *p = buf;
  
-@@ -8657,18 +8713,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+@@ -8657,18 +8736,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
  static ssize_t show_channels(struct device *d,
  			     struct device_attribute *attr, char *buf)
  {
@@ -620670,7 +641346,7 @@
  	if (hw_mode) {
  		channels = hw_mode->channels;
  		count = hw_mode->num_channels;
-@@ -8695,7 +8751,7 @@ static ssize_t show_channels(struct device *d,
+@@ -8695,7 +8774,7 @@ static ssize_t show_channels(struct device *d,
  			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
  			       "active/passive" : "passive only");
  
@@ -620679,7 +641355,7 @@
  	if (hw_mode) {
  		channels = hw_mode->channels;
  		count = hw_mode->num_channels;
-@@ -8731,17 +8787,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+@@ -8731,17 +8810,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
  static ssize_t show_statistics(struct device *d,
  			       struct device_attribute *attr, char *buf)
  {
@@ -620701,7 +641377,7 @@
  	mutex_unlock(&priv->mutex);
  
  	if (rc) {
-@@ -8769,9 +8825,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+@@ -8769,9 +8848,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
  static ssize_t show_antenna(struct device *d,
  			    struct device_attribute *attr, char *buf)
  {
@@ -620713,7 +641389,7 @@
  		return -EAGAIN;
  
  	return sprintf(buf, "%d\n", priv->antenna);
-@@ -8782,7 +8838,7 @@ static ssize_t store_antenna(struct device *d,
+@@ -8782,7 +8861,7 @@ static ssize_t store_antenna(struct device *d,
  			     const char *buf, size_t count)
  {
  	int ant;
@@ -620722,7 +641398,7 @@
  
  	if (count == 0)
  		return 0;
-@@ -8794,7 +8850,7 @@ static ssize_t store_antenna(struct device *d,
+@@ -8794,7 +8873,7 @@ static ssize_t store_antenna(struct device *d,
  
  	if ((ant >= 0) && (ant <= 2)) {
  		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
@@ -620731,7 +641407,7 @@
  	} else
  		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
  
-@@ -8807,8 +8863,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+@@ -8807,8 +8886,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
  static ssize_t show_status(struct device *d,
  			   struct device_attribute *attr, char *buf)
  {
@@ -620742,7 +641418,7 @@
  		return -EAGAIN;
  	return sprintf(buf, "0x%08x\n", (int)priv->status);
  }
-@@ -8822,7 +8878,7 @@ static ssize_t dump_error_log(struct device *d,
+@@ -8822,7 +8901,7 @@ static ssize_t dump_error_log(struct device *d,
  	char *p = (char *)buf;
  
  	if (p[0] == '1')
@@ -620751,7 +641427,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -8836,7 +8892,7 @@ static ssize_t dump_event_log(struct device *d,
+@@ -8836,7 +8915,7 @@ static ssize_t dump_event_log(struct device *d,
  	char *p = (char *)buf;
  
  	if (p[0] == '1')
@@ -620760,7 +641436,7 @@
  
  	return strnlen(buf, count);
  }
-@@ -8849,34 +8905,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+@@ -8849,34 +8928,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
   *
   *****************************************************************************/
  
@@ -620813,7 +641489,7 @@
  
  	cancel_delayed_work_sync(&priv->init_alive_start);
  	cancel_delayed_work(&priv->scan_check);
-@@ -8885,14 +8941,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+@@ -8885,14 +8964,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
  	cancel_work_sync(&priv->beacon_update);
  }
  
@@ -620830,7 +641506,7 @@
  	&dev_attr_measurement.attr,
  #endif
  	&dev_attr_power_level.attr,
-@@ -8908,54 +8964,56 @@ static struct attribute *iwl_sysfs_entries[] = {
+@@ -8908,54 +8987,56 @@ static struct attribute *iwl_sysfs_entries[] = {
  	NULL
  };
  
@@ -620922,7 +641598,7 @@
  		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
  			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
  		err = -EINVAL;
-@@ -8964,7 +9022,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8964,7 +9045,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	/* mac80211 allocates memory for this device instance, including
  	 *   space for this driver's private structure */
@@ -620931,7 +641607,7 @@
  	if (hw == NULL) {
  		IWL_ERROR("Can not allocate network device\n");
  		err = -ENOMEM;
-@@ -8979,9 +9037,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -8979,9 +9060,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	priv->hw = hw;
  
  	priv->pci_dev = pdev;
@@ -620944,7 +641620,7 @@
  	atomic_set(&priv->restrict_refcnt, 0);
  #endif
  	priv->retry_rate = 1;
-@@ -9000,12 +9058,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9000,12 +9081,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	/* Tell mac80211 our Tx characteristics */
  	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
  
@@ -620963,7 +641639,7 @@
  
  	spin_lock_init(&priv->lock);
  	spin_lock_init(&priv->power_data.lock);
-@@ -9026,7 +9086,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9026,7 +9109,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	pci_set_master(pdev);
  
@@ -620973,7 +641649,7 @@
  
  	priv->data_retry_limit = -1;
  	priv->ieee_channels = NULL;
-@@ -9045,9 +9106,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9045,9 +9129,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	err = pci_request_regions(pdev, DRV_NAME);
  	if (err)
  		goto out_pci_disable_device;
@@ -620985,7 +641661,7 @@
  	priv->hw_base = pci_iomap(pdev, 0, 0);
  	if (!priv->hw_base) {
  		err = -ENODEV;
-@@ -9060,7 +9123,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9060,7 +9146,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	/* Initialize module parameter values here */
  
@@ -620995,7 +641671,7 @@
  		set_bit(STATUS_RF_KILL_SW, &priv->status);
  		IWL_DEBUG_INFO("Radio disabled.\n");
  	}
-@@ -9069,91 +9133,92 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9069,91 +9156,109 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  
  	priv->ps_mode = 0;
  	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
@@ -621047,27 +641723,20 @@
  	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
  
 -	pci_enable_msi(pdev);
--
--	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
--	if (err) {
--		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
--		goto out_disable_msi;
--	}
--
--	mutex_lock(&priv->mutex);
 +	iwl4965_disable_interrupts(priv);
  
--	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+-	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
 +	err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
  	if (err) {
- 		IWL_ERROR("failed to create sysfs device attributes\n");
--		mutex_unlock(&priv->mutex);
- 		goto out_release_irq;
+-		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+-		goto out_disable_msi;
++		IWL_ERROR("failed to create sysfs device attributes\n");
++		goto out_release_irq;
  	}
  
--	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
--	 * ucode filename and max sizes are card-specific. */
--	err = iwl_read_ucode(priv);
+-	mutex_lock(&priv->mutex);
+-
+-	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
 +	/* nic init */
 +	iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 +                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
@@ -621083,9 +641752,9 @@
 +	/* Read the EEPROM */
 +	err = iwl4965_eeprom_init(priv);
  	if (err) {
--		IWL_ERROR("Could not read microcode: %d\n", err);
+-		IWL_ERROR("failed to create sysfs device attributes\n");
 -		mutex_unlock(&priv->mutex);
--		goto out_pci_alloc;
+-		goto out_release_irq;
 +		IWL_ERROR("Unable to init EEPROM\n");
 +		goto out_remove_sysfs;
  	}
@@ -621094,14 +641763,32 @@
 +	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
 +	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
  
+-	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+-	 * ucode filename and max sizes are card-specific. */
+-	err = iwl_read_ucode(priv);
++	err = iwl4965_init_channel_map(priv);
+ 	if (err) {
+-		IWL_ERROR("Could not read microcode: %d\n", err);
+-		mutex_unlock(&priv->mutex);
+-		goto out_pci_alloc;
++		IWL_ERROR("initializing regulatory failed: %d\n", err);
++		goto out_remove_sysfs;
+ 	}
+ 
 -	mutex_unlock(&priv->mutex);
--
++	err = iwl4965_init_geos(priv);
++	if (err) {
++		IWL_ERROR("initializing geos failed: %d\n", err);
++		goto out_free_channel_map;
++	}
++	iwl4965_reset_channel_flag(priv);
+ 
 -	IWL_DEBUG_INFO("Queing UP work.\n");
 +	iwl4965_rate_control_register(priv->hw);
 +	err = ieee80211_register_hw(priv->hw);
 +	if (err) {
 +		IWL_ERROR("Failed to register network device (error %d)\n", err);
-+		goto out_remove_sysfs;
++		goto out_free_geos;
 +	}
  
 -	queue_work(priv->workqueue, &priv->up);
@@ -621116,6 +641803,10 @@
 -	iwl_dealloc_ucode_pci(priv);
 -
 -	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
++ out_free_geos:
++	iwl4965_free_geos(priv);
++ out_free_channel_map:
++	iwl4965_free_channel_map(priv);
 + out_remove_sysfs:
 +	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
  
@@ -621131,7 +641822,7 @@
  
   out_iounmap:
  	pci_iounmap(pdev, priv->hw_base);
-@@ -9168,9 +9233,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -9168,9 +9273,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  	return err;
  }
  
@@ -621143,7 +641834,7 @@
  	struct list_head *p, *q;
  	int i;
  
-@@ -9181,43 +9246,41 @@ static void iwl_pci_remove(struct pci_dev *pdev)
+@@ -9181,52 +9286,48 @@ static void iwl_pci_remove(struct pci_dev *pdev)
  
  	set_bit(STATUS_EXIT_PENDING, &priv->status);
  
@@ -621197,7 +641888,18 @@
  	pci_iounmap(pdev, priv->hw_base);
  	pci_release_regions(pdev);
  	pci_disable_device(pdev);
-@@ -9236,93 +9299,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
+ 	pci_set_drvdata(pdev, NULL);
+ 
+-	kfree(priv->channel_info);
+-
+-	kfree(priv->ieee_channels);
+-	kfree(priv->ieee_rates);
++	iwl4965_free_channel_map(priv);
++	iwl4965_free_geos(priv);
+ 
+ 	if (priv->ibss_beacon)
+ 		dev_kfree_skb(priv->ibss_beacon);
+@@ -9236,93 +9337,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
  
  #ifdef CONFIG_PM
  
@@ -621205,10 +641907,10 @@
 +static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
  {
 -	struct iwl_priv *priv = pci_get_drvdata(pdev);
+-
+-	set_bit(STATUS_IN_SUSPEND, &priv->status);
 +	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
  
--	set_bit(STATUS_IN_SUSPEND, &priv->status);
--
 -	/* Take down the device; powers it off, etc. */
 -	iwl_down(priv);
 -
@@ -621303,7 +642005,7 @@
  	return 0;
  }
  
-@@ -9334,33 +9335,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
+@@ -9334,33 +9373,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
   *
   *****************************************************************************/
  
@@ -621348,7 +642050,7 @@
  		return ret;
  	}
  #endif
-@@ -9368,32 +9369,34 @@ static int __init iwl_init(void)
+@@ -9368,32 +9407,34 @@ static int __init iwl_init(void)
  	return ret;
  }
  
@@ -622667,19 +643369,19 @@
      All entries in the scan table (not just the new scan data when keep=1)
      will be displayed upon completion by use of the getscantable ioctl.
 diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
-index b61b176..c622e9b 100644
+index b61b176..87e145f 100644
 --- a/drivers/net/wireless/libertas/assoc.c
 +++ b/drivers/net/wireless/libertas/assoc.c
-@@ -9,39 +9,16 @@
+@@ -9,39 +9,18 @@
  #include "decl.h"
  #include "hostcmd.h"
  #include "host.h"
 +#include "cmd.h"
  
  
- static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- 
+-static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+-static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+-
 -static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
 -{
 -	DECLARE_MAC_BUF(mac);
@@ -622702,7 +643404,11 @@
 -	       assoc_req->secinfo.wep_enabled ? " WEP" : "",
 -	       assoc_req->secinfo.auth_mode);
 -}
--
++static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
++	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
++static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
++	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ 
  
 -static int assoc_helper_essid(wlan_private *priv,
 +static int assoc_helper_essid(struct lbs_private *priv,
@@ -622712,7 +643418,7 @@
  	int ret = 0;
  	struct bss_descriptor * bss;
  	int channel = -1;
-@@ -55,18 +32,17 @@ static int assoc_helper_essid(wlan_private *priv,
+@@ -55,18 +34,17 @@ static int assoc_helper_essid(wlan_private *priv,
  	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
  		channel = assoc_req->channel;
  
@@ -622735,7 +643441,7 @@
  		} else {
  			lbs_deb_assoc("SSID not found; cannot associate\n");
  		}
-@@ -74,23 +50,23 @@ static int assoc_helper_essid(wlan_private *priv,
+@@ -74,23 +52,23 @@ static int assoc_helper_essid(wlan_private *priv,
  		/* Scan for the network, do not save previous results.  Stale
  		 *   scan data will cause us to join a non-existant adhoc network
  		 */
@@ -622763,7 +643469,7 @@
  		}
  	}
  
-@@ -99,10 +75,9 @@ static int assoc_helper_essid(wlan_private *priv,
+@@ -99,10 +77,9 @@ static int assoc_helper_essid(wlan_private *priv,
  }
  
  
@@ -622775,7 +643481,7 @@
  	int ret = 0;
  	struct bss_descriptor * bss;
  	DECLARE_MAC_BUF(mac);
-@@ -111,7 +86,7 @@ static int assoc_helper_bssid(wlan_private *priv,
+@@ -111,7 +88,7 @@ static int assoc_helper_bssid(wlan_private *priv,
  		print_mac(mac, assoc_req->bssid));
  
  	/* Search for index position in list for requested MAC */
@@ -622784,7 +643490,7 @@
  			    assoc_req->mode);
  	if (bss == NULL) {
  		lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
-@@ -121,10 +96,10 @@ static int assoc_helper_bssid(wlan_private *priv,
+@@ -121,10 +98,10 @@ static int assoc_helper_bssid(wlan_private *priv,
  
  	memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
  	if (assoc_req->mode == IW_MODE_INFRA) {
@@ -622798,7 +643504,7 @@
  	}
  
  out:
-@@ -133,11 +108,13 @@ out:
+@@ -133,11 +110,13 @@ out:
  }
  
  
@@ -622813,7 +643519,7 @@
  	/* If we're given and 'any' BSSID, try associating based on SSID */
  
  	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-@@ -145,42 +122,36 @@ static int assoc_helper_associate(wlan_private *priv,
+@@ -145,42 +124,36 @@ static int assoc_helper_associate(wlan_private *priv,
  		    && compare_ether_addr(bssid_off, assoc_req->bssid)) {
  			ret = assoc_helper_bssid(priv, assoc_req);
  			done = 1;
@@ -622864,7 +643570,7 @@
  				    CMD_802_11_SNMP_MIB,
  				    0, CMD_OPTION_WAITFORRSP,
  				    OID_802_11_INFRASTRUCTURE_MODE,
-@@ -192,57 +163,76 @@ done:
+@@ -192,57 +165,76 @@ done:
  }
  
  
@@ -622968,7 +643674,7 @@
  	}
  
  	if (   assoc_req->secinfo.wep_enabled
-@@ -255,83 +245,75 @@ static int assoc_helper_channel(wlan_private *priv,
+@@ -255,83 +247,75 @@ static int assoc_helper_channel(wlan_private *priv,
  	}
  
  	/* Must restart/rejoin adhoc networks after channel change */
@@ -623081,7 +643787,7 @@
  	if (ret)
  		goto out;
  
-@@ -341,28 +323,19 @@ static int assoc_helper_secinfo(wlan_private *priv,
+@@ -341,28 +325,19 @@ static int assoc_helper_secinfo(wlan_private *priv,
  	 */
  
  	/* Get RSN enabled/disabled */
@@ -623114,7 +643820,7 @@
  
  out:
  	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-@@ -370,7 +343,7 @@ out:
+@@ -370,7 +345,7 @@ out:
  }
  
  
@@ -623123,7 +643829,7 @@
                                   struct assoc_request * assoc_req)
  {
  	int ret = 0;
-@@ -385,7 +358,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
+@@ -385,7 +360,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
  
  	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
  		clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
@@ -623132,7 +643838,7 @@
  					CMD_802_11_KEY_MATERIAL,
  					CMD_ACT_SET,
  					CMD_OPTION_WAITFORRSP,
-@@ -399,7 +372,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
+@@ -399,7 +374,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
  	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
  		clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
  
@@ -623141,7 +643847,7 @@
  					CMD_802_11_KEY_MATERIAL,
  					CMD_ACT_SET,
  					CMD_OPTION_WAITFORRSP,
-@@ -413,20 +386,19 @@ out:
+@@ -413,20 +388,19 @@ out:
  }
  
  
@@ -623167,7 +643873,7 @@
  	}
  
  	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-@@ -434,55 +406,68 @@ static int assoc_helper_wpa_ie(wlan_private *priv,
+@@ -434,55 +408,68 @@ static int assoc_helper_wpa_ie(wlan_private *priv,
  }
  
  
@@ -623256,7 +643962,7 @@
  	                      assoc_req->ssid, assoc_req->ssid_len) != 0)
  		return 1;
  
-@@ -493,18 +478,19 @@ static int should_stop_adhoc(wlan_adapter *adapter,
+@@ -493,18 +480,19 @@ static int should_stop_adhoc(wlan_adapter *adapter,
  	}
  
  	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
@@ -623280,7 +643986,7 @@
  	struct assoc_request * assoc_req = NULL;
  	int ret = 0;
  	int find_any_ssid = 0;
-@@ -512,16 +498,33 @@ void libertas_association_worker(struct work_struct *work)
+@@ -512,16 +500,33 @@ void libertas_association_worker(struct work_struct *work)
  
  	lbs_deb_enter(LBS_DEB_ASSOC);
  
@@ -623320,7 +644026,7 @@
  
  	/* If 'any' SSID was specified, find an SSID to associate with */
  	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
-@@ -538,7 +541,7 @@ void libertas_association_worker(struct work_struct *work)
+@@ -538,7 +543,7 @@ void libertas_association_worker(struct work_struct *work)
  	if (find_any_ssid) {
  		u8 new_mode;
  
@@ -623329,7 +644035,7 @@
  				&assoc_req->ssid_len, assoc_req->mode, &new_mode);
  		if (ret) {
  			lbs_deb_assoc("Could not find best network\n");
-@@ -557,18 +560,18 @@ void libertas_association_worker(struct work_struct *work)
+@@ -557,18 +562,18 @@ void libertas_association_worker(struct work_struct *work)
  	 * Check if the attributes being changing require deauthentication
  	 * from the currently associated infrastructure access point.
  	 */
@@ -623354,7 +644060,7 @@
  			if (ret) {
  				lbs_deb_assoc("Teardown of AdHoc network due to "
  					"new configuration request failed: %d\n",
-@@ -581,58 +584,40 @@ void libertas_association_worker(struct work_struct *work)
+@@ -581,58 +586,40 @@ void libertas_association_worker(struct work_struct *work)
  	/* Send the various configuration bits to the firmware */
  	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
  		ret = assoc_helper_mode(priv, assoc_req);
@@ -623419,7 +644125,7 @@
  	}
  
  	/* SSID/BSSID should be the _last_ config option set, because they
-@@ -644,28 +629,27 @@ void libertas_association_worker(struct work_struct *work)
+@@ -644,28 +631,27 @@ void libertas_association_worker(struct work_struct *work)
  
  		ret = assoc_helper_associate(priv, assoc_req);
  		if (ret) {
@@ -623458,7 +644164,7 @@
  				CMD_802_11_GET_LOG,
  				0, CMD_OPTION_WAITFORRSP, 0, NULL);
  		} else {
-@@ -679,9 +663,9 @@ out:
+@@ -679,9 +665,9 @@ out:
  			ret);
  	}
  
@@ -623471,7 +644177,7 @@
  	kfree(assoc_req);
  
  done:
-@@ -692,14 +676,15 @@ done:
+@@ -692,14 +678,15 @@ done:
  /*
   * Caller MUST hold any necessary locks
   */
@@ -623491,7 +644197,7 @@
  			lbs_pr_info("Not enough memory to allocate association"
  				" request!\n");
  			return NULL;
-@@ -709,60 +694,59 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+@@ -709,60 +696,59 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
  	/* Copy current configuration attributes to the association request,
  	 * but don't overwrite any that are already set.
  	 */
@@ -629379,7 +650085,7 @@
 -#endif				/* _WLAN_DEFS_H_ */
 +#endif
 diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
-index 1fb807a..58d7ef6 100644
+index 1fb807a..5a69f2b 100644
 --- a/drivers/net/wireless/libertas/dev.h
 +++ b/drivers/net/wireless/libertas/dev.h
 @@ -1,21 +1,20 @@
@@ -629495,10 +650201,7 @@
 -	int (*hw_get_int_status) (wlan_private * priv, u8 *);
 -	int (*hw_read_event_cause) (wlan_private *);
 -};
-+	int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
-+	int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
-+	int (*hw_read_event_cause) (struct lbs_private *);
- 
+-
 -/** Association request
 - *
 - * Encapsulates all the options that describe a specific assocation request
@@ -629517,11 +650220,7 @@
 -#define ASSOC_FLAG_SECINFO		10
 -#define ASSOC_FLAG_WPA_IE		11
 -	unsigned long flags;
-+	/* Wake On LAN */
-+	uint32_t wol_criteria;
-+	uint8_t wol_gpio;
-+	uint8_t wol_gap;
- 
+-
 -	u8 ssid[IW_ESSID_MAX_SIZE + 1];
 -	u8 ssid_len;
 -	u8 channel;
@@ -629536,14 +650235,21 @@
 -	/** WPA keys */
 -	struct enc_key wpa_mcast_key;
 -	struct enc_key wpa_unicast_key;
-+	/* was struct lbs_adapter from here... */
++	int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
++	int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
++	int (*hw_read_event_cause) (struct lbs_private *);
  
 -	struct wlan_802_11_security secinfo;
--
++	/* Wake On LAN */
++	uint32_t wol_criteria;
++	uint8_t wol_gpio;
++	uint8_t wol_gap;
+ 
 -	/** WPA Information Elements*/
 -	u8 wpa_ie[MAX_WPA_IE_LEN];
 -	u8 wpa_ie_len;
--
++	/* was struct lbs_adapter from here... */
+ 
 -	/* BSS to associate with for infrastructure of Ad-Hoc join */
 -	struct bss_descriptor bss;
 -};
@@ -629694,19 +650400,19 @@
 +#define ASSOC_FLAG_SECINFO		10
 +#define ASSOC_FLAG_WPA_IE		11
 +	unsigned long flags;
- 
--	u8 last_scanned_channel;
++
 +	u8 ssid[IW_ESSID_MAX_SIZE + 1];
 +	u8 ssid_len;
 +	u8 channel;
 +	u8 band;
 +	u8 mode;
-+	u8 bssid[ETH_ALEN];
++	u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
 +
 +	/** WEP keys */
 +	struct enc_key wep_keys[4];
 +	u16 wep_tx_keyidx;
-+
+ 
+-	u8 last_scanned_channel;
 +	/** WPA keys */
 +	struct enc_key wpa_mcast_key;
 +	struct enc_key wpa_unicast_key;
@@ -630743,7 +651449,7 @@
  } __attribute__ ((packed));
  
 diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
-index ba4fc2b..4b5ab9a 100644
+index ba4fc2b..5a9cadb 100644
 --- a/drivers/net/wireless/libertas/if_cs.c
 +++ b/drivers/net/wireless/libertas/if_cs.c
 @@ -57,7 +57,7 @@ MODULE_LICENSE("GPL");
@@ -630755,7 +651461,7 @@
  	void __iomem *iobase;
  };
  
-@@ -243,7 +243,7 @@ static inline void if_cs_disable_ints(struct if_cs_card *card)
+@@ -243,35 +243,30 @@ static inline void if_cs_disable_ints(struct if_cs_card *card)
  
  static irqreturn_t if_cs_interrupt(int irq, void *data)
  {
@@ -630764,7 +651470,10 @@
  	u16 int_cause;
  
  	lbs_deb_enter(LBS_DEB_CS);
-@@ -253,25 +253,20 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
+ 
+ 	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
+-	if(int_cause == 0x0) {
++	if (int_cause == 0x0) {
  		/* Not for us */
  		return IRQ_NONE;
  
@@ -630772,8 +651481,9 @@
 +	} else if (int_cause == 0xffff) {
  		/* Read in junk, the card has probably been removed */
 -		card->priv->adapter->surpriseremoved = 1;
+-
 +		card->priv->surpriseremoved = 1;
- 
++		return IRQ_HANDLED;
  	} else {
 -		if(int_cause & IF_CS_H_IC_TX_OVER) {
 -			card->priv->dnld_sent = DNLD_RES_RECEIVED;
@@ -630932,6 +651642,16 @@
  	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
  
  	return 0;
+@@ -725,8 +717,8 @@ static void if_cs_release(struct pcmcia_device *p_dev)
+ 
+ 	lbs_deb_enter(LBS_DEB_CS);
+ 
+-	pcmcia_disable_device(p_dev);
+ 	free_irq(p_dev->irq.AssignedIRQ, card);
++	pcmcia_disable_device(p_dev);
+ 	if (card->iobase)
+ 		ioport_unmap(card->iobase);
+ 
 @@ -746,7 +738,7 @@ static void if_cs_release(struct pcmcia_device *p_dev)
  static int if_cs_probe(struct pcmcia_device *p_dev)
  {
@@ -641902,614 +662622,3377 @@
      }
  /* TBD reserve  skb_reserve(skb, delta); */
      skb_pull(skb, delta);
-diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
-index 31c1dd2..d6cba13 100644
---- a/drivers/net/wireless/rt2x00/rt2400pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
-@@ -24,11 +24,6 @@
- 	Supported chipsets: RT2460.
-  */
- 
--/*
-- * Set enviroment defines for rt2x00.h
-- */
--#define DRV_NAME "rt2400pci"
--
- #include <linux/delay.h>
- #include <linux/etherdevice.h>
- #include <linux/init.h>
-@@ -54,7 +49,7 @@
-  * the access attempt is considered to have failed,
-  * and we will print an error.
-  */
--static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
-+static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
- {
- 	u32 reg;
- 	unsigned int i;
-@@ -69,7 +64,7 @@ static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
- 	return reg;
- }
- 
--static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
-+static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
- 				const unsigned int word, const u8 value)
- {
- 	u32 reg;
-@@ -95,7 +90,7 @@ static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
- 	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
- }
- 
--static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
-+static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
- 			       const unsigned int word, u8 *value)
- {
- 	u32 reg;
-@@ -132,7 +127,7 @@ static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
- 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
- }
- 
--static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
-+static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
- 			       const unsigned int word, const u32 value)
- {
- 	u32 reg;
-@@ -195,13 +190,13 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
- #ifdef CONFIG_RT2X00_LIB_DEBUGFS
- #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
- 
--static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
-+static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
- 			       const unsigned int word, u32 *data)
- {
- 	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
- }
- 
--static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
-+static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
- 				const unsigned int word, u32 data)
- {
- 	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-@@ -285,7 +280,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
- 	 */
- 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
- 	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
--	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-+	rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
- 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- 	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
- 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-@@ -397,7 +392,7 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
- }
- 
- static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
--				     int antenna_tx, int antenna_rx)
-+				     struct antenna_setup *ant)
- {
- 	u8 r1;
- 	u8 r4;
-@@ -408,14 +403,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
- 	/*
- 	 * Configure the TX antenna.
- 	 */
--	switch (antenna_tx) {
--	case ANTENNA_SW_DIVERSITY:
-+	switch (ant->tx) {
- 	case ANTENNA_HW_DIVERSITY:
- 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
- 		break;
- 	case ANTENNA_A:
- 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
- 		break;
-+	case ANTENNA_SW_DIVERSITY:
-+		/*
-+		 * NOTE: We should never come here because rt2x00lib is
-+		 * supposed to catch this and send us the correct antenna
-+		 * explicitely. However we are nog going to bug about this.
-+		 * Instead, just default to antenna B.
-+		 */
- 	case ANTENNA_B:
- 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
- 		break;
-@@ -424,14 +425,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
- 	/*
- 	 * Configure the RX antenna.
- 	 */
--	switch (antenna_rx) {
--	case ANTENNA_SW_DIVERSITY:
-+	switch (ant->rx) {
- 	case ANTENNA_HW_DIVERSITY:
- 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
- 		break;
- 	case ANTENNA_A:
- 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
- 		break;
-+	case ANTENNA_SW_DIVERSITY:
-+		/*
-+		 * NOTE: We should never come here because rt2x00lib is
-+		 * supposed to catch this and send us the correct antenna
-+		 * explicitely. However we are nog going to bug about this.
-+		 * Instead, just default to antenna B.
-+		 */
- 	case ANTENNA_B:
- 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
- 		break;
-@@ -485,9 +492,7 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
- 		rt2400pci_config_txpower(rt2x00dev,
- 					 libconf->conf->power_level);
- 	if (flags & CONFIG_UPDATE_ANTENNA)
--		rt2400pci_config_antenna(rt2x00dev,
--					 libconf->conf->antenna_sel_tx,
--					 libconf->conf->antenna_sel_rx);
-+		rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
- 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
- 		rt2400pci_config_duration(rt2x00dev, libconf);
- }
-@@ -514,18 +519,10 @@ static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
- 
- 	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
- 	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
--
--	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
--		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
--		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
--	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
--		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
--		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
--	} else {
--		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
--		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
--	}
--
-+	rt2x00_set_field32(&reg, LEDCSR_LINK,
-+			   (rt2x00dev->led_mode != LED_MODE_ASUS));
-+	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
-+			   (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
- 	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
- }
- 
-@@ -542,7 +539,8 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
- /*
-  * Link tuning
-  */
--static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
-+static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
-+				 struct link_qual *qual)
- {
- 	u32 reg;
- 	u8 bbp;
-@@ -551,13 +549,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
- 	 * Update FCS error count from register.
- 	 */
- 	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
--	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
-+	qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
- 
- 	/*
- 	 * Update False CCA count from register.
- 	 */
- 	rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
--	rt2x00dev->link.false_cca = bbp;
-+	qual->false_cca = bbp;
- }
- 
- static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
-@@ -582,10 +580,10 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
- 	 */
- 	rt2400pci_bbp_read(rt2x00dev, 13, &reg);
- 
--	if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
-+	if (rt2x00dev->link.qual.false_cca > 512 && reg < 0x20) {
- 		rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
- 		rt2x00dev->link.vgc_level = reg;
--	} else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
-+	} else if (rt2x00dev->link.qual.false_cca < 100 && reg > 0x08) {
- 		rt2400pci_bbp_write(rt2x00dev, 13, --reg);
- 		rt2x00dev->link.vgc_level = reg;
- 	}
-@@ -594,65 +592,43 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
- /*
-  * Initialization functions.
-  */
--static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
-+static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
-+				   struct data_entry *entry)
- {
--	struct data_ring *ring = rt2x00dev->rx;
--	struct data_desc *rxd;
--	unsigned int i;
-+	__le32 *rxd = entry->priv;
- 	u32 word;
- 
--	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
--
--	for (i = 0; i < ring->stats.limit; i++) {
--		rxd = ring->entry[i].priv;
--
--		rt2x00_desc_read(rxd, 2, &word);
--		rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
--				   ring->data_size);
--		rt2x00_desc_write(rxd, 2, word);
--
--		rt2x00_desc_read(rxd, 1, &word);
--		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
--				   ring->entry[i].data_dma);
--		rt2x00_desc_write(rxd, 1, word);
-+	rt2x00_desc_read(rxd, 2, &word);
-+	rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size);
-+	rt2x00_desc_write(rxd, 2, word);
- 
--		rt2x00_desc_read(rxd, 0, &word);
--		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
--		rt2x00_desc_write(rxd, 0, word);
--	}
-+	rt2x00_desc_read(rxd, 1, &word);
-+	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
-+	rt2x00_desc_write(rxd, 1, word);
- 
--	rt2x00_ring_index_clear(rt2x00dev->rx);
-+	rt2x00_desc_read(rxd, 0, &word);
-+	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-+	rt2x00_desc_write(rxd, 0, word);
- }
- 
--static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
-+static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
-+				   struct data_entry *entry)
- {
--	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
--	struct data_desc *txd;
--	unsigned int i;
-+	__le32 *txd = entry->priv;
- 	u32 word;
- 
--	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
--
--	for (i = 0; i < ring->stats.limit; i++) {
--		txd = ring->entry[i].priv;
--
--		rt2x00_desc_read(txd, 1, &word);
--		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
--				   ring->entry[i].data_dma);
--		rt2x00_desc_write(txd, 1, word);
--
--		rt2x00_desc_read(txd, 2, &word);
--		rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
--				   ring->data_size);
--		rt2x00_desc_write(txd, 2, word);
-+	rt2x00_desc_read(txd, 1, &word);
-+	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
-+	rt2x00_desc_write(txd, 1, word);
- 
--		rt2x00_desc_read(txd, 0, &word);
--		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
--		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
--		rt2x00_desc_write(txd, 0, word);
--	}
-+	rt2x00_desc_read(txd, 2, &word);
-+	rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size);
-+	rt2x00_desc_write(txd, 2, word);
- 
--	rt2x00_ring_index_clear(ring);
-+	rt2x00_desc_read(txd, 0, &word);
-+	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-+	rt2x00_desc_write(txd, 0, word);
- }
- 
- static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
-@@ -660,15 +636,6 @@ static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
- 	u32 reg;
- 
- 	/*
--	 * Initialize rings.
--	 */
--	rt2400pci_init_rxring(rt2x00dev);
--	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
--	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
--	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
--	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
--
--	/*
- 	 * Initialize registers.
- 	 */
- 	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
-@@ -1014,53 +981,37 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
-  * TX descriptor initialization
-  */
- static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
--				    struct data_desc *txd,
-+				    struct sk_buff *skb,
- 				    struct txdata_entry_desc *desc,
--				    struct ieee80211_hdr *ieee80211hdr,
--				    unsigned int length,
- 				    struct ieee80211_tx_control *control)
- {
-+	struct skb_desc *skbdesc = get_skb_desc(skb);
-+	__le32 *txd = skbdesc->desc;
- 	u32 word;
--	u32 signal = 0;
--	u32 service = 0;
--	u32 length_high = 0;
--	u32 length_low = 0;
--
--	/*
--	 * The PLCP values should be treated as if they
--	 * were BBP values.
--	 */
--	rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
--	rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
--	rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
--
--	rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
--	rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
--	rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
--
--	rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
--	rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
--	rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
--
--	rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
--	rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
--	rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
- 
- 	/*
- 	 * Start writing the descriptor words.
- 	 */
- 	rt2x00_desc_read(txd, 2, &word);
--	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
-+	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
- 	rt2x00_desc_write(txd, 2, word);
- 
- 	rt2x00_desc_read(txd, 3, &word);
--	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
--	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1);
- 	rt2x00_desc_write(txd, 3, word);
- 
- 	rt2x00_desc_read(txd, 4, &word);
--	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
--	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
-+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1);
-+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7);
-+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
- 	rt2x00_desc_write(txd, 4, word);
- 
- 	rt2x00_desc_read(txd, 0, &word);
-@@ -1069,7 +1020,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
- 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
- 	rt2x00_set_field32(&word, TXD_W0_ACK,
--			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
-+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
- 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
- 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
- 	rt2x00_set_field32(&word, TXD_W0_RTS,
-@@ -1099,12 +1050,12 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- 	}
- 
- 	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
--	if (queue == IEEE80211_TX_QUEUE_DATA0)
--		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
--	else if (queue == IEEE80211_TX_QUEUE_DATA1)
--		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
--	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
--		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
-+	rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
-+			   (queue == IEEE80211_TX_QUEUE_DATA0));
-+	rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
-+			   (queue == IEEE80211_TX_QUEUE_DATA1));
-+	rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
-+			   (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
- 	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
- 
-@@ -1114,7 +1065,7 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- static void rt2400pci_fill_rxdone(struct data_entry *entry,
- 				  struct rxdata_entry_desc *desc)
- {
--	struct data_desc *rxd = entry->priv;
-+	__le32 *rxd = entry->priv;
- 	u32 word0;
- 	u32 word2;
- 
-@@ -1135,6 +1086,7 @@ static void rt2400pci_fill_rxdone(struct data_entry *entry,
- 	    entry->ring->rt2x00dev->rssi_offset;
- 	desc->ofdm = 0;
- 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
- }
- 
- /*
-@@ -1144,7 +1096,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
- {
- 	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
- 	struct data_entry *entry;
--	struct data_desc *txd;
-+	__le32 *txd;
- 	u32 word;
- 	int tx_status;
- 	int retry;
-@@ -1164,26 +1116,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
- 		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
- 		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- 
--		rt2x00lib_txdone(entry, tx_status, retry);
--
--		/*
--		 * Make this entry available for reuse.
--		 */
--		entry->flags = 0;
--		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
--		rt2x00_desc_write(txd, 0, word);
--		rt2x00_ring_index_done_inc(ring);
-+		rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
- 	}
--
--	/*
--	 * If the data ring was full before the txdone handler
--	 * we must make sure the packet queue in the mac80211 stack
--	 * is reenabled when the txdone handler has finished.
--	 */
--	entry = ring->entry;
--	if (!rt2x00_ring_full(ring))
--		ieee80211_wake_queue(rt2x00dev->hw,
--				     entry->tx_status.control.queue);
- }
- 
- static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
-@@ -1315,12 +1249,23 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
- 	/*
- 	 * Identify default antenna configuration.
- 	 */
--	rt2x00dev->hw->conf.antenna_sel_tx =
-+	rt2x00dev->default_ant.tx =
- 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
--	rt2x00dev->hw->conf.antenna_sel_rx =
-+	rt2x00dev->default_ant.rx =
- 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
- 
- 	/*
-+	 * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead.
-+	 * I am not 100% sure about this, but the legacy drivers do not
-+	 * indicate antenna swapping in software is required when
-+	 * diversity is enabled.
-+	 */
-+	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
-+		rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY;
-+	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
-+		rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY;
+diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
+new file mode 100644
+index 0000000..d3ecf89
+--- /dev/null
++++ b/drivers/net/wireless/rndis_wlan.c
+@@ -0,0 +1,2757 @@
++/*
++ * Driver for RNDIS based wireless USB devices.
++ *
++ * Copyright (C) 2007 by Bjorge Dijkstra <bjd at jooz.net>
++ * Copyright (C) 2008 by Jussi Kivilinna <jussi.kivilinna at mbnet.fi>
++ *
++ * 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
++ *
++ *  Portions of this file are based on NDISwrapper project,
++ *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
++ *  http://ndiswrapper.sourceforge.net/
++ */
 +
-+	/*
- 	 * Store led mode, for correct led behaviour.
- 	 */
- 	rt2x00dev->led_mode =
-@@ -1447,7 +1392,6 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
- 				       struct dev_addr_list *mc_list)
- {
- 	struct rt2x00_dev *rt2x00dev = hw->priv;
--	struct interface *intf = &rt2x00dev->interface;
- 	u32 reg;
- 
- 	/*
-@@ -1466,21 +1410,18 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
- 	 * Apply some rules to the filters:
- 	 * - Some filters imply different filters to be set.
- 	 * - Some things we can't filter out at all.
--	 * - Some filters are set based on interface type.
- 	 */
- 	*total_flags |= FIF_ALLMULTI;
- 	if (*total_flags & FIF_OTHER_BSS ||
- 	    *total_flags & FIF_PROMISC_IN_BSS)
- 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
--	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
--		*total_flags |= FIF_PROMISC_IN_BSS;
- 
- 	/*
- 	 * Check if there is any work left for us.
- 	 */
--	if (intf->filter == *total_flags)
-+	if (rt2x00dev->packet_filter == *total_flags)
- 		return;
--	intf->filter = *total_flags;
-+	rt2x00dev->packet_filter = *total_flags;
- 
- 	/*
- 	 * Start configuration steps.
-@@ -1583,7 +1524,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
- 	.configure_filter	= rt2400pci_configure_filter,
- 	.get_stats		= rt2x00mac_get_stats,
- 	.set_retry_limit	= rt2400pci_set_retry_limit,
--	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
-+	.bss_info_changed	= rt2x00mac_bss_info_changed,
- 	.conf_tx		= rt2400pci_conf_tx,
- 	.get_tx_stats		= rt2x00mac_get_tx_stats,
- 	.get_tsf		= rt2400pci_get_tsf,
-@@ -1597,6 +1538,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
- 	.probe_hw		= rt2400pci_probe_hw,
- 	.initialize		= rt2x00pci_initialize,
- 	.uninitialize		= rt2x00pci_uninitialize,
-+	.init_rxentry		= rt2400pci_init_rxentry,
-+	.init_txentry		= rt2400pci_init_txentry,
- 	.set_device_state	= rt2400pci_set_device_state,
- 	.rfkill_poll		= rt2400pci_rfkill_poll,
- 	.link_stats		= rt2400pci_link_stats,
-@@ -1614,7 +1557,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
- };
- 
- static const struct rt2x00_ops rt2400pci_ops = {
--	.name		= DRV_NAME,
-+	.name		= KBUILD_MODNAME,
- 	.rxd_size	= RXD_DESC_SIZE,
- 	.txd_size	= TXD_DESC_SIZE,
- 	.eeprom_size	= EEPROM_SIZE,
-@@ -1642,7 +1585,7 @@ MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
- MODULE_LICENSE("GPL");
- 
- static struct pci_driver rt2400pci_driver = {
--	.name		= DRV_NAME,
-+	.name		= KBUILD_MODNAME,
- 	.id_table	= rt2400pci_device_table,
- 	.probe		= rt2x00pci_probe,
- 	.remove		= __devexit_p(rt2x00pci_remove),
-diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
-index ae22501..369aac6 100644
---- a/drivers/net/wireless/rt2x00/rt2400pci.h
-+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
-@@ -803,8 +803,8 @@
- /*
-  * DMA descriptor defines.
-  */
--#define TXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
--#define RXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
-+#define TXD_DESC_SIZE			( 8 * sizeof(__le32) )
-+#define RXD_DESC_SIZE			( 8 * sizeof(__le32) )
- 
- /*
-  * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
-@@ -839,11 +839,21 @@
- 
- /*
-  * Word3 & 4: PLCP information
-- */
--#define TXD_W3_PLCP_SIGNAL		FIELD32(0x0000ffff)
--#define TXD_W3_PLCP_SERVICE		FIELD32(0xffff0000)
--#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x0000ffff)
--#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0xffff0000)
-+ * The PLCP values should be treated as if they were BBP values.
++// #define	DEBUG			// error path messages, extra info
++// #define	VERBOSE			// more; success messages
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/workqueue.h>
++#include <linux/mutex.h>
++#include <linux/mii.h>
++#include <linux/usb.h>
++#include <linux/usb/cdc.h>
++#include <linux/wireless.h>
++#include <linux/if_arp.h>
++#include <linux/ctype.h>
++#include <linux/spinlock.h>
++#include <net/iw_handler.h>
++#include <net/ieee80211.h>
++#include <linux/usb/usbnet.h>
++#include <linux/usb/rndis_host.h>
++
++
++/* NOTE: All these are settings for Broadcom chipset */
++static char modparam_country[4] = "EU";
++module_param_string(country, modparam_country, 4, 0444);
++MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU");
++
++static int modparam_frameburst = 1;
++module_param_named(frameburst, modparam_frameburst, int, 0444);
++MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)");
++
++static int modparam_afterburner = 0;
++module_param_named(afterburner, modparam_afterburner, int, 0444);
++MODULE_PARM_DESC(afterburner,
++	"enable afterburner aka '125 High Speed Mode' (default: off)");
++
++static int modparam_power_save = 0;
++module_param_named(power_save, modparam_power_save, int, 0444);
++MODULE_PARM_DESC(power_save,
++	"set power save mode: 0=off, 1=on, 2=fast (default: off)");
++
++static int modparam_power_output = 3;
++module_param_named(power_output, modparam_power_output, int, 0444);
++MODULE_PARM_DESC(power_output,
++	"set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)");
++
++static int modparam_roamtrigger = -70;
++module_param_named(roamtrigger, modparam_roamtrigger, int, 0444);
++MODULE_PARM_DESC(roamtrigger,
++	"set roaming dBm trigger: -80=optimize for distance, "
++				"-60=bandwidth (default: -70)");
++
++static int modparam_roamdelta = 1;
++module_param_named(roamdelta, modparam_roamdelta, int, 0444);
++MODULE_PARM_DESC(roamdelta,
++	"set roaming tendency: 0=aggressive, 1=moderate, "
++				"2=conservative (default: moderate)");
++
++static int modparam_workaround_interval = 500;
++module_param_named(workaround_interval, modparam_workaround_interval,
++							int, 0444);
++MODULE_PARM_DESC(workaround_interval,
++	"set stall workaround interval in msecs (default: 500)");
++
++
++/* various RNDIS OID defs */
++#define OID_GEN_LINK_SPEED			ccpu2(0x00010107)
++#define OID_GEN_RNDIS_CONFIG_PARAMETER		ccpu2(0x0001021b)
++
++#define OID_GEN_XMIT_OK				ccpu2(0x00020101)
++#define OID_GEN_RCV_OK				ccpu2(0x00020102)
++#define OID_GEN_XMIT_ERROR			ccpu2(0x00020103)
++#define OID_GEN_RCV_ERROR			ccpu2(0x00020104)
++#define OID_GEN_RCV_NO_BUFFER			ccpu2(0x00020105)
++
++#define OID_802_3_PERMANENT_ADDRESS		ccpu2(0x01010101)
++#define OID_802_3_CURRENT_ADDRESS		ccpu2(0x01010102)
++#define OID_802_3_MULTICAST_LIST		ccpu2(0x01010103)
++#define OID_802_3_MAXIMUM_LIST_SIZE		ccpu2(0x01010104)
++
++#define OID_802_11_BSSID			ccpu2(0x0d010101)
++#define OID_802_11_SSID				ccpu2(0x0d010102)
++#define OID_802_11_INFRASTRUCTURE_MODE		ccpu2(0x0d010108)
++#define OID_802_11_ADD_WEP			ccpu2(0x0d010113)
++#define OID_802_11_REMOVE_WEP			ccpu2(0x0d010114)
++#define OID_802_11_DISASSOCIATE			ccpu2(0x0d010115)
++#define OID_802_11_AUTHENTICATION_MODE		ccpu2(0x0d010118)
++#define OID_802_11_PRIVACY_FILTER		ccpu2(0x0d010119)
++#define OID_802_11_BSSID_LIST_SCAN		ccpu2(0x0d01011a)
++#define OID_802_11_ENCRYPTION_STATUS		ccpu2(0x0d01011b)
++#define OID_802_11_ADD_KEY			ccpu2(0x0d01011d)
++#define OID_802_11_REMOVE_KEY			ccpu2(0x0d01011e)
++#define OID_802_11_PMKID			ccpu2(0x0d010123)
++#define OID_802_11_NETWORK_TYPES_SUPPORTED	ccpu2(0x0d010203)
++#define OID_802_11_NETWORK_TYPE_IN_USE		ccpu2(0x0d010204)
++#define OID_802_11_TX_POWER_LEVEL		ccpu2(0x0d010205)
++#define OID_802_11_RSSI				ccpu2(0x0d010206)
++#define OID_802_11_RSSI_TRIGGER			ccpu2(0x0d010207)
++#define OID_802_11_FRAGMENTATION_THRESHOLD	ccpu2(0x0d010209)
++#define OID_802_11_RTS_THRESHOLD		ccpu2(0x0d01020a)
++#define OID_802_11_SUPPORTED_RATES		ccpu2(0x0d01020e)
++#define OID_802_11_CONFIGURATION		ccpu2(0x0d010211)
++#define OID_802_11_BSSID_LIST			ccpu2(0x0d010217)
++
++
++/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */
++#define	WL_NOISE	-96	/* typical noise level in dBm */
++#define	WL_SIGMAX	-32	/* typical maximum signal level in dBm */
++
++
++/* Assume that Broadcom 4320 (only chipset at time of writing known to be
++ * based on wireless rndis) has default txpower of 13dBm.
++ * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
++ *   13dBm == 19.9mW
++ */
++#define BCM4320_DEFAULT_TXPOWER 20
++
++
++/* codes for "status" field of completion messages */
++#define RNDIS_STATUS_ADAPTER_NOT_READY		ccpu2(0xc0010011)
++#define RNDIS_STATUS_ADAPTER_NOT_OPEN		ccpu2(0xc0010012)
++
++
++/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
++ * slightly modified for datatype endianess, etc
++ */
++#define NDIS_802_11_LENGTH_SSID 32
++#define NDIS_802_11_LENGTH_RATES 8
++#define NDIS_802_11_LENGTH_RATES_EX 16
++
++struct NDIS_802_11_SSID {
++	__le32 SsidLength;
++	u8 Ssid[NDIS_802_11_LENGTH_SSID];
++} __attribute__((packed));
++
++enum NDIS_802_11_NETWORK_TYPE {
++	Ndis802_11FH,
++	Ndis802_11DS,
++	Ndis802_11OFDM5,
++	Ndis802_11OFDM24,
++	Ndis802_11NetworkTypeMax
++};
++
++struct NDIS_802_11_CONFIGURATION_FH {
++	__le32 Length;
++	__le32 HopPattern;
++	__le32 HopSet;
++	__le32 DwellTime;
++} __attribute__((packed));
++
++struct NDIS_802_11_CONFIGURATION {
++	__le32 Length;
++	__le32 BeaconPeriod;
++	__le32 ATIMWindow;
++	__le32 DSConfig;
++	struct NDIS_802_11_CONFIGURATION_FH FHConfig;
++} __attribute__((packed));
++
++enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
++	Ndis802_11IBSS,
++	Ndis802_11Infrastructure,
++	Ndis802_11AutoUnknown,
++	Ndis802_11InfrastructureMax
++};
++
++enum NDIS_802_11_AUTHENTICATION_MODE {
++	Ndis802_11AuthModeOpen,
++	Ndis802_11AuthModeShared,
++	Ndis802_11AuthModeAutoSwitch,
++	Ndis802_11AuthModeWPA,
++	Ndis802_11AuthModeWPAPSK,
++	Ndis802_11AuthModeWPANone,
++	Ndis802_11AuthModeWPA2,
++	Ndis802_11AuthModeWPA2PSK,
++	Ndis802_11AuthModeMax
++};
++
++enum NDIS_802_11_ENCRYPTION_STATUS {
++	Ndis802_11WEPEnabled,
++	Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
++	Ndis802_11WEPDisabled,
++	Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
++	Ndis802_11WEPKeyAbsent,
++	Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
++	Ndis802_11WEPNotSupported,
++	Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
++	Ndis802_11Encryption2Enabled,
++	Ndis802_11Encryption2KeyAbsent,
++	Ndis802_11Encryption3Enabled,
++	Ndis802_11Encryption3KeyAbsent
++};
++
++enum NDIS_802_11_PRIVACY_FILTER {
++	Ndis802_11PrivFilterAcceptAll,
++	Ndis802_11PrivFilter8021xWEP
++};
++
++struct NDIS_WLAN_BSSID_EX {
++	__le32 Length;
++	u8 MacAddress[6];
++	u8 Padding[2];
++	struct NDIS_802_11_SSID Ssid;
++	__le32 Privacy;
++	__le32 Rssi;
++	enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
++	struct NDIS_802_11_CONFIGURATION Configuration;
++	enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
++	u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
++	__le32 IELength;
++	u8 IEs[0];
++} __attribute__((packed));
++
++struct NDIS_802_11_BSSID_LIST_EX {
++	__le32 NumberOfItems;
++	struct NDIS_WLAN_BSSID_EX Bssid[0];
++} __attribute__((packed));
++
++struct NDIS_802_11_FIXED_IEs {
++	u8 Timestamp[8];
++	__le16 BeaconInterval;
++	__le16 Capabilities;
++} __attribute__((packed));
++
++struct NDIS_802_11_WEP {
++	__le32 Length;
++	__le32 KeyIndex;
++	__le32 KeyLength;
++	u8 KeyMaterial[32];
++} __attribute__((packed));
++
++struct NDIS_802_11_KEY {
++	__le32 Length;
++	__le32 KeyIndex;
++	__le32 KeyLength;
++	u8 Bssid[6];
++	u8 Padding[6];
++	__le64 KeyRSC;
++	u8 KeyMaterial[32];
++} __attribute__((packed));
++
++struct NDIS_802_11_REMOVE_KEY {
++	__le32 Length;
++	__le32 KeyIndex;
++	u8 Bssid[6];
++} __attribute__((packed));
++
++struct RNDIS_CONFIG_PARAMETER_INFOBUFFER {
++	__le32 ParameterNameOffset;
++	__le32 ParameterNameLength;
++	__le32 ParameterType;
++	__le32 ParameterValueOffset;
++	__le32 ParameterValueLength;
++} __attribute__((packed));
++
++/* these have to match what is in wpa_supplicant */
++enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
++enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, CIPHER_WEP104 }
++	wpa_cipher;
++enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, KEY_MGMT_802_1X_NO_WPA,
++	KEY_MGMT_WPA_NONE } wpa_key_mgmt;
++
++/*
++ *  private data
 + */
-+#define TXD_W3_PLCP_SIGNAL		FIELD32(0x000000ff)
-+#define TXD_W3_PLCP_SIGNAL_REGNUM	FIELD32(0x00007f00)
-+#define TXD_W3_PLCP_SIGNAL_BUSY		FIELD32(0x00008000)
-+#define TXD_W3_PLCP_SERVICE		FIELD32(0x00ff0000)
-+#define TXD_W3_PLCP_SERVICE_REGNUM	FIELD32(0x7f000000)
-+#define TXD_W3_PLCP_SERVICE_BUSY	FIELD32(0x80000000)
++#define NET_TYPE_11FB	0
 +
-+#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x000000ff)
-+#define TXD_W3_PLCP_LENGTH_LOW_REGNUM	FIELD32(0x00007f00)
-+#define TXD_W3_PLCP_LENGTH_LOW_BUSY	FIELD32(0x00008000)
-+#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0x00ff0000)
-+#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM	FIELD32(0x7f000000)
-+#define TXD_W3_PLCP_LENGTH_HIGH_BUSY	FIELD32(0x80000000)
- 
- /*
-  * Word5
-diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
-index 702321c..e874fdc 100644
---- a/drivers/net/wireless/rt2x00/rt2500pci.c
-+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
-@@ -24,11 +24,6 @@
- 	Supported chipsets: RT2560.
-  */
- 
++#define CAP_MODE_80211A		1
++#define CAP_MODE_80211B		2
++#define CAP_MODE_80211G		4
++#define CAP_MODE_MASK		7
++#define CAP_SUPPORT_TXPOWER	8
++
++#define WORK_CONNECTION_EVENT	(1<<0)
++#define WORK_SET_MULTICAST_LIST	(1<<1)
++
++/* RNDIS device private data */
++struct rndis_wext_private {
++	char name[32];
++
++	struct usbnet *usbdev;
++
++	struct workqueue_struct *workqueue;
++	struct delayed_work stats_work;
++	struct work_struct work;
++	struct mutex command_lock;
++	spinlock_t stats_lock;
++	unsigned long work_pending;
++
++	struct iw_statistics iwstats;
++	struct iw_statistics privstats;
++
++	int  nick_len;
++	char nick[32];
++
++	int caps;
++	int multicast_size;
++
++	/* module parameters */
++	char param_country[4];
++	int  param_frameburst;
++	int  param_afterburner;
++	int  param_power_save;
++	int  param_power_output;
++	int  param_roamtrigger;
++	int  param_roamdelta;
++	u32  param_workaround_interval;
++
++	/* hardware state */
++	int radio_on;
++	int infra_mode;
++	struct NDIS_802_11_SSID essid;
++
++	/* encryption stuff */
++	int  encr_tx_key_index;
++	char encr_keys[4][32];
++	int  encr_key_len[4];
++	int  wpa_version;
++	int  wpa_keymgmt;
++	int  wpa_authalg;
++	int  wpa_ie_len;
++	u8  *wpa_ie;
++	int  wpa_cipher_pair;
++	int  wpa_cipher_group;
++};
++
++
++static const int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
++				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
++
++static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 };
++
++static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
++
++static const unsigned char zero_bssid[ETH_ALEN] = {0,};
++static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
++							0xff, 0xff, 0xff };
++
++
++static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev)
++{
++	return (struct rndis_wext_private *)dev->driver_priv;
++}
++
++
++static u32 get_bcm4320_power(struct rndis_wext_private *priv)
++{
++	return BCM4320_DEFAULT_TXPOWER *
++		bcm4320_power_output[priv->param_power_output] / 100;
++}
++
++
++/* translate error code */
++static int rndis_error_status(__le32 rndis_status)
++{
++	int ret = -EINVAL;
++	switch (rndis_status) {
++	case RNDIS_STATUS_SUCCESS:
++		ret = 0;
++		break;
++	case RNDIS_STATUS_FAILURE:
++	case RNDIS_STATUS_INVALID_DATA:
++		ret = -EINVAL;
++		break;
++	case RNDIS_STATUS_NOT_SUPPORTED:
++		ret = -EOPNOTSUPP;
++		break;
++	case RNDIS_STATUS_ADAPTER_NOT_READY:
++	case RNDIS_STATUS_ADAPTER_NOT_OPEN:
++		ret = -EBUSY;
++		break;
++	}
++	return ret;
++}
++
++
++static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++	union {
++		void			*buf;
++		struct rndis_msg_hdr	*header;
++		struct rndis_query	*get;
++		struct rndis_query_c	*get_c;
++	} u;
++	int ret, buflen;
++
++	buflen = *len + sizeof(*u.get);
++	if (buflen < CONTROL_BUFFER_SIZE)
++		buflen = CONTROL_BUFFER_SIZE;
++	u.buf = kmalloc(buflen, GFP_KERNEL);
++	if (!u.buf)
++		return -ENOMEM;
++	memset(u.get, 0, sizeof *u.get);
++	u.get->msg_type = RNDIS_MSG_QUERY;
++	u.get->msg_len = ccpu2(sizeof *u.get);
++	u.get->oid = oid;
++
++	mutex_lock(&priv->command_lock);
++	ret = rndis_command(dev, u.header);
++	mutex_unlock(&priv->command_lock);
++
++	if (ret == 0) {
++		ret = le32_to_cpu(u.get_c->len);
++		*len = (*len > ret) ? ret : *len;
++		memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
++		ret = rndis_error_status(u.get_c->status);
++	}
++
++	kfree(u.buf);
++	return ret;
++}
++
++
++static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++	union {
++		void			*buf;
++		struct rndis_msg_hdr	*header;
++		struct rndis_set	*set;
++		struct rndis_set_c	*set_c;
++	} u;
++	int ret, buflen;
++
++	buflen = len + sizeof(*u.set);
++	if (buflen < CONTROL_BUFFER_SIZE)
++		buflen = CONTROL_BUFFER_SIZE;
++	u.buf = kmalloc(buflen, GFP_KERNEL);
++	if (!u.buf)
++		return -ENOMEM;
++
++	memset(u.set, 0, sizeof *u.set);
++	u.set->msg_type = RNDIS_MSG_SET;
++	u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len);
++	u.set->oid = oid;
++	u.set->len = cpu_to_le32(len);
++	u.set->offset = ccpu2(sizeof(*u.set) - 8);
++	u.set->handle = ccpu2(0);
++	memcpy(u.buf + sizeof(*u.set), data, len);
++
++	mutex_lock(&priv->command_lock);
++	ret = rndis_command(dev, u.header);
++	mutex_unlock(&priv->command_lock);
++
++	if (ret == 0)
++		ret = rndis_error_status(u.set_c->status);
++
++	kfree(u.buf);
++	return ret;
++}
++
++
++/*
++ * Specs say that we can only set config parameters only soon after device
++ * initialization.
++ *   value_type: 0 = u32, 2 = unicode string
++ */
++static int rndis_set_config_parameter(struct usbnet *dev, char *param,
++						int value_type, void *value)
++{
++	struct RNDIS_CONFIG_PARAMETER_INFOBUFFER *infobuf;
++	int value_len, info_len, param_len, ret, i;
++	__le16 *unibuf;
++	__le32 *dst_value;
++
++	if (value_type == 0)
++		value_len = sizeof(__le32);
++	else if (value_type == 2)
++		value_len = strlen(value) * sizeof(__le16);
++	else
++		return -EINVAL;
++
++	param_len = strlen(param) * sizeof(__le16);
++	info_len = sizeof(*infobuf) + param_len + value_len;
++
++#ifdef DEBUG
++	info_len += 12;
++#endif
++	infobuf = kmalloc(info_len, GFP_KERNEL);
++	if (!infobuf)
++		return -ENOMEM;
++
++#ifdef DEBUG
++	info_len -= 12;
++	/* extra 12 bytes are for padding (debug output) */
++	memset(infobuf, 0xCC, info_len + 12);
++#endif
++
++	if (value_type == 2)
++		devdbg(dev, "setting config parameter: %s, value: %s",
++						param, (u8 *)value);
++	else
++		devdbg(dev, "setting config parameter: %s, value: %d",
++						param, *(u32 *)value);
++
++	infobuf->ParameterNameOffset = cpu_to_le32(sizeof(*infobuf));
++	infobuf->ParameterNameLength = cpu_to_le32(param_len);
++	infobuf->ParameterType = cpu_to_le32(value_type);
++	infobuf->ParameterValueOffset = cpu_to_le32(sizeof(*infobuf) +
++								param_len);
++	infobuf->ParameterValueLength = cpu_to_le32(value_len);
++
++	/* simple string to unicode string conversion */
++	unibuf = (void *)infobuf + sizeof(*infobuf);
++	for (i = 0; i < param_len / sizeof(__le16); i++)
++		unibuf[i] = cpu_to_le16(param[i]);
++
++	if (value_type == 2) {
++		unibuf = (void *)infobuf + sizeof(*infobuf) + param_len;
++		for (i = 0; i < value_len / sizeof(__le16); i++)
++			unibuf[i] = cpu_to_le16(((u8 *)value)[i]);
++	} else {
++		dst_value = (void *)infobuf + sizeof(*infobuf) + param_len;
++		*dst_value = cpu_to_le32(*(u32 *)value);
++	}
++
++#ifdef DEBUG
++	devdbg(dev, "info buffer (len: %d):", info_len);
++	for (i = 0; i < info_len; i += 12) {
++		u32 *tmp = (u32 *)((u8 *)infobuf + i);
++		devdbg(dev, "%08X:%08X:%08X",
++			cpu_to_be32(tmp[0]),
++			cpu_to_be32(tmp[1]),
++			cpu_to_be32(tmp[2]));
++	}
++#endif
++
++	ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER,
++							infobuf, info_len);
++	if (ret != 0)
++		devdbg(dev, "setting rndis config paramater failed, %d.", ret);
++
++	kfree(infobuf);
++	return ret;
++}
++
++static int rndis_set_config_parameter_str(struct usbnet *dev,
++						char *param, char *value)
++{
++	return(rndis_set_config_parameter(dev, param, 2, value));
++}
++
++/*static int rndis_set_config_parameter_u32(struct usbnet *dev,
++						char *param, u32 value)
++{
++	return(rndis_set_config_parameter(dev, param, 0, &value));
++}*/
++
++
++/*
++ * data conversion functions
++ */
++static int level_to_qual(int level)
++{
++	int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
++	return qual >= 0 ? (qual <= 100 ? qual : 100) : 0;
++}
++
++
++static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq)
++{
++	freq->e = 0;
++	freq->i = 0;
++	freq->flags = 0;
++
++	/* see comment in wireless.h above the "struct iw_freq"
++	 * definition for an explanation of this if
++	 * NOTE: 1000000 is due to the kHz
++	 */
++	if (dsconfig > 1000000) {
++		freq->m = dsconfig / 10;
++		freq->e = 1;
++	} else
++		freq->m = dsconfig;
++
++	/* convert from kHz to Hz */
++	freq->e += 3;
++}
++
++
++static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
++{
++	if (freq->m < 1000 && freq->e == 0) {
++		if (freq->m >= 1 &&
++			freq->m <= (sizeof(freq_chan) / sizeof(freq_chan[0])))
++			*dsconfig = freq_chan[freq->m - 1] * 1000;
++		else
++			return -1;
++	} else {
++		int i;
++		*dsconfig = freq->m;
++		for (i = freq->e; i > 0; i--)
++			*dsconfig *= 10;
++		*dsconfig /= 1000;
++	}
++
++	return 0;
++}
++
++
++/*
++ * common functions
++ */
++static int
++add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
++
++static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
++{
++	int ret, len;
++
++	len = sizeof(*ssid);
++	ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len);
++
++	if (ret != 0)
++		ssid->SsidLength = 0;
++
++#ifdef DEBUG
++	{
++		unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1];
++
++		memcpy(tmp, ssid->Ssid, le32_to_cpu(ssid->SsidLength));
++		tmp[le32_to_cpu(ssid->SsidLength)] = 0;
++		devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret);
++	}
++#endif
++	return ret;
++}
++
++
++static int set_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	int ret;
++
++	ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
++	if (ret == 0) {
++		memcpy(&priv->essid, ssid, sizeof(priv->essid));
++		priv->radio_on = 1;
++		devdbg(usbdev, "set_essid: radio_on = 1");
++	}
++
++	return ret;
++}
++
++
++static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
++{
++	int ret, len;
++
++	len = ETH_ALEN;
++	ret = rndis_query_oid(usbdev, OID_802_11_BSSID, bssid, &len);
++
++	if (ret != 0)
++		memset(bssid, 0, ETH_ALEN);
++
++	return ret;
++}
++
++
++static int is_associated(struct usbnet *usbdev)
++{
++	u8 bssid[ETH_ALEN];
++	int ret;
++
++	ret = get_bssid(usbdev, bssid);
++
++	return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0);
++}
++
++
++static int disassociate(struct usbnet *usbdev, int reset_ssid)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct NDIS_802_11_SSID ssid;
++	int i, ret = 0;
++
++	if (priv->radio_on) {
++		ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0);
++		if (ret == 0) {
++			priv->radio_on = 0;
++			devdbg(usbdev, "disassociate: radio_on = 0");
++
++			if (reset_ssid)
++				msleep(100);
++		}
++	}
++
++	/* disassociate causes radio to be turned off; if reset_ssid
++	 * is given, set random ssid to enable radio */
++	if (reset_ssid) {
++		ssid.SsidLength = cpu_to_le32(sizeof(ssid.Ssid));
++		get_random_bytes(&ssid.Ssid[2], sizeof(ssid.Ssid)-2);
++		ssid.Ssid[0] = 0x1;
++		ssid.Ssid[1] = 0xff;
++		for (i = 2; i < sizeof(ssid.Ssid); i++)
++			ssid.Ssid[i] = 0x1 + (ssid.Ssid[i] * 0xfe / 0xff);
++		ret = set_essid(usbdev, &ssid);
++	}
++	return ret;
++}
++
++
++static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tmp;
++	int auth_mode, ret;
++
++	devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x "
++		"keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt);
++
++	if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
++		if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
++			auth_mode = Ndis802_11AuthModeWPA2;
++		else
++			auth_mode = Ndis802_11AuthModeWPA2PSK;
++	} else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
++		if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
++			auth_mode = Ndis802_11AuthModeWPA;
++		else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK)
++			auth_mode = Ndis802_11AuthModeWPAPSK;
++		else
++			auth_mode = Ndis802_11AuthModeWPANone;
++	} else if (authalg & IW_AUTH_ALG_SHARED_KEY) {
++		if (authalg & IW_AUTH_ALG_OPEN_SYSTEM)
++			auth_mode = Ndis802_11AuthModeAutoSwitch;
++		else
++			auth_mode = Ndis802_11AuthModeShared;
++	} else
++		auth_mode = Ndis802_11AuthModeOpen;
++
++	tmp = cpu_to_le32(auth_mode);
++	ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
++								sizeof(tmp));
++	if (ret != 0) {
++		devwarn(usbdev, "setting auth mode failed (%08X)", ret);
++		return ret;
++	}
++
++	priv->wpa_version = wpa_version;
++	priv->wpa_authalg = authalg;
++	return 0;
++}
++
++
++static int set_priv_filter(struct usbnet *usbdev)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tmp;
++
++	devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version);
++
++	if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
++	    priv->wpa_version & IW_AUTH_WPA_VERSION_WPA)
++		tmp = cpu_to_le32(Ndis802_11PrivFilter8021xWEP);
++	else
++		tmp = cpu_to_le32(Ndis802_11PrivFilterAcceptAll);
++
++	return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp,
++								sizeof(tmp));
++}
++
++
++static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tmp;
++	int encr_mode, ret;
++
++	devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x",
++		pairwise,
++		groupwise);
++
++	if (pairwise & IW_AUTH_CIPHER_CCMP)
++		encr_mode = Ndis802_11Encryption3Enabled;
++	else if (pairwise & IW_AUTH_CIPHER_TKIP)
++		encr_mode = Ndis802_11Encryption2Enabled;
++	else if (pairwise &
++		 (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
++		encr_mode = Ndis802_11Encryption1Enabled;
++	else if (groupwise & IW_AUTH_CIPHER_CCMP)
++		encr_mode = Ndis802_11Encryption3Enabled;
++	else if (groupwise & IW_AUTH_CIPHER_TKIP)
++		encr_mode = Ndis802_11Encryption2Enabled;
++	else
++		encr_mode = Ndis802_11EncryptionDisabled;
++
++	tmp = cpu_to_le32(encr_mode);
++	ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
++								sizeof(tmp));
++	if (ret != 0) {
++		devwarn(usbdev, "setting encr mode failed (%08X)", ret);
++		return ret;
++	}
++
++	priv->wpa_cipher_pair = pairwise;
++	priv->wpa_cipher_group = groupwise;
++	return 0;
++}
++
++
++static int set_assoc_params(struct usbnet *usbdev)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg);
++	set_priv_filter(usbdev);
++	set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group);
++
++	return 0;
++}
++
++
++static int set_infra_mode(struct usbnet *usbdev, int mode)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tmp;
++	int ret, i;
++
++	devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
++
++	tmp = cpu_to_le32(mode);
++	ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp,
++								sizeof(tmp));
++	if (ret != 0) {
++		devwarn(usbdev, "setting infra mode failed (%08X)", ret);
++		return ret;
++	}
++
++	/* NDIS drivers clear keys when infrastructure mode is
++	 * changed. But Linux tools assume otherwise. So set the
++	 * keys */
++	if (priv->wpa_keymgmt == 0 ||
++		priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
++		for (i = 0; i < 4; i++) {
++			if (priv->encr_key_len[i] > 0)
++				add_wep_key(usbdev, priv->encr_keys[i],
++						priv->encr_key_len[i], i);
++		}
++	}
++
++	priv->infra_mode = mode;
++	return 0;
++}
++
++
++static void set_default_iw_params(struct usbnet *usbdev)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	priv->wpa_keymgmt = 0;
++	priv->wpa_version = 0;
++
++	set_infra_mode(usbdev, Ndis802_11Infrastructure);
++	set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
++				IW_AUTH_ALG_OPEN_SYSTEM);
++	set_priv_filter(usbdev);
++	set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
++}
++
++
++static int deauthenticate(struct usbnet *usbdev)
++{
++	int ret;
++
++	ret = disassociate(usbdev, 1);
++	set_default_iw_params(usbdev);
++	return ret;
++}
++
++
++/* index must be 0 - N, as per NDIS  */
++static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct NDIS_802_11_WEP ndis_key;
++	int ret;
++
++	if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
++		return -EINVAL;
++
++	memset(&ndis_key, 0, sizeof(ndis_key));
++
++	ndis_key.Length = cpu_to_le32(sizeof(ndis_key));
++	ndis_key.KeyLength = cpu_to_le32(key_len);
++	ndis_key.KeyIndex = cpu_to_le32(index);
++	memcpy(&ndis_key.KeyMaterial, key, key_len);
++
++	if (index == priv->encr_tx_key_index) {
++		ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
++		ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
++						IW_AUTH_CIPHER_NONE);
++		if (ret)
++			devwarn(usbdev, "encryption couldn't be enabled (%08X)",
++									ret);
++	}
++
++	ret = rndis_set_oid(usbdev, OID_802_11_ADD_WEP, &ndis_key,
++							sizeof(ndis_key));
++	if (ret != 0) {
++		devwarn(usbdev, "adding encryption key %d failed (%08X)",
++							index+1, ret);
++		return ret;
++	}
++
++	priv->encr_key_len[index] = key_len;
++	memcpy(&priv->encr_keys[index], key, key_len);
++
++	return 0;
++}
++
++
++/* remove_key is for both wep and wpa */
++static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct NDIS_802_11_REMOVE_KEY remove_key;
++	__le32 keyindex;
++	int ret;
++
++	if (priv->encr_key_len[index] == 0)
++		return 0;
++
++	priv->encr_key_len[index] = 0;
++	memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
++
++	if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
++	    priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
++	    priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
++	    priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
++		remove_key.Length = cpu_to_le32(sizeof(remove_key));
++		remove_key.KeyIndex = cpu_to_le32(index);
++		if (bssid) {
++			/* pairwise key */
++			if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
++				remove_key.KeyIndex |= cpu_to_le32(1 << 30);
++			memcpy(remove_key.Bssid, bssid,
++					sizeof(remove_key.Bssid));
++		} else
++			memset(remove_key.Bssid, 0xff,
++						sizeof(remove_key.Bssid));
++
++		ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_KEY, &remove_key,
++							sizeof(remove_key));
++		if (ret != 0)
++			return ret;
++	} else {
++		keyindex = cpu_to_le32(index);
++		ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_WEP, &keyindex,
++							sizeof(keyindex));
++		if (ret != 0) {
++			devwarn(usbdev,
++				"removing encryption key %d failed (%08X)",
++				index, ret);
++			return ret;
++		}
++	}
++
++	/* if it is transmit key, disable encryption */
++	if (index == priv->encr_tx_key_index)
++		set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
++
++	return 0;
++}
++
++
++static void set_multicast_list(struct usbnet *usbdev)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct dev_mc_list *mclist;
++	__le32 filter;
++	int ret, i, size;
++	char *buf;
++
++	filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
++
++	if (usbdev->net->flags & IFF_PROMISC) {
++		filter |= RNDIS_PACKET_TYPE_PROMISCUOUS |
++			RNDIS_PACKET_TYPE_ALL_LOCAL;
++	} else if (usbdev->net->flags & IFF_ALLMULTI ||
++		   usbdev->net->mc_count > priv->multicast_size) {
++		filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
++	} else if (usbdev->net->mc_count > 0) {
++		size = min(priv->multicast_size, usbdev->net->mc_count);
++		buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
++		if (!buf) {
++			devwarn(usbdev,
++				"couldn't alloc %d bytes of memory",
++				size * ETH_ALEN);
++			return;
++		}
++
++		mclist = usbdev->net->mc_list;
++		for (i = 0; i < size && mclist; mclist = mclist->next) {
++			if (mclist->dmi_addrlen != ETH_ALEN)
++				continue;
++
++			memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
++			i++;
++		}
++
++		ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf,
++								i * ETH_ALEN);
++		if (ret == 0 && i > 0)
++			filter |= RNDIS_PACKET_TYPE_MULTICAST;
++		else
++			filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
++
++		devdbg(usbdev, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d",
++						i, priv->multicast_size, ret);
++
++		kfree(buf);
++	}
++
++	ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
++							sizeof(filter));
++	if (ret < 0) {
++		devwarn(usbdev, "couldn't set packet filter: %08x",
++							le32_to_cpu(filter));
++	}
++
++	devdbg(usbdev, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d",
++						le32_to_cpu(filter), ret);
++}
++
++
++/*
++ * wireless extension handlers
++ */
++
++static int rndis_iw_commit(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	/* dummy op */
++	return 0;
++}
++
++
++static int rndis_iw_get_range(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct iw_range *range = (struct iw_range *)extra;
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	int len, ret, i, j, num, has_80211g_rates;
++	u8 rates[8];
++	__le32 tx_power;
++
++	devdbg(usbdev, "SIOCGIWRANGE");
++
++	/* clear iw_range struct */
++	memset(range, 0, sizeof(*range));
++	wrqu->data.length = sizeof(*range);
++
++	range->txpower_capa = IW_TXPOW_MWATT;
++	range->num_txpower = 1;
++	if (priv->caps & CAP_SUPPORT_TXPOWER) {
++		len = sizeof(tx_power);
++		ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
++						&tx_power, &len);
++		if (ret == 0 && le32_to_cpu(tx_power) != 0xFF)
++			range->txpower[0] = le32_to_cpu(tx_power);
++		else
++			range->txpower[0] = get_bcm4320_power(priv);
++	} else
++		range->txpower[0] = get_bcm4320_power(priv);
++
++	len = sizeof(rates);
++	ret = rndis_query_oid(usbdev, OID_802_11_SUPPORTED_RATES, &rates,
++								&len);
++	has_80211g_rates = 0;
++	if (ret == 0) {
++		j = 0;
++		for (i = 0; i < len; i++) {
++			if (rates[i] == 0)
++				break;
++			range->bitrate[j] = (rates[i] & 0x7f) * 500000;
++			/* check for non 802.11b rates */
++			if (range->bitrate[j] == 6000000 ||
++				range->bitrate[j] == 9000000 ||
++				(range->bitrate[j] >= 12000000 &&
++				range->bitrate[j] != 22000000))
++				has_80211g_rates = 1;
++			j++;
++		}
++		range->num_bitrates = j;
++	} else
++		range->num_bitrates = 0;
++
++	/* fill in 802.11g rates */
++	if (has_80211g_rates) {
++		num = range->num_bitrates;
++		for (i = 0; i < sizeof(rates_80211g); i++) {
++			for (j = 0; j < num; j++) {
++				if (range->bitrate[j] ==
++					rates_80211g[i] * 1000000)
++					break;
++			}
++			if (j == num)
++				range->bitrate[range->num_bitrates++] =
++					rates_80211g[i] * 1000000;
++			if (range->num_bitrates == IW_MAX_BITRATES)
++				break;
++		}
++
++		/* estimated max real througput in bps */
++		range->throughput = 54 * 1000 * 1000 / 2;
++
++		/* ~35%	more with afterburner */
++		if (priv->param_afterburner)
++			range->throughput = range->throughput / 100 * 135;
++	} else {
++		/* estimated max real througput in bps */
++		range->throughput = 11 * 1000 * 1000 / 2;
++	}
++
++	range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0]));
++
++	for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) &&
++			i < IW_MAX_FREQUENCIES; i++) {
++		range->freq[i].i = i + 1;
++		range->freq[i].m = freq_chan[i] * 100000;
++		range->freq[i].e = 1;
++	}
++	range->num_frequency = i;
++
++	range->min_rts = 0;
++	range->max_rts = 2347;
++	range->min_frag = 256;
++	range->max_frag = 2346;
++
++	range->max_qual.qual = 100;
++	range->max_qual.level = 154;
++	range->max_qual.updated = IW_QUAL_QUAL_UPDATED
++				| IW_QUAL_LEVEL_UPDATED
++				| IW_QUAL_NOISE_INVALID;
++
++	range->we_version_compiled = WIRELESS_EXT;
++	range->we_version_source = WIRELESS_EXT;
++
++	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
++			IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
++	return 0;
++}
++
++
++static int rndis_iw_get_name(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	strcpy(wrqu->name, priv->name);
++	return 0;
++}
++
++
++static int rndis_iw_set_essid(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
++{
++	struct NDIS_802_11_SSID ssid;
++	int length = wrqu->essid.length;
++	struct usbnet *usbdev = dev->priv;
++
++	devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'",
++		wrqu->essid.flags, wrqu->essid.length, essid);
++
++	if (length > NDIS_802_11_LENGTH_SSID)
++		length = NDIS_802_11_LENGTH_SSID;
++
++	ssid.SsidLength = cpu_to_le32(length);
++	if (length > 0)
++		memcpy(ssid.Ssid, essid, length);
++	else
++		memset(ssid.Ssid, 0, NDIS_802_11_LENGTH_SSID);
++
++	set_assoc_params(usbdev);
++
++	if (!wrqu->essid.flags || length == 0)
++		return disassociate(usbdev, 1);
++	else
++		return set_essid(usbdev, &ssid);
++}
++
++
++static int rndis_iw_get_essid(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
++{
++	struct NDIS_802_11_SSID ssid;
++	struct usbnet *usbdev = dev->priv;
++	int ret;
++
++	ret = get_essid(usbdev, &ssid);
++
++	if (ret == 0 && le32_to_cpu(ssid.SsidLength) > 0) {
++		wrqu->essid.flags = 1;
++		wrqu->essid.length = le32_to_cpu(ssid.SsidLength);
++		memcpy(essid, ssid.Ssid, wrqu->essid.length);
++		essid[wrqu->essid.length] = 0;
++	} else {
++		memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID));
++		wrqu->essid.flags = 0;
++		wrqu->essid.length = 0;
++	}
++	devdbg(usbdev, "SIOCGIWESSID: %s", essid);
++	return ret;
++}
++
++
++static int rndis_iw_get_bssid(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	unsigned char bssid[ETH_ALEN];
++	int ret;
++	DECLARE_MAC_BUF(mac);
++
++	ret = get_bssid(usbdev, bssid);
++
++	if (ret == 0)
++		devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid));
++	else
++		devdbg(usbdev, "SIOCGIWAP: <not associated>");
++
++	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
++	memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN);
++
++	return ret;
++}
++
++
++static int rndis_iw_set_bssid(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	u8 *bssid = (u8 *)wrqu->ap_addr.sa_data;
++	DECLARE_MAC_BUF(mac);
++	int ret;
++
++	devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid));
++
++	ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
++
++	/* user apps may set ap's mac address, which is not required;
++	 * they may fail to work if this function fails, so return
++	 * success */
++	if (ret)
++		devwarn(usbdev, "setting AP mac address failed (%08X)", ret);
++
++	return 0;
++}
++
++
++static int rndis_iw_set_auth(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct iw_param *p = &wrqu->param;
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	int ret = -ENOTSUPP;
++
++	switch (p->flags & IW_AUTH_INDEX) {
++	case IW_AUTH_WPA_VERSION:
++		devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value);
++		priv->wpa_version = p->value;
++		ret = 0;
++		break;
++
++	case IW_AUTH_CIPHER_PAIRWISE:
++		devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value);
++		priv->wpa_cipher_pair = p->value;
++		ret = 0;
++		break;
++
++	case IW_AUTH_CIPHER_GROUP:
++		devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value);
++		priv->wpa_cipher_group = p->value;
++		ret = 0;
++		break;
++
++	case IW_AUTH_KEY_MGMT:
++		devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value);
++		priv->wpa_keymgmt = p->value;
++		ret = 0;
++		break;
++
++	case IW_AUTH_TKIP_COUNTERMEASURES:
++		devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x",
++								p->value);
++		ret = 0;
++		break;
++
++	case IW_AUTH_DROP_UNENCRYPTED:
++		devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value);
++		ret = 0;
++		break;
++
++	case IW_AUTH_80211_AUTH_ALG:
++		devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value);
++		priv->wpa_authalg = p->value;
++		ret = 0;
++		break;
++
++	case IW_AUTH_WPA_ENABLED:
++		devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value);
++		if (wrqu->param.value)
++			deauthenticate(usbdev);
++		ret = 0;
++		break;
++
++	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
++		devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x",
++								p->value);
++		ret = 0;
++		break;
++
++	case IW_AUTH_ROAMING_CONTROL:
++		devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value);
++		ret = 0;
++		break;
++
++	case IW_AUTH_PRIVACY_INVOKED:
++		devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d",
++				wrqu->param.flags & IW_AUTH_INDEX);
++		return -EOPNOTSUPP;
++
++	default:
++		devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN  %08x, %08x",
++			p->flags & IW_AUTH_INDEX, p->value);
++	}
++	return ret;
++}
++
++
++static int rndis_iw_get_auth(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct iw_param *p = &wrqu->param;
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	switch (p->flags & IW_AUTH_INDEX) {
++	case IW_AUTH_WPA_VERSION:
++		p->value = priv->wpa_version;
++		break;
++	case IW_AUTH_CIPHER_PAIRWISE:
++		p->value = priv->wpa_cipher_pair;
++		break;
++	case IW_AUTH_CIPHER_GROUP:
++		p->value = priv->wpa_cipher_group;
++		break;
++	case IW_AUTH_KEY_MGMT:
++		p->value = priv->wpa_keymgmt;
++		break;
++	case IW_AUTH_80211_AUTH_ALG:
++		p->value = priv->wpa_authalg;
++		break;
++	default:
++		devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d",
++				wrqu->param.flags & IW_AUTH_INDEX);
++		return -EOPNOTSUPP;
++	}
++	return 0;
++}
++
++
++static int rndis_iw_get_mode(struct net_device *dev,
++				struct iw_request_info *info,
++				union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	switch (priv->infra_mode) {
++	case Ndis802_11IBSS:
++		wrqu->mode = IW_MODE_ADHOC;
++		break;
++	case Ndis802_11Infrastructure:
++		wrqu->mode = IW_MODE_INFRA;
++		break;
++	/*case Ndis802_11AutoUnknown:*/
++	default:
++		wrqu->mode = IW_MODE_AUTO;
++		break;
++	}
++	devdbg(usbdev, "SIOCGIWMODE: %08x", wrqu->mode);
++	return 0;
++}
++
++
++static int rndis_iw_set_mode(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	int mode;
++
++	devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode);
++
++	switch (wrqu->mode) {
++	case IW_MODE_ADHOC:
++		mode = Ndis802_11IBSS;
++		break;
++	case IW_MODE_INFRA:
++		mode = Ndis802_11Infrastructure;
++		break;
++	/*case IW_MODE_AUTO:*/
++	default:
++		mode = Ndis802_11AutoUnknown;
++		break;
++	}
++
++	return set_infra_mode(usbdev, mode);
++}
++
++
++static int rndis_iw_set_encode(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	int ret, index, key_len;
++	u8 *key;
++
++	index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
++
++	/* iwconfig gives index as 1 - N */
++	if (index > 0)
++		index--;
++	else
++		index = priv->encr_tx_key_index;
++
++	if (index < 0 || index >= 4) {
++		devwarn(usbdev, "encryption index out of range (%u)", index);
++		return -EINVAL;
++	}
++
++	/* remove key if disabled */
++	if (wrqu->data.flags & IW_ENCODE_DISABLED) {
++		if (remove_key(usbdev, index, NULL))
++			return -EINVAL;
++		else
++			return 0;
++	}
++
++	/* global encryption state (for all keys) */
++	if (wrqu->data.flags & IW_ENCODE_OPEN)
++		ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
++						IW_AUTH_ALG_OPEN_SYSTEM);
++	else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/
++		ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
++						IW_AUTH_ALG_SHARED_KEY);
++	if (ret != 0)
++		return ret;
++
++	if (wrqu->data.length > 0) {
++		key_len = wrqu->data.length;
++		key = extra;
++	} else {
++		/* must be set as tx key */
++		if (priv->encr_key_len[index] == 0)
++			return -EINVAL;
++		key_len = priv->encr_key_len[index];
++		key = priv->encr_keys[index];
++		priv->encr_tx_key_index = index;
++	}
++
++	if (add_wep_key(usbdev, key, key_len, index) != 0)
++		return -EINVAL;
++
++	if (index == priv->encr_tx_key_index)
++		/* ndis drivers want essid to be set after setting encr */
++		set_essid(usbdev, &priv->essid);
++
++	return 0;
++}
++
++
++static int rndis_iw_set_encode_ext(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct NDIS_802_11_KEY ndis_key;
++	int i, keyidx, ret;
++	u8 *addr;
++
++	keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
++
++	/* iwconfig gives index as 1 - N */
++	if (keyidx)
++		keyidx--;
++	else
++		keyidx = priv->encr_tx_key_index;
++
++	if (keyidx < 0 || keyidx >= 4)
++		return -EINVAL;
++
++	if (ext->alg == WPA_ALG_WEP) {
++		if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
++			priv->encr_tx_key_index = keyidx;
++		return add_wep_key(usbdev, ext->key, ext->key_len, keyidx);
++	}
++
++	if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
++	    ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
++		return remove_key(usbdev, keyidx, NULL);
++
++	if (ext->key_len > sizeof(ndis_key.KeyMaterial))
++		return -1;
++
++	memset(&ndis_key, 0, sizeof(ndis_key));
++
++	ndis_key.Length = cpu_to_le32(sizeof(ndis_key) -
++				sizeof(ndis_key.KeyMaterial) + ext->key_len);
++	ndis_key.KeyLength = cpu_to_le32(ext->key_len);
++	ndis_key.KeyIndex = cpu_to_le32(keyidx);
++
++	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
++		for (i = 0; i < 6; i++)
++			ndis_key.KeyRSC |=
++				cpu_to_le64(ext->rx_seq[i] << (i * 8));
++		ndis_key.KeyIndex |= cpu_to_le32(1 << 29);
++	}
++
++	addr = ext->addr.sa_data;
++	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
++		/* group key */
++		if (priv->infra_mode == Ndis802_11IBSS)
++			memset(ndis_key.Bssid, 0xff, ETH_ALEN);
++		else
++			get_bssid(usbdev, ndis_key.Bssid);
++	} else {
++		/* pairwise key */
++		ndis_key.KeyIndex |= cpu_to_le32(1 << 30);
++		memcpy(ndis_key.Bssid, addr, ETH_ALEN);
++	}
++
++	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
++		ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
++
++	if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
++		/* wpa_supplicant gives us the Michael MIC RX/TX keys in
++		 * different order than NDIS spec, so swap the order here. */
++		memcpy(ndis_key.KeyMaterial, ext->key, 16);
++		memcpy(ndis_key.KeyMaterial + 16, ext->key + 24, 8);
++		memcpy(ndis_key.KeyMaterial + 24, ext->key + 16, 8);
++	} else
++		memcpy(ndis_key.KeyMaterial, ext->key, ext->key_len);
++
++	ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
++					le32_to_cpu(ndis_key.Length));
++	devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret);
++	if (ret != 0)
++		return ret;
++
++	priv->encr_key_len[keyidx] = ext->key_len;
++	memcpy(&priv->encr_keys[keyidx], ndis_key.KeyMaterial, ext->key_len);
++	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
++		priv->encr_tx_key_index = keyidx;
++
++	return 0;
++}
++
++
++static int rndis_iw_set_scan(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct iw_param *param = &wrqu->param;
++	struct usbnet *usbdev = dev->priv;
++	union iwreq_data evt;
++	int ret = -EINVAL;
++	__le32 tmp;
++
++	devdbg(usbdev, "SIOCSIWSCAN");
++
++	if (param->flags == 0) {
++		tmp = ccpu2(1);
++		ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
++								sizeof(tmp));
++		evt.data.flags = 0;
++		evt.data.length = 0;
++		wireless_send_event(dev, SIOCGIWSCAN, &evt, NULL);
++	}
++	return ret;
++}
++
++
++static char *rndis_translate_scan(struct net_device *dev,
++    char *cev, char *end_buf, struct NDIS_WLAN_BSSID_EX *bssid)
++{
++#ifdef DEBUG
++	struct usbnet *usbdev = dev->priv;
++#endif
++	struct ieee80211_info_element *ie;
++	char *current_val;
++	int bssid_len, ie_len, i;
++	u32 beacon, atim;
++	struct iw_event iwe;
++	unsigned char sbuf[32];
++	DECLARE_MAC_BUF(mac);
++
++	bssid_len = le32_to_cpu(bssid->Length);
++
++	devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->MacAddress));
++	iwe.cmd = SIOCGIWAP;
++	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
++	memcpy(iwe.u.ap_addr.sa_data, bssid->MacAddress, ETH_ALEN);
++	cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
++
++	devdbg(usbdev, "SSID(%d) %s",
++		le32_to_cpu(bssid->Ssid.SsidLength),
++		bssid->Ssid.Ssid);
++	iwe.cmd = SIOCGIWESSID;
++	iwe.u.essid.length = le32_to_cpu(bssid->Ssid.SsidLength);
++	iwe.u.essid.flags = 1;
++	cev = iwe_stream_add_point(cev, end_buf, &iwe,
++						bssid->Ssid.Ssid);
++
++	devdbg(usbdev, "MODE %d",
++			le32_to_cpu(bssid->InfrastructureMode));
++	iwe.cmd = SIOCGIWMODE;
++	switch (le32_to_cpu(bssid->InfrastructureMode)) {
++	case Ndis802_11IBSS:
++		iwe.u.mode = IW_MODE_ADHOC;
++		break;
++	case Ndis802_11Infrastructure:
++		iwe.u.mode = IW_MODE_INFRA;
++		break;
++	/*case Ndis802_11AutoUnknown:*/
++	default:
++		iwe.u.mode = IW_MODE_AUTO;
++		break;
++	}
++	cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
++
++	devdbg(usbdev, "FREQ %d kHz",
++		le32_to_cpu(bssid->Configuration.DSConfig));
++	iwe.cmd = SIOCGIWFREQ;
++	dsconfig_to_freq(le32_to_cpu(bssid->Configuration.DSConfig),
++								&iwe.u.freq);
++	cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
++
++	devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->Rssi));
++	iwe.cmd = IWEVQUAL;
++	iwe.u.qual.qual  = level_to_qual(le32_to_cpu(bssid->Rssi));
++	iwe.u.qual.level = le32_to_cpu(bssid->Rssi);
++	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
++			| IW_QUAL_LEVEL_UPDATED
++			| IW_QUAL_NOISE_INVALID;
++	cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
++
++	devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->Privacy));
++	iwe.cmd = SIOCGIWENCODE;
++	iwe.u.data.length = 0;
++	if (le32_to_cpu(bssid->Privacy) == Ndis802_11PrivFilterAcceptAll)
++		iwe.u.data.flags = IW_ENCODE_DISABLED;
++	else
++		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
++
++	cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
++
++	devdbg(usbdev, "RATES:");
++	current_val = cev + IW_EV_LCP_LEN;
++	iwe.cmd = SIOCGIWRATE;
++	for (i = 0; i < sizeof(bssid->SupportedRates); i++) {
++		if (bssid->SupportedRates[i] & 0x7f) {
++			iwe.u.bitrate.value =
++				((bssid->SupportedRates[i] & 0x7f) *
++				500000);
++			devdbg(usbdev, " %d", iwe.u.bitrate.value);
++			current_val = iwe_stream_add_value(cev,
++				current_val, end_buf, &iwe,
++				IW_EV_PARAM_LEN);
++		}
++	}
++
++	if ((current_val - cev) > IW_EV_LCP_LEN)
++		cev = current_val;
++
++	beacon = le32_to_cpu(bssid->Configuration.BeaconPeriod);
++	devdbg(usbdev, "BCN_INT %d", beacon);
++	iwe.cmd = IWEVCUSTOM;
++	snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
++	iwe.u.data.length = strlen(sbuf);
++	cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
++
++	atim = le32_to_cpu(bssid->Configuration.ATIMWindow);
++	devdbg(usbdev, "ATIM %d", atim);
++	iwe.cmd = IWEVCUSTOM;
++	snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
++	iwe.u.data.length = strlen(sbuf);
++	cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
++
++	ie = (void *)(bssid->IEs + sizeof(struct NDIS_802_11_FIXED_IEs));
++	ie_len = min(bssid_len - (int)sizeof(*bssid),
++					(int)le32_to_cpu(bssid->IELength));
++	ie_len -= sizeof(struct NDIS_802_11_FIXED_IEs);
++	while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
++		if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
++				memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
++				ie->id == MFIE_TYPE_RSN) {
++			devdbg(usbdev, "IE: WPA%d",
++					(ie->id == MFIE_TYPE_RSN) ? 2 : 1);
++			iwe.cmd = IWEVGENIE;
++			iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
++			cev = iwe_stream_add_point(cev, end_buf, &iwe,
++								(u8 *)ie);
++		}
++
++		ie_len -= sizeof(*ie) + ie->len;
++		ie = (struct ieee80211_info_element *)&ie->data[ie->len];
++	}
++
++	return cev;
++}
++
++
++static int rndis_iw_get_scan(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	void *buf = NULL;
++	char *cev = extra;
++	struct NDIS_802_11_BSSID_LIST_EX *bssid_list;
++	struct NDIS_WLAN_BSSID_EX *bssid;
++	int ret = -EINVAL, len, count, bssid_len;
++
++	devdbg(usbdev, "SIOCGIWSCAN");
++
++	len = CONTROL_BUFFER_SIZE;
++	buf = kmalloc(len, GFP_KERNEL);
++	if (!buf) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
++
++	if (ret != 0)
++		goto out;
++
++	bssid_list = buf;
++	bssid = bssid_list->Bssid;
++	bssid_len = le32_to_cpu(bssid->Length);
++	count = le32_to_cpu(bssid_list->NumberOfItems);
++	devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
++
++	while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
++		cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA,
++									bssid);
++		bssid = (void *)bssid + bssid_len;
++		bssid_len = le32_to_cpu(bssid->Length);
++		count--;
++	}
++
++out:
++	wrqu->data.length = cev - extra;
++	wrqu->data.flags = 0;
++	kfree(buf);
++	return ret;
++}
++
++
++static int rndis_iw_set_genie(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	int ret = 0;
++
++#ifdef DEBUG
++	int j;
++	u8 *gie = extra;
++	for (j = 0; j < wrqu->data.length; j += 8)
++		devdbg(usbdev,
++			"SIOCSIWGENIE %04x - "
++			"%02x %02x %02x %02x %02x %02x %02x %02x", j,
++			gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3],
++			gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]);
++#endif
++	/* clear existing IEs */
++	if (priv->wpa_ie_len) {
++		kfree(priv->wpa_ie);
++		priv->wpa_ie_len = 0;
++	}
++
++	/* set new IEs */
++	priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL);
++	if (priv->wpa_ie) {
++		priv->wpa_ie_len = wrqu->data.length;
++		memcpy(priv->wpa_ie, extra, priv->wpa_ie_len);
++	} else
++		ret = -ENOMEM;
++	return ret;
++}
++
++
++static int rndis_iw_get_genie(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	devdbg(usbdev, "SIOCGIWGENIE");
++
++	if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) {
++		wrqu->data.length = 0;
++		return 0;
++	}
++
++	if (wrqu->data.length < priv->wpa_ie_len)
++		return -E2BIG;
++
++	wrqu->data.length = priv->wpa_ie_len;
++	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
++
++	return 0;
++}
++
++
++static int rndis_iw_set_rts(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	__le32 tmp;
++	devdbg(usbdev, "SIOCSIWRTS");
++
++	tmp = cpu_to_le32(wrqu->rts.value);
++	return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
++								sizeof(tmp));
++}
++
++
++static int rndis_iw_get_rts(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	__le32 tmp;
++	int len, ret;
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
++	if (ret == 0) {
++		wrqu->rts.value = le32_to_cpu(tmp);
++		wrqu->rts.flags = 1;
++		wrqu->rts.disabled = 0;
++	}
++
++	devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
++
++	return ret;
++}
++
++
++static int rndis_iw_set_frag(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	__le32 tmp;
++
++	devdbg(usbdev, "SIOCSIWFRAG");
++
++	tmp = cpu_to_le32(wrqu->frag.value);
++	return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
++								sizeof(tmp));
++}
++
++
++static int rndis_iw_get_frag(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	__le32 tmp;
++	int len, ret;
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
++									&len);
++	if (ret == 0) {
++		wrqu->frag.value = le32_to_cpu(tmp);
++		wrqu->frag.flags = 1;
++		wrqu->frag.disabled = 0;
++	}
++	devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
++	return ret;
++}
++
++
++static int rndis_iw_set_nick(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	devdbg(usbdev, "SIOCSIWNICK");
++
++	priv->nick_len = wrqu->data.length;
++	if (priv->nick_len > 32)
++		priv->nick_len = 32;
++
++	memcpy(priv->nick, extra, priv->nick_len);
++	return 0;
++}
++
++
++static int rndis_iw_get_nick(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	wrqu->data.flags = 1;
++	wrqu->data.length = priv->nick_len;
++	memcpy(extra, priv->nick, priv->nick_len);
++
++	devdbg(usbdev, "SIOCGIWNICK: '%s'", priv->nick);
++
++	return 0;
++}
++
++
++static int rndis_iw_set_freq(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct NDIS_802_11_CONFIGURATION config;
++	unsigned int dsconfig;
++	int len, ret;
++
++	/* this OID is valid only when not associated */
++	if (is_associated(usbdev))
++		return 0;
++
++	dsconfig = 0;
++	if (freq_to_dsconfig(&wrqu->freq, &dsconfig))
++		return -EINVAL;
++
++	len = sizeof(config);
++	ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
++	if (ret != 0) {
++		devdbg(usbdev, "SIOCSIWFREQ: querying configuration failed");
++		return 0;
++	}
++
++	config.DSConfig = cpu_to_le32(dsconfig);
++
++	devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e);
++	return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
++								sizeof(config));
++}
++
++
++static int rndis_iw_get_freq(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct NDIS_802_11_CONFIGURATION config;
++	int len, ret;
++
++	len = sizeof(config);
++	ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
++	if (ret == 0)
++		dsconfig_to_freq(le32_to_cpu(config.DSConfig), &wrqu->freq);
++
++	devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m);
++	return ret;
++}
++
++
++static int rndis_iw_get_txpower(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tx_power;
++	int ret = 0, len;
++
++	if (priv->radio_on) {
++		if (priv->caps & CAP_SUPPORT_TXPOWER) {
++			len = sizeof(tx_power);
++			ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
++							&tx_power, &len);
++			if (ret != 0)
++				return ret;
++		} else
++			/* fake incase not supported */
++			tx_power = cpu_to_le32(get_bcm4320_power(priv));
++
++		wrqu->txpower.flags = IW_TXPOW_MWATT;
++		wrqu->txpower.value = le32_to_cpu(tx_power);
++		wrqu->txpower.disabled = 0;
++	} else {
++		wrqu->txpower.flags = IW_TXPOW_MWATT;
++		wrqu->txpower.value = 0;
++		wrqu->txpower.disabled = 1;
++	}
++
++	devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
++
++	return ret;
++}
++
++
++static int rndis_iw_set_txpower(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	__le32 tx_power = 0;
++	int ret = 0;
++
++	if (!wrqu->txpower.disabled) {
++		if (wrqu->txpower.flags == IW_TXPOW_MWATT)
++			tx_power = cpu_to_le32(wrqu->txpower.value);
++		else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
++			if (wrqu->txpower.value > 20)
++				tx_power = cpu_to_le32(128);
++			else if (wrqu->txpower.value < -43)
++				tx_power = cpu_to_le32(127);
++			else {
++				signed char tmp;
++				tmp = wrqu->txpower.value;
++				tmp = -12 - tmp;
++				tmp <<= 2;
++				tx_power = cpu_to_le32((unsigned char)tmp);
++			}
++		}
++	}
++
++	devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
++
++	if (le32_to_cpu(tx_power) != 0) {
++		if (priv->caps & CAP_SUPPORT_TXPOWER) {
++			/* turn radio on first */
++			if (!priv->radio_on)
++				disassociate(usbdev, 1);
++
++			ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
++						&tx_power, sizeof(tx_power));
++			if (ret != 0)
++				ret = -EOPNOTSUPP;
++			return ret;
++		} else {
++			/* txpower unsupported, just turn radio on */
++			if (!priv->radio_on)
++				return disassociate(usbdev, 1);
++			return 0; /* all ready on */
++		}
++	}
++
++	/* tx_power == 0, turn off radio */
++	return disassociate(usbdev, 0);
++}
++
++
++static int rndis_iw_get_rate(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	__le32 tmp;
++	int ret, len;
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
++	if (ret == 0) {
++		wrqu->bitrate.value = le32_to_cpu(tmp) * 100;
++		wrqu->bitrate.disabled = 0;
++		wrqu->bitrate.flags = 1;
++	}
++	return ret;
++}
++
++
++static int rndis_iw_set_mlme(struct net_device *dev,
++    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	struct iw_mlme *mlme = (struct iw_mlme *)extra;
++	unsigned char bssid[ETH_ALEN];
++
++	get_bssid(usbdev, bssid);
++
++	if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN))
++		return -EINVAL;
++
++	switch (mlme->cmd) {
++	case IW_MLME_DEAUTH:
++		return deauthenticate(usbdev);
++	case IW_MLME_DISASSOC:
++		return disassociate(usbdev, priv->radio_on);
++	default:
++		return -EOPNOTSUPP;
++	}
++
++	return 0;
++}
++
++
++static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++	unsigned long flags;
++
++	spin_lock_irqsave(&priv->stats_lock, flags);
++	memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats));
++	spin_unlock_irqrestore(&priv->stats_lock, flags);
++
++	return &priv->iwstats;
++}
++
++
++#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT]
++static const iw_handler rndis_iw_handler[] =
++{
++	IW_IOCTL(SIOCSIWCOMMIT)    = rndis_iw_commit,
++	IW_IOCTL(SIOCGIWNAME)      = rndis_iw_get_name,
++	IW_IOCTL(SIOCSIWFREQ)      = rndis_iw_set_freq,
++	IW_IOCTL(SIOCGIWFREQ)      = rndis_iw_get_freq,
++	IW_IOCTL(SIOCSIWMODE)      = rndis_iw_set_mode,
++	IW_IOCTL(SIOCGIWMODE)      = rndis_iw_get_mode,
++	IW_IOCTL(SIOCGIWRANGE)     = rndis_iw_get_range,
++	IW_IOCTL(SIOCSIWAP)        = rndis_iw_set_bssid,
++	IW_IOCTL(SIOCGIWAP)        = rndis_iw_get_bssid,
++	IW_IOCTL(SIOCSIWSCAN)      = rndis_iw_set_scan,
++	IW_IOCTL(SIOCGIWSCAN)      = rndis_iw_get_scan,
++	IW_IOCTL(SIOCSIWESSID)     = rndis_iw_set_essid,
++	IW_IOCTL(SIOCGIWESSID)     = rndis_iw_get_essid,
++	IW_IOCTL(SIOCSIWNICKN)     = rndis_iw_set_nick,
++	IW_IOCTL(SIOCGIWNICKN)     = rndis_iw_get_nick,
++	IW_IOCTL(SIOCGIWRATE)      = rndis_iw_get_rate,
++	IW_IOCTL(SIOCSIWRTS)       = rndis_iw_set_rts,
++	IW_IOCTL(SIOCGIWRTS)       = rndis_iw_get_rts,
++	IW_IOCTL(SIOCSIWFRAG)      = rndis_iw_set_frag,
++	IW_IOCTL(SIOCGIWFRAG)      = rndis_iw_get_frag,
++	IW_IOCTL(SIOCSIWTXPOW)     = rndis_iw_set_txpower,
++	IW_IOCTL(SIOCGIWTXPOW)     = rndis_iw_get_txpower,
++	IW_IOCTL(SIOCSIWENCODE)    = rndis_iw_set_encode,
++	IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
++	IW_IOCTL(SIOCSIWAUTH)      = rndis_iw_set_auth,
++	IW_IOCTL(SIOCGIWAUTH)      = rndis_iw_get_auth,
++	IW_IOCTL(SIOCSIWGENIE)     = rndis_iw_set_genie,
++	IW_IOCTL(SIOCGIWGENIE)     = rndis_iw_get_genie,
++	IW_IOCTL(SIOCSIWMLME)      = rndis_iw_set_mlme,
++};
++
++static const iw_handler rndis_wext_private_handler[] = {
++};
++
++static const struct iw_priv_args rndis_wext_private_args[] = {
++};
++
++
++static const struct iw_handler_def rndis_iw_handlers = {
++	.num_standard = ARRAY_SIZE(rndis_iw_handler),
++	.num_private  = ARRAY_SIZE(rndis_wext_private_handler),
++	.num_private_args = ARRAY_SIZE(rndis_wext_private_args),
++	.standard = (iw_handler *)rndis_iw_handler,
++	.private  = (iw_handler *)rndis_wext_private_handler,
++	.private_args = (struct iw_priv_args *)rndis_wext_private_args,
++	.get_wireless_stats = rndis_get_wireless_stats,
++};
++
++
++static void rndis_wext_worker(struct work_struct *work)
++{
++	struct rndis_wext_private *priv =
++		container_of(work, struct rndis_wext_private, work);
++	struct usbnet *usbdev = priv->usbdev;
++	union iwreq_data evt;
++	unsigned char bssid[ETH_ALEN];
++	int ret;
++
++	if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) {
++		ret = get_bssid(usbdev, bssid);
++
++		if (!ret) {
++			evt.data.flags = 0;
++			evt.data.length = 0;
++			memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
++			wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
++		}
++	}
++
++	if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
++		set_multicast_list(usbdev);
++}
++
++static void rndis_wext_set_multicast_list(struct net_device *dev)
++{
++	struct usbnet *usbdev = dev->priv;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
++
++	set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
++	queue_work(priv->workqueue, &priv->work);
++}
++
++static void rndis_wext_link_change(struct usbnet *dev, int state)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++	union iwreq_data evt;
++
++	if (state) {
++		/* queue work to avoid recursive calls into rndis_command */
++		set_bit(WORK_CONNECTION_EVENT, &priv->work_pending);
++		queue_work(priv->workqueue, &priv->work);
++	} else {
++		evt.data.flags = 0;
++		evt.data.length = 0;
++		memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
++		wireless_send_event(dev->net, SIOCGIWAP, &evt, NULL);
++	}
++}
++
++
++static int rndis_wext_get_caps(struct usbnet *dev)
++{
++	struct {
++		__le32	num_items;
++		__le32	items[8];
++	} networks_supported;
++	int len, retval, i, n;
++	__le32 tx_power;
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++
++	/* determine if supports setting txpower */
++	len = sizeof(tx_power);
++	retval = rndis_query_oid(dev, OID_802_11_TX_POWER_LEVEL, &tx_power,
++								&len);
++	if (retval == 0 && le32_to_cpu(tx_power) != 0xFF)
++		priv->caps |= CAP_SUPPORT_TXPOWER;
++
++	/* determine supported modes */
++	len = sizeof(networks_supported);
++	retval = rndis_query_oid(dev, OID_802_11_NETWORK_TYPES_SUPPORTED,
++						&networks_supported, &len);
++	if (retval >= 0) {
++		n = le32_to_cpu(networks_supported.num_items);
++		if (n > 8)
++			n = 8;
++		for (i = 0; i < n; i++) {
++			switch (le32_to_cpu(networks_supported.items[i])) {
++			case Ndis802_11FH:
++			case Ndis802_11DS:
++				priv->caps |= CAP_MODE_80211B;
++				break;
++			case Ndis802_11OFDM5:
++				priv->caps |= CAP_MODE_80211A;
++				break;
++			case Ndis802_11OFDM24:
++				priv->caps |= CAP_MODE_80211G;
++				break;
++			}
++		}
++		if (priv->caps & CAP_MODE_80211A)
++			strcat(priv->name, "a");
++		if (priv->caps & CAP_MODE_80211B)
++			strcat(priv->name, "b");
++		if (priv->caps & CAP_MODE_80211G)
++			strcat(priv->name, "g");
++	}
++
++	return retval;
++}
++
++
++#define STATS_UPDATE_JIFFIES (HZ)
++static void rndis_update_wireless_stats(struct work_struct *work)
++{
++	struct rndis_wext_private *priv =
++		container_of(work, struct rndis_wext_private, stats_work.work);
++	struct usbnet *usbdev = priv->usbdev;
++	struct iw_statistics iwstats;
++	__le32 rssi, tmp;
++	int len, ret, bitrate, j;
++	unsigned long flags;
++	int update_jiffies = STATS_UPDATE_JIFFIES;
++	void *buf;
++
++	spin_lock_irqsave(&priv->stats_lock, flags);
++	memcpy(&iwstats, &priv->privstats, sizeof(iwstats));
++	spin_unlock_irqrestore(&priv->stats_lock, flags);
++
++	/* only update stats when connected */
++	if (!is_associated(usbdev)) {
++		iwstats.qual.qual = 0;
++		iwstats.qual.level = 0;
++		iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
++				| IW_QUAL_LEVEL_UPDATED
++				| IW_QUAL_NOISE_INVALID
++				| IW_QUAL_QUAL_INVALID
++				| IW_QUAL_LEVEL_INVALID;
++		goto end;
++	}
++
++	len = sizeof(rssi);
++	ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
++
++	devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret,
++							le32_to_cpu(rssi));
++	if (ret == 0) {
++		memset(&iwstats.qual, 0, sizeof(iwstats.qual));
++		iwstats.qual.qual  = level_to_qual(le32_to_cpu(rssi));
++		iwstats.qual.level = le32_to_cpu(rssi);
++		iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
++				| IW_QUAL_LEVEL_UPDATED
++				| IW_QUAL_NOISE_INVALID;
++	}
++
++	memset(&iwstats.discard, 0, sizeof(iwstats.discard));
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len);
++	if (ret == 0)
++		iwstats.discard.misc += le32_to_cpu(tmp);
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len);
++	if (ret == 0)
++		iwstats.discard.misc += le32_to_cpu(tmp);
++
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len);
++	if (ret == 0)
++		iwstats.discard.misc += le32_to_cpu(tmp);
++
++	/* Workaround transfer stalls on poor quality links. */
++	len = sizeof(tmp);
++	ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
++	if (ret == 0) {
++		bitrate = le32_to_cpu(tmp) * 100;
++		if (bitrate > 11000000)
++			goto end;
++
++		/* Decrease stats worker interval to catch stalls.
++		 * faster. Faster than 400-500ms causes packet loss,
++		 * Slower doesn't catch stalls fast enough.
++		 */
++		j = msecs_to_jiffies(priv->param_workaround_interval);
++		if (j > STATS_UPDATE_JIFFIES)
++			j = STATS_UPDATE_JIFFIES;
++		else if (j <= 0)
++			j = 1;
++		update_jiffies = j;
++
++		/* Send scan OID. Use of both OIDs is required to get device
++		 * working.
++		 */
++		tmp = ccpu2(1);
++		rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
++								sizeof(tmp));
++
++		len = CONTROL_BUFFER_SIZE;
++		buf = kmalloc(len, GFP_KERNEL);
++		if (!buf)
++			goto end;
++
++		rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
++		kfree(buf);
++	}
++end:
++	spin_lock_irqsave(&priv->stats_lock, flags);
++	memcpy(&priv->privstats, &iwstats, sizeof(iwstats));
++	spin_unlock_irqrestore(&priv->stats_lock, flags);
++
++	if (update_jiffies >= HZ)
++		update_jiffies = round_jiffies_relative(update_jiffies);
++	else {
++		j = round_jiffies_relative(update_jiffies);
++		if (abs(j - update_jiffies) <= 10)
++			update_jiffies = j;
++	}
++
++	queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies);
++}
++
++
++static int bcm4320_early_init(struct usbnet *dev)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++	char buf[8];
++
++	/* Early initialization settings, setting these won't have effect
++	 * if called after generic_rndis_bind().
++	 */
++
++	priv->param_country[0] = modparam_country[0];
++	priv->param_country[1] = modparam_country[1];
++	priv->param_country[2] = 0;
++	priv->param_frameburst   = modparam_frameburst;
++	priv->param_afterburner  = modparam_afterburner;
++	priv->param_power_save   = modparam_power_save;
++	priv->param_power_output = modparam_power_output;
++	priv->param_roamtrigger  = modparam_roamtrigger;
++	priv->param_roamdelta    = modparam_roamdelta;
++	priv->param_workaround_interval = modparam_workaround_interval;
++
++	priv->param_country[0] = toupper(priv->param_country[0]);
++	priv->param_country[1] = toupper(priv->param_country[1]);
++	/* doesn't support EU as country code, use FI instead */
++	if (!strcmp(priv->param_country, "EU"))
++		strcpy(priv->param_country, "FI");
++
++	if (priv->param_power_save < 0)
++		priv->param_power_save = 0;
++	else if (priv->param_power_save > 2)
++		priv->param_power_save = 2;
++
++	if (priv->param_roamtrigger < -80)
++		priv->param_roamtrigger = -80;
++	else if (priv->param_roamtrigger > -60)
++		priv->param_roamtrigger = -60;
++
++	if (priv->param_roamdelta < 0)
++		priv->param_roamdelta = 0;
++	else if (priv->param_roamdelta > 2)
++		priv->param_roamdelta = 2;
++
++	if (priv->param_workaround_interval < 0)
++		priv->param_workaround_interval = 500;
++
++	rndis_set_config_parameter_str(dev, "Country", priv->param_country);
++	rndis_set_config_parameter_str(dev, "FrameBursting",
++					priv->param_frameburst ? "1" : "0");
++	rndis_set_config_parameter_str(dev, "Afterburner",
++					priv->param_afterburner ? "1" : "0");
++	sprintf(buf, "%d", priv->param_power_save);
++	rndis_set_config_parameter_str(dev, "PowerSaveMode", buf);
++	sprintf(buf, "%d", priv->param_power_output);
++	rndis_set_config_parameter_str(dev, "PwrOut", buf);
++	sprintf(buf, "%d", priv->param_roamtrigger);
++	rndis_set_config_parameter_str(dev, "RoamTrigger", buf);
++	sprintf(buf, "%d", priv->param_roamdelta);
++	rndis_set_config_parameter_str(dev, "RoamDelta", buf);
++
++	return 0;
++}
++
++
++static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf)
++{
++	struct net_device *net = dev->net;
++	struct rndis_wext_private *priv;
++	int retval, len;
++	__le32 tmp;
++
++	/* allocate rndis private data */
++	priv = kmalloc(sizeof(struct rndis_wext_private), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	/* These have to be initialized before calling generic_rndis_bind().
++	 * Otherwise we'll be in big trouble in rndis_wext_early_init().
++	 */
++	dev->driver_priv = priv;
++	memset(priv, 0, sizeof(*priv));
++	memset(priv->name, 0, sizeof(priv->name));
++	strcpy(priv->name, "IEEE802.11");
++	net->wireless_handlers = &rndis_iw_handlers;
++	priv->usbdev = dev;
++
++	mutex_init(&priv->command_lock);
++	spin_lock_init(&priv->stats_lock);
++
++	/* try bind rndis_host */
++	retval = generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_WIRELESS);
++	if (retval < 0)
++		goto fail;
++
++	/* generic_rndis_bind set packet filter to multicast_all+
++	 * promisc mode which doesn't work well for our devices (device
++	 * picks up rssi to closest station instead of to access point).
++	 *
++	 * rndis_host wants to avoid all OID as much as possible
++	 * so do promisc/multicast handling in rndis_wext.
++	 */
++	dev->net->set_multicast_list = rndis_wext_set_multicast_list;
++	tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
++	retval = rndis_set_oid(dev, OID_GEN_CURRENT_PACKET_FILTER, &tmp,
++								sizeof(tmp));
++
++	len = sizeof(tmp);
++	retval = rndis_query_oid(dev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, &len);
++	priv->multicast_size = le32_to_cpu(tmp);
++	if (retval < 0 || priv->multicast_size < 0)
++		priv->multicast_size = 0;
++	if (priv->multicast_size > 0)
++		dev->net->flags |= IFF_MULTICAST;
++	else
++		dev->net->flags &= ~IFF_MULTICAST;
++
++	priv->iwstats.qual.qual = 0;
++	priv->iwstats.qual.level = 0;
++	priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
++					| IW_QUAL_LEVEL_UPDATED
++					| IW_QUAL_NOISE_INVALID
++					| IW_QUAL_QUAL_INVALID
++					| IW_QUAL_LEVEL_INVALID;
++
++	rndis_wext_get_caps(dev);
++	set_default_iw_params(dev);
++
++	/* turn radio on */
++	priv->radio_on = 1;
++	disassociate(dev, 1);
++
++	/* because rndis_command() sleeps we need to use workqueue */
++	priv->workqueue = create_singlethread_workqueue("rndis_wlan");
++	INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
++	queue_delayed_work(priv->workqueue, &priv->stats_work,
++		round_jiffies_relative(STATS_UPDATE_JIFFIES));
++	INIT_WORK(&priv->work, rndis_wext_worker);
++
++	return 0;
++
++fail:
++	kfree(priv);
++	return retval;
++}
++
++
++static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf)
++{
++	struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
++
++	/* turn radio off */
++	disassociate(dev, 0);
++
++	cancel_delayed_work_sync(&priv->stats_work);
++	cancel_work_sync(&priv->work);
++	flush_workqueue(priv->workqueue);
++	destroy_workqueue(priv->workqueue);
++
++	if (priv && priv->wpa_ie_len)
++		kfree(priv->wpa_ie);
++	kfree(priv);
++
++	rndis_unbind(dev, intf);
++}
++
++
++static int rndis_wext_reset(struct usbnet *dev)
++{
++	return deauthenticate(dev);
++}
++
++
++static const struct driver_info	bcm4320b_info = {
++	.description =	"Wireless RNDIS device, BCM4320b based",
++	.flags =	FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
++	.bind =		rndis_wext_bind,
++	.unbind =	rndis_wext_unbind,
++	.status =	rndis_status,
++	.rx_fixup =	rndis_rx_fixup,
++	.tx_fixup =	rndis_tx_fixup,
++	.reset =	rndis_wext_reset,
++	.early_init =	bcm4320_early_init,
++	.link_change =	rndis_wext_link_change,
++};
++
++static const struct driver_info	bcm4320a_info = {
++	.description =	"Wireless RNDIS device, BCM4320a based",
++	.flags =	FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
++	.bind =		rndis_wext_bind,
++	.unbind =	rndis_wext_unbind,
++	.status =	rndis_status,
++	.rx_fixup =	rndis_rx_fixup,
++	.tx_fixup =	rndis_tx_fixup,
++	.reset =	rndis_wext_reset,
++	.early_init =	bcm4320_early_init,
++	.link_change =	rndis_wext_link_change,
++};
++
++static const struct driver_info rndis_wext_info = {
++	.description =	"Wireless RNDIS device",
++	.flags =	FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
++	.bind =		rndis_wext_bind,
++	.unbind =	rndis_wext_unbind,
++	.status =	rndis_status,
++	.rx_fixup =	rndis_rx_fixup,
++	.tx_fixup =	rndis_tx_fixup,
++	.reset =	rndis_wext_reset,
++	.early_init =	bcm4320_early_init,
++	.link_change =	rndis_wext_link_change,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static const struct usb_device_id products [] = {
++#define	RNDIS_MASTER_INTERFACE \
++	.bInterfaceClass	= USB_CLASS_COMM, \
++	.bInterfaceSubClass	= 2 /* ACM */, \
++	.bInterfaceProtocol	= 0x0ff
++
++/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom
++ * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki.
++ */
++{
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0411,
++	.idProduct		= 0x00bc,	/* Buffalo WLI-U2-KG125S */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0baf,
++	.idProduct		= 0x011b,	/* U.S. Robotics USR5421 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x050d,
++	.idProduct		= 0x011b,	/* Belkin F5D7051 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x1799,	/* Belkin has two vendor ids */
++	.idProduct		= 0x011b,	/* Belkin F5D7051 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x13b1,
++	.idProduct		= 0x0014,	/* Linksys WUSB54GSv2 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x13b1,
++	.idProduct		= 0x0026,	/* Linksys WUSB54GSC */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0b05,
++	.idProduct		= 0x1717,	/* Asus WL169gE */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0a5c,
++	.idProduct		= 0xd11b,	/* Eminent EM4045 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x1690,
++	.idProduct		= 0x0715,	/* BT Voyager 1055 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320b_info,
++},
++/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom
++ * parameters available, hardware probably contain older firmware version with
++ * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki.
++ */
++{
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x13b1,
++	.idProduct		= 0x000e,	/* Linksys WUSB54GSv1 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320a_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0baf,
++	.idProduct		= 0x0111,	/* U.S. Robotics USR5420 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320a_info,
++}, {
++	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
++			  | USB_DEVICE_ID_MATCH_DEVICE,
++	.idVendor		= 0x0411,
++	.idProduct		= 0x004b,	/* BUFFALO WLI-USB-G54 */
++	RNDIS_MASTER_INTERFACE,
++	.driver_info		= (unsigned long) &bcm4320a_info,
++},
++/* Generic Wireless RNDIS devices that we don't have exact
++ * idVendor/idProduct/chip yet.
++ */
++{
++	/* RNDIS is MSFT's un-official variant of CDC ACM */
++	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
++	.driver_info = (unsigned long) &rndis_wext_info,
++}, {
++	/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
++	USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
++	.driver_info = (unsigned long) &rndis_wext_info,
++},
++	{ },		// END
++};
++MODULE_DEVICE_TABLE(usb, products);
++
++static struct usb_driver rndis_wlan_driver = {
++	.name =		"rndis_wlan",
++	.id_table =	products,
++	.probe =	usbnet_probe,
++	.disconnect =	usbnet_disconnect,
++	.suspend =	usbnet_suspend,
++	.resume =	usbnet_resume,
++};
++
++static int __init rndis_wlan_init(void)
++{
++	return usb_register(&rndis_wlan_driver);
++}
++module_init(rndis_wlan_init);
++
++static void __exit rndis_wlan_exit(void)
++{
++	usb_deregister(&rndis_wlan_driver);
++}
++module_exit(rndis_wlan_exit);
++
++MODULE_AUTHOR("Bjorge Dijkstra");
++MODULE_AUTHOR("Jussi Kivilinna");
++MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
+index 31c1dd2..d6cba13 100644
+--- a/drivers/net/wireless/rt2x00/rt2400pci.c
++++ b/drivers/net/wireless/rt2x00/rt2400pci.c
+@@ -24,11 +24,6 @@
+ 	Supported chipsets: RT2460.
+  */
+ 
+-/*
+- * Set enviroment defines for rt2x00.h
+- */
+-#define DRV_NAME "rt2400pci"
+-
+ #include <linux/delay.h>
+ #include <linux/etherdevice.h>
+ #include <linux/init.h>
+@@ -54,7 +49,7 @@
+  * the access attempt is considered to have failed,
+  * and we will print an error.
+  */
+-static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
++static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
+ {
+ 	u32 reg;
+ 	unsigned int i;
+@@ -69,7 +64,7 @@ static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+ 	return reg;
+ }
+ 
+-static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
++static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
+ 				const unsigned int word, const u8 value)
+ {
+ 	u32 reg;
+@@ -95,7 +90,7 @@ static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ 	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ }
+ 
+-static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
++static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
+ 			       const unsigned int word, u8 *value)
+ {
+ 	u32 reg;
+@@ -132,7 +127,7 @@ static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+ }
+ 
+-static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
++static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
+ 			       const unsigned int word, const u32 value)
+ {
+ 	u32 reg;
+@@ -195,13 +190,13 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+ #ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+ 
+-static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
++static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
+ 			       const unsigned int word, u32 *data)
+ {
+ 	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+ }
+ 
+-static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
++static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
+ 				const unsigned int word, u32 data)
+ {
+ 	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+@@ -285,7 +280,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ 	 */
+ 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ 	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+-	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
++	rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
+ 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ 	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+ 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+@@ -397,7 +392,7 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
+ }
+ 
+ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+-				     int antenna_tx, int antenna_rx)
++				     struct antenna_setup *ant)
+ {
+ 	u8 r1;
+ 	u8 r4;
+@@ -408,14 +403,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ 	/*
+ 	 * Configure the TX antenna.
+ 	 */
+-	switch (antenna_tx) {
+-	case ANTENNA_SW_DIVERSITY:
++	switch (ant->tx) {
+ 	case ANTENNA_HW_DIVERSITY:
+ 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+ 		break;
+ 	case ANTENNA_A:
+ 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+ 		break;
++	case ANTENNA_SW_DIVERSITY:
++		/*
++		 * NOTE: We should never come here because rt2x00lib is
++		 * supposed to catch this and send us the correct antenna
++		 * explicitely. However we are nog going to bug about this.
++		 * Instead, just default to antenna B.
++		 */
+ 	case ANTENNA_B:
+ 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+ 		break;
+@@ -424,14 +425,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ 	/*
+ 	 * Configure the RX antenna.
+ 	 */
+-	switch (antenna_rx) {
+-	case ANTENNA_SW_DIVERSITY:
++	switch (ant->rx) {
+ 	case ANTENNA_HW_DIVERSITY:
+ 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ 		break;
+ 	case ANTENNA_A:
+ 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+ 		break;
++	case ANTENNA_SW_DIVERSITY:
++		/*
++		 * NOTE: We should never come here because rt2x00lib is
++		 * supposed to catch this and send us the correct antenna
++		 * explicitely. However we are nog going to bug about this.
++		 * Instead, just default to antenna B.
++		 */
+ 	case ANTENNA_B:
+ 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ 		break;
+@@ -485,9 +492,7 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
+ 		rt2400pci_config_txpower(rt2x00dev,
+ 					 libconf->conf->power_level);
+ 	if (flags & CONFIG_UPDATE_ANTENNA)
+-		rt2400pci_config_antenna(rt2x00dev,
+-					 libconf->conf->antenna_sel_tx,
+-					 libconf->conf->antenna_sel_rx);
++		rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
+ 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ 		rt2400pci_config_duration(rt2x00dev, libconf);
+ }
+@@ -514,18 +519,10 @@ static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
+ 
+ 	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+ 	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+-
+-	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+-	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+-		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+-	} else {
+-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+-	}
+-
++	rt2x00_set_field32(&reg, LEDCSR_LINK,
++			   (rt2x00dev->led_mode != LED_MODE_ASUS));
++	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
++			   (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
+ 	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+ }
+ 
+@@ -542,7 +539,8 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
+ /*
+  * Link tuning
+  */
+-static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
++static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
++				 struct link_qual *qual)
+ {
+ 	u32 reg;
+ 	u8 bbp;
+@@ -551,13 +549,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
+ 	 * Update FCS error count from register.
+ 	 */
+ 	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+-	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
++	qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+ 
+ 	/*
+ 	 * Update False CCA count from register.
+ 	 */
+ 	rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
+-	rt2x00dev->link.false_cca = bbp;
++	qual->false_cca = bbp;
+ }
+ 
+ static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+@@ -582,10 +580,10 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+ 	 */
+ 	rt2400pci_bbp_read(rt2x00dev, 13, &reg);
+ 
+-	if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
++	if (rt2x00dev->link.qual.false_cca > 512 && reg < 0x20) {
+ 		rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
+ 		rt2x00dev->link.vgc_level = reg;
+-	} else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
++	} else if (rt2x00dev->link.qual.false_cca < 100 && reg > 0x08) {
+ 		rt2400pci_bbp_write(rt2x00dev, 13, --reg);
+ 		rt2x00dev->link.vgc_level = reg;
+ 	}
+@@ -594,65 +592,43 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+ /*
+  * Initialization functions.
+  */
+-static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
++static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
++				   struct data_entry *entry)
+ {
+-	struct data_ring *ring = rt2x00dev->rx;
+-	struct data_desc *rxd;
+-	unsigned int i;
++	__le32 *rxd = entry->priv;
+ 	u32 word;
+ 
+-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+-
+-	for (i = 0; i < ring->stats.limit; i++) {
+-		rxd = ring->entry[i].priv;
+-
+-		rt2x00_desc_read(rxd, 2, &word);
+-		rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
+-				   ring->data_size);
+-		rt2x00_desc_write(rxd, 2, word);
+-
+-		rt2x00_desc_read(rxd, 1, &word);
+-		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+-				   ring->entry[i].data_dma);
+-		rt2x00_desc_write(rxd, 1, word);
++	rt2x00_desc_read(rxd, 2, &word);
++	rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size);
++	rt2x00_desc_write(rxd, 2, word);
+ 
+-		rt2x00_desc_read(rxd, 0, &word);
+-		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+-		rt2x00_desc_write(rxd, 0, word);
+-	}
++	rt2x00_desc_read(rxd, 1, &word);
++	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
++	rt2x00_desc_write(rxd, 1, word);
+ 
+-	rt2x00_ring_index_clear(rt2x00dev->rx);
++	rt2x00_desc_read(rxd, 0, &word);
++	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
++	rt2x00_desc_write(rxd, 0, word);
+ }
+ 
+-static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
++static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
++				   struct data_entry *entry)
+ {
+-	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+-	struct data_desc *txd;
+-	unsigned int i;
++	__le32 *txd = entry->priv;
+ 	u32 word;
+ 
+-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+-
+-	for (i = 0; i < ring->stats.limit; i++) {
+-		txd = ring->entry[i].priv;
+-
+-		rt2x00_desc_read(txd, 1, &word);
+-		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+-				   ring->entry[i].data_dma);
+-		rt2x00_desc_write(txd, 1, word);
+-
+-		rt2x00_desc_read(txd, 2, &word);
+-		rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
+-				   ring->data_size);
+-		rt2x00_desc_write(txd, 2, word);
++	rt2x00_desc_read(txd, 1, &word);
++	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
++	rt2x00_desc_write(txd, 1, word);
+ 
+-		rt2x00_desc_read(txd, 0, &word);
+-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+-		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+-		rt2x00_desc_write(txd, 0, word);
+-	}
++	rt2x00_desc_read(txd, 2, &word);
++	rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size);
++	rt2x00_desc_write(txd, 2, word);
+ 
+-	rt2x00_ring_index_clear(ring);
++	rt2x00_desc_read(txd, 0, &word);
++	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
++	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
++	rt2x00_desc_write(txd, 0, word);
+ }
+ 
+ static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+@@ -660,15 +636,6 @@ static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+ 	u32 reg;
+ 
+ 	/*
+-	 * Initialize rings.
+-	 */
+-	rt2400pci_init_rxring(rt2x00dev);
+-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+-
+-	/*
+ 	 * Initialize registers.
+ 	 */
+ 	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+@@ -1014,53 +981,37 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+  * TX descriptor initialization
+  */
+ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+-				    struct data_desc *txd,
++				    struct sk_buff *skb,
+ 				    struct txdata_entry_desc *desc,
+-				    struct ieee80211_hdr *ieee80211hdr,
+-				    unsigned int length,
+ 				    struct ieee80211_tx_control *control)
+ {
++	struct skb_desc *skbdesc = get_skb_desc(skb);
++	__le32 *txd = skbdesc->desc;
+ 	u32 word;
+-	u32 signal = 0;
+-	u32 service = 0;
+-	u32 length_high = 0;
+-	u32 length_low = 0;
+-
+-	/*
+-	 * The PLCP values should be treated as if they
+-	 * were BBP values.
+-	 */
+-	rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
+-	rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
+-	rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
+-
+-	rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
+-	rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
+-	rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
+-
+-	rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
+-	rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
+-	rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
+-
+-	rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
+-	rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
+-	rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
+ 
+ 	/*
+ 	 * Start writing the descriptor words.
+ 	 */
+ 	rt2x00_desc_read(txd, 2, &word);
+-	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
++	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
+ 	rt2x00_desc_write(txd, 2, word);
+ 
+ 	rt2x00_desc_read(txd, 3, &word);
+-	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
+-	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1);
+ 	rt2x00_desc_write(txd, 3, word);
+ 
+ 	rt2x00_desc_read(txd, 4, &word);
+-	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
+-	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
++	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1);
++	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7);
++	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
+ 	rt2x00_desc_write(txd, 4, word);
+ 
+ 	rt2x00_desc_read(txd, 0, &word);
+@@ -1069,7 +1020,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ 	rt2x00_set_field32(&word, TXD_W0_ACK,
+-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
++			   test_bit(ENTRY_TXD_ACK, &desc->flags));
+ 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ 	rt2x00_set_field32(&word, TXD_W0_RTS,
+@@ -1099,12 +1050,12 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ 	}
+ 
+ 	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+-	if (queue == IEEE80211_TX_QUEUE_DATA0)
+-		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+-	else if (queue == IEEE80211_TX_QUEUE_DATA1)
+-		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+-	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+-		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
++	rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
++			   (queue == IEEE80211_TX_QUEUE_DATA0));
++	rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
++			   (queue == IEEE80211_TX_QUEUE_DATA1));
++	rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
++			   (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
+ 	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ }
+ 
+@@ -1114,7 +1065,7 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ static void rt2400pci_fill_rxdone(struct data_entry *entry,
+ 				  struct rxdata_entry_desc *desc)
+ {
+-	struct data_desc *rxd = entry->priv;
++	__le32 *rxd = entry->priv;
+ 	u32 word0;
+ 	u32 word2;
+ 
+@@ -1135,6 +1086,7 @@ static void rt2400pci_fill_rxdone(struct data_entry *entry,
+ 	    entry->ring->rt2x00dev->rssi_offset;
+ 	desc->ofdm = 0;
+ 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
++	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
+ }
+ 
+ /*
+@@ -1144,7 +1096,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+ {
+ 	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ 	struct data_entry *entry;
+-	struct data_desc *txd;
++	__le32 *txd;
+ 	u32 word;
+ 	int tx_status;
+ 	int retry;
+@@ -1164,26 +1116,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+ 		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ 		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+ 
+-		rt2x00lib_txdone(entry, tx_status, retry);
+-
+-		/*
+-		 * Make this entry available for reuse.
+-		 */
+-		entry->flags = 0;
+-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+-		rt2x00_desc_write(txd, 0, word);
+-		rt2x00_ring_index_done_inc(ring);
++		rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
+ 	}
+-
+-	/*
+-	 * If the data ring was full before the txdone handler
+-	 * we must make sure the packet queue in the mac80211 stack
+-	 * is reenabled when the txdone handler has finished.
+-	 */
+-	entry = ring->entry;
+-	if (!rt2x00_ring_full(ring))
+-		ieee80211_wake_queue(rt2x00dev->hw,
+-				     entry->tx_status.control.queue);
+ }
+ 
+ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+@@ -1315,12 +1249,23 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+ 	/*
+ 	 * Identify default antenna configuration.
+ 	 */
+-	rt2x00dev->hw->conf.antenna_sel_tx =
++	rt2x00dev->default_ant.tx =
+ 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+-	rt2x00dev->hw->conf.antenna_sel_rx =
++	rt2x00dev->default_ant.rx =
+ 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+ 
+ 	/*
++	 * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead.
++	 * I am not 100% sure about this, but the legacy drivers do not
++	 * indicate antenna swapping in software is required when
++	 * diversity is enabled.
++	 */
++	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
++		rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY;
++	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
++		rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY;
++
++	/*
+ 	 * Store led mode, for correct led behaviour.
+ 	 */
+ 	rt2x00dev->led_mode =
+@@ -1447,7 +1392,6 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+ 				       struct dev_addr_list *mc_list)
+ {
+ 	struct rt2x00_dev *rt2x00dev = hw->priv;
+-	struct interface *intf = &rt2x00dev->interface;
+ 	u32 reg;
+ 
+ 	/*
+@@ -1466,21 +1410,18 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+ 	 * Apply some rules to the filters:
+ 	 * - Some filters imply different filters to be set.
+ 	 * - Some things we can't filter out at all.
+-	 * - Some filters are set based on interface type.
+ 	 */
+ 	*total_flags |= FIF_ALLMULTI;
+ 	if (*total_flags & FIF_OTHER_BSS ||
+ 	    *total_flags & FIF_PROMISC_IN_BSS)
+ 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+-		*total_flags |= FIF_PROMISC_IN_BSS;
+ 
+ 	/*
+ 	 * Check if there is any work left for us.
+ 	 */
+-	if (intf->filter == *total_flags)
++	if (rt2x00dev->packet_filter == *total_flags)
+ 		return;
+-	intf->filter = *total_flags;
++	rt2x00dev->packet_filter = *total_flags;
+ 
+ 	/*
+ 	 * Start configuration steps.
+@@ -1583,7 +1524,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
+ 	.configure_filter	= rt2400pci_configure_filter,
+ 	.get_stats		= rt2x00mac_get_stats,
+ 	.set_retry_limit	= rt2400pci_set_retry_limit,
+-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
++	.bss_info_changed	= rt2x00mac_bss_info_changed,
+ 	.conf_tx		= rt2400pci_conf_tx,
+ 	.get_tx_stats		= rt2x00mac_get_tx_stats,
+ 	.get_tsf		= rt2400pci_get_tsf,
+@@ -1597,6 +1538,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
+ 	.probe_hw		= rt2400pci_probe_hw,
+ 	.initialize		= rt2x00pci_initialize,
+ 	.uninitialize		= rt2x00pci_uninitialize,
++	.init_rxentry		= rt2400pci_init_rxentry,
++	.init_txentry		= rt2400pci_init_txentry,
+ 	.set_device_state	= rt2400pci_set_device_state,
+ 	.rfkill_poll		= rt2400pci_rfkill_poll,
+ 	.link_stats		= rt2400pci_link_stats,
+@@ -1614,7 +1557,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
+ };
+ 
+ static const struct rt2x00_ops rt2400pci_ops = {
+-	.name		= DRV_NAME,
++	.name		= KBUILD_MODNAME,
+ 	.rxd_size	= RXD_DESC_SIZE,
+ 	.txd_size	= TXD_DESC_SIZE,
+ 	.eeprom_size	= EEPROM_SIZE,
+@@ -1642,7 +1585,7 @@ MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
+ MODULE_LICENSE("GPL");
+ 
+ static struct pci_driver rt2400pci_driver = {
+-	.name		= DRV_NAME,
++	.name		= KBUILD_MODNAME,
+ 	.id_table	= rt2400pci_device_table,
+ 	.probe		= rt2x00pci_probe,
+ 	.remove		= __devexit_p(rt2x00pci_remove),
+diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
+index ae22501..369aac6 100644
+--- a/drivers/net/wireless/rt2x00/rt2400pci.h
++++ b/drivers/net/wireless/rt2x00/rt2400pci.h
+@@ -803,8 +803,8 @@
+ /*
+  * DMA descriptor defines.
+  */
+-#define TXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
+-#define RXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
++#define TXD_DESC_SIZE			( 8 * sizeof(__le32) )
++#define RXD_DESC_SIZE			( 8 * sizeof(__le32) )
+ 
+ /*
+  * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+@@ -839,11 +839,21 @@
+ 
+ /*
+  * Word3 & 4: PLCP information
+- */
+-#define TXD_W3_PLCP_SIGNAL		FIELD32(0x0000ffff)
+-#define TXD_W3_PLCP_SERVICE		FIELD32(0xffff0000)
+-#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x0000ffff)
+-#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0xffff0000)
++ * The PLCP values should be treated as if they were BBP values.
++ */
++#define TXD_W3_PLCP_SIGNAL		FIELD32(0x000000ff)
++#define TXD_W3_PLCP_SIGNAL_REGNUM	FIELD32(0x00007f00)
++#define TXD_W3_PLCP_SIGNAL_BUSY		FIELD32(0x00008000)
++#define TXD_W3_PLCP_SERVICE		FIELD32(0x00ff0000)
++#define TXD_W3_PLCP_SERVICE_REGNUM	FIELD32(0x7f000000)
++#define TXD_W3_PLCP_SERVICE_BUSY	FIELD32(0x80000000)
++
++#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x000000ff)
++#define TXD_W3_PLCP_LENGTH_LOW_REGNUM	FIELD32(0x00007f00)
++#define TXD_W3_PLCP_LENGTH_LOW_BUSY	FIELD32(0x00008000)
++#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0x00ff0000)
++#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM	FIELD32(0x7f000000)
++#define TXD_W3_PLCP_LENGTH_HIGH_BUSY	FIELD32(0x80000000)
+ 
+ /*
+  * Word5
+diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
+index 702321c..e874fdc 100644
+--- a/drivers/net/wireless/rt2x00/rt2500pci.c
++++ b/drivers/net/wireless/rt2x00/rt2500pci.c
+@@ -24,11 +24,6 @@
+ 	Supported chipsets: RT2560.
+  */
+ 
 -/*
 - * Set enviroment defines for rt2x00.h
 - */
@@ -646503,7 +669986,7 @@
  void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
  
 diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
-index ecae968..ab52f22 100644
+index ecae968..b31f0c2 100644
 --- a/drivers/net/wireless/rt2x00/rt61pci.c
 +++ b/drivers/net/wireless/rt2x00/rt61pci.c
 @@ -24,11 +24,6 @@
@@ -647183,7 +670666,17 @@
  	u32 word;
  	u32 reg;
  	u32 old_reg;
-@@ -1809,24 +1746,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
+@@ -1799,7 +1736,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
+ 			WARNING(rt2x00dev,
+ 				"TX status report missed for entry %p\n",
+ 				entry_done);
+-			rt2x00lib_txdone(entry_done, TX_FAIL_OTHER, 0);
++			rt2x00pci_txdone(rt2x00dev, entry_done, TX_FAIL_OTHER,
++					 0);
+ 			entry_done = rt2x00_get_data_entry_done(ring);
+ 		}
+ 
+@@ -1809,24 +1747,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
  		tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
  		retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
  
@@ -647209,7 +670702,7 @@
  	}
  }
  
-@@ -1920,8 +1840,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+@@ -1920,8 +1841,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
  	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
  	if (word == 0xffff) {
  		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
@@ -647222,7 +670715,7 @@
  		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
  		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
  		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
-@@ -2025,11 +1947,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+@@ -2025,11 +1948,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
  	}
  
  	/*
@@ -647242,7 +670735,7 @@
  	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
  
  	/*
-@@ -2039,12 +1967,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+@@ -2039,12 +1968,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
  		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
  
  	/*
@@ -647255,7 +670748,7 @@
  	 * Detect if this device has an hardware controlled radio.
  	 */
  #ifdef CONFIG_RT61PCI_RFKILL
-@@ -2072,6 +1994,38 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+@@ -2072,6 +1995,38 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
  		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
  
  	/*
@@ -647294,7 +670787,7 @@
  	 * Store led settings, for correct led behaviour.
  	 * If the eeprom value is invalid,
  	 * switch to default led mode.
-@@ -2325,7 +2279,6 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+@@ -2325,7 +2280,6 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
  				     struct dev_addr_list *mc_list)
  {
  	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -647302,7 +670795,7 @@
  	u32 reg;
  
  	/*
-@@ -2344,22 +2297,19 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+@@ -2344,22 +2298,19 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
  	 * Apply some rules to the filters:
  	 * - Some filters imply different filters to be set.
  	 * - Some things we can't filter out at all.
@@ -647327,7 +670820,7 @@
  
  	/*
  	 * Start configuration steps.
-@@ -2426,6 +2376,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -2426,6 +2377,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  			  struct ieee80211_tx_control *control)
  {
  	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -647337,7 +670830,7 @@
  
  	/*
  	 * Just in case the ieee80211 doesn't set this,
-@@ -2433,6 +2386,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -2433,6 +2387,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  	 * initialization.
  	 */
  	control->queue = IEEE80211_TX_QUEUE_BEACON;
@@ -647346,7 +670839,7 @@
  
  	/*
  	 * We need to append the descriptor in front of the
-@@ -2446,15 +2401,23 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -2446,15 +2402,23 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  	}
  
  	/*
@@ -647377,7 +670870,7 @@
  
  	/*
  	 * Write entire beacon with descriptor to register,
-@@ -2478,7 +2441,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
+@@ -2478,7 +2442,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
  	.configure_filter	= rt61pci_configure_filter,
  	.get_stats		= rt2x00mac_get_stats,
  	.set_retry_limit	= rt61pci_set_retry_limit,
@@ -647386,7 +670879,7 @@
  	.conf_tx		= rt2x00mac_conf_tx,
  	.get_tx_stats		= rt2x00mac_get_tx_stats,
  	.get_tsf		= rt61pci_get_tsf,
-@@ -2493,6 +2456,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
+@@ -2493,6 +2457,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
  	.load_firmware		= rt61pci_load_firmware,
  	.initialize		= rt2x00pci_initialize,
  	.uninitialize		= rt2x00pci_uninitialize,
@@ -647395,7 +670888,7 @@
  	.set_device_state	= rt61pci_set_device_state,
  	.rfkill_poll		= rt61pci_rfkill_poll,
  	.link_stats		= rt61pci_link_stats,
-@@ -2510,7 +2475,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
+@@ -2510,7 +2476,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
  };
  
  static const struct rt2x00_ops rt61pci_ops = {
@@ -647404,7 +670897,7 @@
  	.rxd_size	= RXD_DESC_SIZE,
  	.txd_size	= TXD_DESC_SIZE,
  	.eeprom_size	= EEPROM_SIZE,
-@@ -2547,7 +2512,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2661);
+@@ -2547,7 +2513,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2661);
  MODULE_LICENSE("GPL");
  
  static struct pci_driver rt61pci_driver = {
@@ -648315,10 +671808,10 @@
 +#endif /* RTL8180_H */
 diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
 new file mode 100644
-index 0000000..07f37b0
+index 0000000..27ebd68
 --- /dev/null
 +++ b/drivers/net/wireless/rtl8180_dev.c
-@@ -0,0 +1,1051 @@
+@@ -0,0 +1,1052 @@
 +
 +/*
 + * Linux device driver for RTL8180 / RTL8185
@@ -648357,6 +671850,7 @@
 +static struct pci_device_id rtl8180_table[] __devinitdata = {
 +	/* rtl8185 */
 +	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
 +	{ PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) },
 +
 +	/* rtl8180 */
@@ -655823,6 +679317,178 @@
  obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
  obj-$(CONFIG_X86_VISWS) += setup-irq.o
  
+diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
+index 9e5ea07..ef5a6a2 100644
+--- a/drivers/pci/bus.c
++++ b/drivers/pci/bus.c
+@@ -108,6 +108,7 @@ int pci_bus_add_device(struct pci_dev *dev)
+ void pci_bus_add_devices(struct pci_bus *bus)
+ {
+ 	struct pci_dev *dev;
++	struct pci_bus *child_bus;
+ 	int retval;
+ 
+ 	list_for_each_entry(dev, &bus->devices, bus_list) {
+@@ -138,11 +139,19 @@ void pci_bus_add_devices(struct pci_bus *bus)
+ 			       up_write(&pci_bus_sem);
+ 			}
+ 			pci_bus_add_devices(dev->subordinate);
+-			retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
+-						   &dev->dev.kobj, "bridge");
++
++			/* register the bus with sysfs as the parent is now
++			 * properly registered. */
++			child_bus = dev->subordinate;
++			child_bus->dev.parent = child_bus->bridge;
++			retval = device_register(&child_bus->dev);
++			if (!retval)
++				retval = device_create_file(&child_bus->dev,
++							&dev_attr_cpuaffinity);
+ 			if (retval)
+-				dev_err(&dev->dev, "Error creating sysfs "
+-					"bridge symlink, continuing...\n");
++				dev_err(&dev->dev, "Error registering pci_bus"
++					" device bridge symlink,"
++					" continuing...\n");
+ 		}
+ 	}
+ }
+@@ -204,7 +213,6 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
+ 	}
+ 	up_read(&pci_bus_sem);
+ }
+-EXPORT_SYMBOL_GPL(pci_walk_bus);
+ 
+ EXPORT_SYMBOL(pci_bus_alloc_resource);
+ EXPORT_SYMBOL_GPL(pci_bus_add_device);
+diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
+index 5dfdfda..91b2dc9 100644
+--- a/drivers/pci/dmar.c
++++ b/drivers/pci/dmar.c
+@@ -25,6 +25,7 @@
+ 
+ #include <linux/pci.h>
+ #include <linux/dmar.h>
++#include "iova.h"
+ 
+ #undef PREFIX
+ #define PREFIX "DMAR:"
+@@ -263,8 +264,8 @@ parse_dmar_table(void)
+ 	if (!dmar)
+ 		return -ENODEV;
+ 
+-	if (!dmar->width) {
+-		printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
++	if (dmar->width < PAGE_SHIFT_4K - 1) {
++		printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
+ 		return -EINVAL;
+ 	}
+ 
+@@ -301,11 +302,24 @@ parse_dmar_table(void)
+ int __init dmar_table_init(void)
+ {
+ 
+-	parse_dmar_table();
++	int ret;
++
++	ret = parse_dmar_table();
++	if (ret) {
++		printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
++		return ret;
++	}
++
+ 	if (list_empty(&dmar_drhd_units)) {
+ 		printk(KERN_INFO PREFIX "No DMAR devices found\n");
+ 		return -ENODEV;
+ 	}
++
++	if (list_empty(&dmar_rmrr_units)) {
++		printk(KERN_INFO PREFIX "No RMRR found\n");
++		return -ENODEV;
++	}
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
+index a64449d..2cdd832 100644
+--- a/drivers/pci/hotplug/Kconfig
++++ b/drivers/pci/hotplug/Kconfig
+@@ -3,8 +3,8 @@
+ #
+ 
+ menuconfig HOTPLUG_PCI
+-	tristate "Support for PCI Hotplug (EXPERIMENTAL)"
+-	depends on PCI && EXPERIMENTAL && HOTPLUG
++	tristate "Support for PCI Hotplug"
++	depends on PCI && HOTPLUG
+ 	---help---
+ 	  Say Y here if you have a motherboard with a PCI Hotplug controller.
+ 	  This allows you to add and remove PCI cards while the machine is
+diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
+index 34a1891..9bdbe1a 100644
+--- a/drivers/pci/hotplug/Makefile
++++ b/drivers/pci/hotplug/Makefile
+@@ -3,7 +3,6 @@
+ #
+ 
+ obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
+-obj-$(CONFIG_HOTPLUG_PCI_FAKE)		+= fakephp.o 
+ obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
+ obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
+ obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
+@@ -16,6 +15,9 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA)		+= rpaphp.o
+ obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)	+= rpadlpar_io.o
+ obj-$(CONFIG_HOTPLUG_PCI_SGI)		+= sgi_hotplug.o
+ 
++# Link this last so it doesn't claim devices that have a real hotplug driver
++obj-$(CONFIG_HOTPLUG_PCI_FAKE)		+= fakephp.o
++
+ pci_hotplug-objs	:=	pci_hotplug_core.o
+ 
+ ifdef CONFIG_HOTPLUG_PCI_CPCI
+diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
+index 1ef417c..7a29164 100644
+--- a/drivers/pci/hotplug/acpiphp.h
++++ b/drivers/pci/hotplug/acpiphp.h
+@@ -113,7 +113,6 @@ struct acpiphp_slot {
+ 	u8		device;		/* pci device# */
+ 
+ 	u32		sun;		/* ACPI _SUN (slot unique number) */
+-	u32		slotno;		/* slot number relative to bridge */
+ 	u32		flags;		/* see below */
+ };
+ 
+diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
+index ff1b1c7..cf22f9e 100644
+--- a/drivers/pci/hotplug/acpiphp_glue.c
++++ b/drivers/pci/hotplug/acpiphp_glue.c
+@@ -102,7 +102,7 @@ static int is_ejectable(acpi_handle handle)
+ }
+ 
+ 
+-/* callback routine to check the existence of ejectable slots */
++/* callback routine to check for the existence of ejectable slots */
+ static acpi_status
+ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+ {
+@@ -117,7 +117,7 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+ 	}
+ }
+ 
+-/* callback routine to check for the existance of a pci dock device */
++/* callback routine to check for the existence of a pci dock device */
+ static acpi_status
+ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+ {
+@@ -1528,7 +1528,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+ 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ 		dbg("%s: re-enumerating slots under %s\n",
+ 			__FUNCTION__, objname);
+-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ 		acpiphp_check_bridge(bridge);
+ 	}
+ 	return AE_OK ;
 diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
 index 47d26b6..750ebd7 100644
 --- a/drivers/pci/hotplug/acpiphp_ibm.c
@@ -655845,8 +679511,160 @@
  
  	dbg("%s\n", __FUNCTION__);
  
+diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
+index d7a293e..94b6401 100644
+--- a/drivers/pci/hotplug/fakephp.c
++++ b/drivers/pci/hotplug/fakephp.c
+@@ -39,6 +39,7 @@
+ #include <linux/init.h>
+ #include <linux/string.h>
+ #include <linux/slab.h>
++#include <linux/workqueue.h>
+ #include "../pci.h"
+ 
+ #if !defined(MODULE)
+@@ -63,10 +64,16 @@ struct dummy_slot {
+ 	struct list_head node;
+ 	struct hotplug_slot *slot;
+ 	struct pci_dev *dev;
++	struct work_struct remove_work;
++	unsigned long removed;
+ };
+ 
+ static int debug;
+ static LIST_HEAD(slot_list);
++static struct workqueue_struct *dummyphp_wq;
++
++static void pci_rescan_worker(struct work_struct *work);
++static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
+ 
+ static int enable_slot (struct hotplug_slot *slot);
+ static int disable_slot (struct hotplug_slot *slot);
+@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev)
+ 	slot->name = &dev->dev.bus_id[0];
+ 	dbg("slot->name = %s\n", slot->name);
+ 
+-	dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
++	dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+ 	if (!dslot)
+ 		goto error_info;
+ 
+@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot)
+ 		err("Problem unregistering a slot %s\n", dslot->slot->name);
+ }
+ 
++/* called from the single-threaded workqueue handler to remove a slot */
++static void remove_slot_worker(struct work_struct *work)
++{
++	struct dummy_slot *dslot =
++		container_of(work, struct dummy_slot, remove_work);
++	remove_slot(dslot);
++}
++
+ /**
+  * pci_rescan_slot - Rescan slot
+  * @temp: Device template. Should be set: bus and devfn.
+@@ -267,11 +282,17 @@ static inline void pci_rescan(void) {
+ 	pci_rescan_buses(&pci_root_buses);
+ }
+ 
++/* called from the single-threaded workqueue handler to rescan all pci buses */
++static void pci_rescan_worker(struct work_struct *work)
++{
++	pci_rescan();
++}
+ 
+ static int enable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	/* mis-use enable_slot for rescanning of the pci bus */
+-	pci_rescan();
++	cancel_work_sync(&pci_rescan_work);
++	queue_work(dummyphp_wq, &pci_rescan_work);
+ 	return -ENODEV;
+ }
+ 
+@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot)
+ 		err("Can't remove PCI devices with other PCI devices behind it yet.\n");
+ 		return -ENODEV;
+ 	}
++	if (test_and_set_bit(0, &dslot->removed)) {
++		dbg("Slot already scheduled for removal\n");
++		return -ENODEV;
++	}
+ 	/* search for subfunctions and disable them first */
+ 	if (!(dslot->dev->devfn & 7)) {
+ 		for (func = 1; func < 8; func++) {
+@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot)
+ 	/* remove the device from the pci core */
+ 	pci_remove_bus_device(dslot->dev);
+ 
+-	/* blow away this sysfs entry and other parts. */
+-	remove_slot(dslot);
++	/* queue work item to blow away this sysfs entry and other parts. */
++	INIT_WORK(&dslot->remove_work, remove_slot_worker);
++	queue_work(dummyphp_wq, &dslot->remove_work);
+ 
+ 	return 0;
+ }
+@@ -340,6 +366,7 @@ static void cleanup_slots (void)
+ 	struct list_head *next;
+ 	struct dummy_slot *dslot;
+ 
++	destroy_workqueue(dummyphp_wq);
+ 	list_for_each_safe (tmp, next, &slot_list) {
+ 		dslot = list_entry (tmp, struct dummy_slot, node);
+ 		remove_slot(dslot);
+@@ -351,6 +378,10 @@ static int __init dummyphp_init(void)
+ {
+ 	info(DRIVER_DESC "\n");
+ 
++	dummyphp_wq = create_singlethread_workqueue(MY_NAME);
++	if (!dummyphp_wq)
++		return -ENOMEM;
++
+ 	return pci_scan_buses();
+ }
+ 
+diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
+index a90c28d..87b6b8b 100644
+--- a/drivers/pci/hotplug/ibmphp_core.c
++++ b/drivers/pci/hotplug/ibmphp_core.c
+@@ -761,10 +761,13 @@ static void ibm_unconfigure_device(struct pci_func *func)
+ 	debug("func->device << 3 | 0x0  = %x\n", func->device << 3 | 0x0);
+ 
+ 	for (j = 0; j < 0x08; j++) {
+-		temp = pci_find_slot(func->busno, (func->device << 3) | j);
+-		if (temp)
++		temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
++		if (temp) {
+ 			pci_remove_bus_device(temp);
++			pci_dev_put(temp);
++		}
+ 	}
++	pci_dev_put(func->dev);
+ }
+ 
+ /*
+@@ -823,7 +826,7 @@ static int ibm_configure_device(struct pci_func *func)
+ 	if (!(bus_structure_fixup(func->busno)))
+ 		flag = 1;
+ 	if (func->dev == NULL)
+-		func->dev = pci_find_slot(func->busno,
++		func->dev = pci_get_bus_and_slot(func->busno,
+ 				PCI_DEVFN(func->device, func->function));
+ 
+ 	if (func->dev == NULL) {
+@@ -836,7 +839,7 @@ static int ibm_configure_device(struct pci_func *func)
+ 		if (num)
+ 			pci_bus_add_devices(bus);
+ 
+-		func->dev = pci_find_slot(func->busno,
++		func->dev = pci_get_bus_and_slot(func->busno,
+ 				PCI_DEVFN(func->device, func->function));
+ 		if (func->dev == NULL) {
+ 			err("ERROR... : pci_dev still NULL\n");
 diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
-index 01c351c..47bb0e1 100644
+index 01c351c..dd59a05 100644
 --- a/drivers/pci/hotplug/pci_hotplug_core.c
 +++ b/drivers/pci/hotplug/pci_hotplug_core.c
 @@ -61,7 +61,7 @@ static int debug;
@@ -655867,7 +679685,22 @@
  /* these strings match up with the values in pci_bus_speed */
  static char *pci_bus_speed_strings[] = {
  	"33 MHz PCI",		/* 0x00 */
-@@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot)
+@@ -139,7 +137,7 @@ static int get_##name (struct hotplug_slot *slot, type *value)		\
+ 	int retval = 0;							\
+ 	if (try_module_get(ops->owner)) {				\
+ 		if (ops->get_##name)					\
+-			retval = ops->get_##name (slot, value);		\
++			retval = ops->get_##name(slot, value);		\
+ 		else							\
+ 			*value = slot->info->name;			\
+ 		module_put(ops->owner);					\
+@@ -627,23 +625,24 @@ int pci_hp_register (struct hotplug_slot *slot)
+ 	if ((slot->info == NULL) || (slot->ops == NULL))
+ 		return -EINVAL;
+ 	if (slot->release == NULL) {
+-		dbg("Why are you trying to register a hotplug slot"
++		dbg("Why are you trying to register a hotplug slot "
+ 		    "without a proper release function?\n");
  		return -EINVAL;
  	}
  
@@ -655952,6 +679785,684 @@
  EXPORT_SYMBOL_GPL(pci_hp_register);
  EXPORT_SYMBOL_GPL(pci_hp_deregister);
  EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
+diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
+index 7959c22..ca656b2 100644
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -82,24 +82,18 @@ struct event_info {
+ };
+ 
+ struct controller {
+-	struct controller *next;
+ 	struct mutex crit_sect;		/* critical section mutex */
+ 	struct mutex ctrl_lock;		/* controller lock */
+ 	int num_slots;			/* Number of slots on ctlr */
+ 	int slot_num_inc;		/* 1 or -1 */
+ 	struct pci_dev *pci_dev;
+ 	struct list_head slot_list;
+-	struct slot *slot;
+ 	struct hpc_ops *hpc_ops;
+ 	wait_queue_head_t queue;	/* sleep & wake process */
+-	u8 bus;
+-	u8 device;
+-	u8 function;
+ 	u8 slot_device_offset;
+ 	u32 first_slot;		/* First physical slot number */  /* PCIE only has 1 slot */
+ 	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+ 	u8 ctrlcap;
+-	u16 vendor_id;
+ 	u8 cap_base;
+ 	struct timer_list poll_timer;
+ 	volatile int cmd_busy;
+@@ -161,6 +155,9 @@ extern int pciehp_configure_device(struct slot *p_slot);
+ extern int pciehp_unconfigure_device(struct slot *p_slot);
+ extern void pciehp_queue_pushbutton_work(struct work_struct *work);
+ int pcie_init(struct controller *ctrl, struct pcie_device *dev);
++int pciehp_enable_slot(struct slot *p_slot);
++int pciehp_disable_slot(struct slot *p_slot);
++int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev);
+ 
+ static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
+ {
+diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
+index 6462ac3..7f4836b 100644
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -453,13 +453,9 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
+ 
+ 	pci_set_drvdata(pdev, ctrl);
+ 
+-	ctrl->bus = pdev->bus->number;  /* ctrl bus */
+-	ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
+-
+-	ctrl->device = PCI_SLOT(pdev->devfn);
+-	ctrl->function = PCI_FUNC(pdev->devfn);
+-	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
+-		ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
++	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
++	    __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn),
++	    PCI_FUNC(pdev->devfn), pdev->irq);
+ 
+ 	/* Setup the slot information structures */
+ 	rc = init_slots(ctrl);
+@@ -471,6 +467,11 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
+ 	t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
+ 
+ 	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
++	if (value) {
++		rc = pciehp_enable_slot(t_slot);
++		if (rc)	/* -ENODEV: shouldn't happen, but deal with it */
++			value = 0;
++	}
+ 	if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
+ 		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
+ 		if (rc)
+@@ -509,6 +510,24 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
+ static int pciehp_resume (struct pcie_device *dev)
+ {
+ 	printk("%s ENTRY\n", __FUNCTION__);
++	if (pciehp_force) {
++		struct pci_dev *pdev = dev->port;
++		struct controller *ctrl = pci_get_drvdata(pdev);
++		struct slot *t_slot;
++		u8 status;
++
++		/* reinitialize the chipset's event detection logic */
++		pcie_init_hardware_part2(ctrl, dev);
++
++		t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
++
++		/* Check if slot is occupied */
++		t_slot->hpc_ops->get_adapter_status(t_slot, &status);
++		if (status)
++			pciehp_enable_slot(t_slot);
++		else
++			pciehp_disable_slot(t_slot);
++	}
+ 	return 0;
+ }
+ #endif
+diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
+index f1e0966..b23061c 100644
+--- a/drivers/pci/hotplug/pciehp_ctrl.c
++++ b/drivers/pci/hotplug/pciehp_ctrl.c
+@@ -37,8 +37,6 @@
+ #include "pciehp.h"
+ 
+ static void interrupt_event_handler(struct work_struct *work);
+-static int pciehp_enable_slot(struct slot *p_slot);
+-static int pciehp_disable_slot(struct slot *p_slot);
+ 
+ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
+ {
+@@ -197,12 +195,6 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+ 			    __FUNCTION__);
+ 			return;
+ 		}
+-		/*
+-		 * After turning power off, we must wait for at least
+-		 * 1 second before taking any action that relies on
+-		 * power having been removed from the slot/adapter.
+-		 */
+-		msleep(1000);
+ 	}
+ }
+ 
+@@ -215,15 +207,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+  */
+ static int board_added(struct slot *p_slot)
+ {
+-	u8 hp_slot;
+ 	int retval = 0;
+ 	struct controller *ctrl = p_slot->ctrl;
+ 
+-	hp_slot = p_slot->device - ctrl->slot_device_offset;
+-
+ 	dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
+ 			__FUNCTION__, p_slot->device,
+-			ctrl->slot_device_offset, hp_slot);
++			ctrl->slot_device_offset, p_slot->hp_slot);
+ 
+ 	if (POWER_CTRL(ctrl->ctrlcap)) {
+ 		/* Power on slot */
+@@ -281,8 +270,6 @@ err_exit:
+  */
+ static int remove_board(struct slot *p_slot)
+ {
+-	u8 device;
+-	u8 hp_slot;
+ 	int retval = 0;
+ 	struct controller *ctrl = p_slot->ctrl;
+ 
+@@ -290,11 +277,7 @@ static int remove_board(struct slot *p_slot)
+ 	if (retval)
+ 		return retval;
+ 
+-	device = p_slot->device;
+-	hp_slot = p_slot->device - ctrl->slot_device_offset;
+-	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+-
+-	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
++	dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot);
+ 
+ 	if (POWER_CTRL(ctrl->ctrlcap)) {
+ 		/* power off slot */
+@@ -621,12 +604,6 @@ int pciehp_disable_slot(struct slot *p_slot)
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -EINVAL;
+ 		}
+-		/*
+-		 * After turning power off, we must wait for at least
+-		 * 1 second before taking any action that relies on
+-		 * power having been removed from the slot/adapter.
+-		 */
+-		msleep(1000);
+ 	}
+ 
+ 	ret = remove_board(p_slot);
+diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
+index 06d025b..6eba9b2 100644
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot)
+ 	return retval;
+ }
+ 
++static inline int pcie_mask_bad_dllp(struct controller *ctrl)
++{
++	struct pci_dev *dev = ctrl->pci_dev;
++	int pos;
++	u32 reg;
++
++	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
++	if (!pos)
++		return 0;
++	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
++	if (reg & PCI_ERR_COR_BAD_DLLP)
++		return 0;
++	reg |= PCI_ERR_COR_BAD_DLLP;
++	pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
++	return 1;
++}
++
++static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
++{
++	struct pci_dev *dev = ctrl->pci_dev;
++	u32 reg;
++	int pos;
++
++	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
++	if (!pos)
++		return;
++	pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
++	if (!(reg & PCI_ERR_COR_BAD_DLLP))
++		return;
++	reg &= ~PCI_ERR_COR_BAD_DLLP;
++	pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
++}
++
+ static int hpc_power_off_slot(struct slot * slot)
+ {
+ 	struct controller *ctrl = slot->ctrl;
+ 	u16 slot_cmd;
+ 	u16 cmd_mask;
+ 	int retval = 0;
++	int changed;
+ 
+ 	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+ 
++	/*
++	 * Set Bad DLLP Mask bit in Correctable Error Mask
++	 * Register. This is the workaround against Bad DLLP error
++	 * that sometimes happens during turning power off the slot
++	 * which conforms to PCI Express 1.0a spec.
++	 */
++	changed = pcie_mask_bad_dllp(ctrl);
++
+ 	slot_cmd = POWER_OFF;
+ 	cmd_mask = PWR_CTRL;
+ 	/*
+@@ -674,6 +716,16 @@ static int hpc_power_off_slot(struct slot * slot)
+ 	dbg("%s: SLOTCTRL %x write cmd %x\n",
+ 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ 
++	/*
++	 * After turning power off, we must wait for at least 1 second
++	 * before taking any action that relies on power having been
++	 * removed from the slot/adapter.
++	 */
++	msleep(1000);
++
++	if (changed)
++		pcie_unmask_bad_dllp(ctrl);
++
+ 	return retval;
+ }
+ 
+@@ -1067,13 +1119,143 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
+ }
+ #endif
+ 
+-int pcie_init(struct controller * ctrl, struct pcie_device *dev)
++static int pcie_init_hardware_part1(struct controller *ctrl,
++				    struct pcie_device *dev)
++{
++	int rc;
++	u16 temp_word;
++	u32 slot_cap;
++	u16 slot_status;
++
++	rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
++	if (rc) {
++		err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
++		return -1;
++	}
++
++	/* Mask Hot-plug Interrupt Enable */
++	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
++	if (rc) {
++		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
++		return -1;
++	}
++
++	dbg("%s: SLOTCTRL %x value read %x\n",
++	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
++	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
++		0x00;
++
++	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
++	if (rc) {
++		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
++		return -1;
++	}
++
++	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
++	if (rc) {
++		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
++		return -1;
++	}
++
++	temp_word = 0x1F; /* Clear all events */
++	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
++	if (rc) {
++		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
++		return -1;
++	}
++	return 0;
++}
++
++int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
+ {
+ 	int rc;
+ 	u16 temp_word;
+-	u16 cap_reg;
+ 	u16 intr_enable = 0;
+ 	u32 slot_cap;
++	u16 slot_status;
++
++	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
++	if (rc) {
++		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
++		goto abort;
++	}
++
++	intr_enable = intr_enable | PRSN_DETECT_ENABLE;
++
++	rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
++	if (rc) {
++		err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
++		goto abort;
++	}
++
++	if (ATTN_BUTTN(slot_cap))
++		intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
++
++	if (POWER_CTRL(slot_cap))
++		intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
++
++	if (MRL_SENS(slot_cap))
++		intr_enable = intr_enable | MRL_DETECT_ENABLE;
++
++	temp_word = (temp_word & ~intr_enable) | intr_enable;
++
++	if (pciehp_poll_mode) {
++		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
++	} else {
++		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
++	}
++
++	/*
++	 * Unmask Hot-plug Interrupt Enable for the interrupt
++	 * notification mechanism case.
++	 */
++	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
++	if (rc) {
++		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
++		goto abort;
++	}
++	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
++	if (rc) {
++		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
++		goto abort_disable_intr;
++	}
++
++	temp_word =  0x1F; /* Clear all events */
++	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
++	if (rc) {
++		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
++		goto abort_disable_intr;
++	}
++
++	if (pciehp_force) {
++		dbg("Bypassing BIOS check for pciehp use on %s\n",
++				pci_name(ctrl->pci_dev));
++	} else {
++		rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
++		if (rc)
++			goto abort_disable_intr;
++	}
++
++	return 0;
++
++	/* We end up here for the many possible ways to fail this API. */
++abort_disable_intr:
++	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
++	if (!rc) {
++		temp_word &= ~(intr_enable | HP_INTR_ENABLE);
++		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
++	}
++	if (rc)
++		err("%s : disabling interrupts failed\n", __FUNCTION__);
++abort:
++	return -1;
++}
++
++int pcie_init(struct controller *ctrl, struct pcie_device *dev)
++{
++	int rc;
++	u16 cap_reg;
++	u32 slot_cap;
+ 	int cap_base;
+ 	u16 slot_status, slot_ctrl;
+ 	struct pci_dev *pdev;
+@@ -1084,9 +1266,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 	dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
+ 			__FUNCTION__, pdev->vendor, pdev->device);
+ 
+-	if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
++	cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
++	if (cap_base == 0) {
+ 		dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 
+ 	ctrl->cap_base = cap_base;
+@@ -1096,7 +1279,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 	rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
+ 	if (rc) {
+ 		err("%s: Cannot read CAPREG register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 	dbg("%s: CAPREG offset %x cap_reg %x\n",
+ 	    __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
+@@ -1106,26 +1289,26 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 		&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
+ 		dbg("%s : This is not a root port or the port is not "
+ 		    "connected to a slot\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 
+ 	rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
+ 	if (rc) {
+ 		err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 	dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+ 	    __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
+ 
+ 	if (!(slot_cap & HP_CAP)) {
+ 		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 	/* For debugging purpose */
+ 	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ 	if (rc) {
+ 		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 	dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+ 	    __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
+@@ -1133,7 +1316,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 	rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ 	if (rc) {
+ 		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
++		goto abort;
+ 	}
+ 	dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+ 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
+@@ -1161,36 +1344,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 	ctrl->first_slot = slot_cap >> 19;
+ 	ctrl->ctrlcap = slot_cap & 0x0000007f;
+ 
+-	/* Mask Hot-plug Interrupt Enable */
+-	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+-	if (rc) {
+-		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
+-	}
+-
+-	dbg("%s: SLOTCTRL %x value read %x\n",
+-	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
+-	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+-		0x00;
+-
+-	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+-	if (rc) {
+-		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
+-	}
+-
+-	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+-	if (rc) {
+-		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
+-	}
+-
+-	temp_word = 0x1F; /* Clear all events */
+-	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+-	if (rc) {
+-		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+-		goto abort_free_ctlr;
+-	}
++	rc = pcie_init_hardware_part1(ctrl, dev);
++	if (rc)
++		goto abort;
+ 
+ 	if (pciehp_poll_mode) {
+ 		/* Install interrupt polling timer. Start with 10 sec delay */
+@@ -1206,7 +1362,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 		if (rc) {
+ 			err("Can't get irq %d for the hotplug controller\n",
+ 			    ctrl->pci_dev->irq);
+-			goto abort_free_ctlr;
++			goto abort;
+ 		}
+ 	}
+ 	dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
+@@ -1224,82 +1380,16 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+ 		}
+ 	}
+ 
+-	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+-	if (rc) {
+-		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+-		goto abort_free_irq;
++	rc = pcie_init_hardware_part2(ctrl, dev);
++	if (rc == 0) {
++		ctrl->hpc_ops = &pciehp_hpc_ops;
++		return 0;
+ 	}
+-
+-	intr_enable = intr_enable | PRSN_DETECT_ENABLE;
+-
+-	if (ATTN_BUTTN(slot_cap))
+-		intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
+-
+-	if (POWER_CTRL(slot_cap))
+-		intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
+-
+-	if (MRL_SENS(slot_cap))
+-		intr_enable = intr_enable | MRL_DETECT_ENABLE;
+-
+-	temp_word = (temp_word & ~intr_enable) | intr_enable;
+-
+-	if (pciehp_poll_mode) {
+-		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
+-	} else {
+-		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+-	}
+-
+-	/*
+-	 * Unmask Hot-plug Interrupt Enable for the interrupt
+-	 * notification mechanism case.
+-	 */
+-	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+-	if (rc) {
+-		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+-		goto abort_free_irq;
+-	}
+-	rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+-	if (rc) {
+-		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+-		goto abort_disable_intr;
+-	}
+-
+-	temp_word =  0x1F; /* Clear all events */
+-	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+-	if (rc) {
+-		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+-		goto abort_disable_intr;
+-	}
+-
+-	if (pciehp_force) {
+-		dbg("Bypassing BIOS check for pciehp use on %s\n",
+-				pci_name(ctrl->pci_dev));
+-	} else {
+-		rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
+-		if (rc)
+-			goto abort_disable_intr;
+-	}
+-
+-	ctrl->hpc_ops = &pciehp_hpc_ops;
+-
+-	return 0;
+-
+-	/* We end up here for the many possible ways to fail this API. */
+-abort_disable_intr:
+-	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+-	if (!rc) {
+-		temp_word &= ~(intr_enable | HP_INTR_ENABLE);
+-		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+-	}
+-	if (rc)
+-		err("%s : disabling interrupts failed\n", __FUNCTION__);
+-
+ abort_free_irq:
+ 	if (pciehp_poll_mode)
+ 		del_timer_sync(&ctrl->poll_timer);
+ 	else
+ 		free_irq(ctrl->pci_dev->irq, ctrl);
+-
+-abort_free_ctlr:
++abort:
+ 	return -1;
+ }
+diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
+index c424ade..dd50713 100644
+--- a/drivers/pci/hotplug/pciehp_pci.c
++++ b/drivers/pci/hotplug/pciehp_pci.c
+@@ -105,12 +105,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
+ 	}
+ 
+ 	/* Find Advanced Error Reporting Enhanced Capability */
+-	pos = 256;
+-	do {
+-		pci_read_config_dword(dev, pos, &reg32);
+-		if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
+-			break;
+-	} while ((pos = PCI_EXT_CAP_NEXT(reg32)));
++	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ 	if (!pos)
+ 		return;
+ 
+@@ -248,11 +243,15 @@ int pciehp_unconfigure_device(struct slot *p_slot)
+ 	u8 bctl = 0;
+ 	u8 presence = 0;
+ 	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
++	u16 command;
+ 
+ 	dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
+ 				p_slot->device);
++	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence);
++	if (ret)
++		presence = 0;
+ 
+-	for (j=0; j<8 ; j++) {
++	for (j = 0; j < 8; j++) {
+ 		struct pci_dev* temp = pci_get_slot(parent,
+ 				(p_slot->device << 3) | j);
+ 		if (!temp)
+@@ -263,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot)
+ 			pci_dev_put(temp);
+ 			continue;
+ 		}
+-		if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+-			ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+-								&presence);
+-			if (!ret && presence) {
+-				pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+-					&bctl);
+-				if (bctl & PCI_BRIDGE_CTL_VGA) {
+-					err("Cannot remove display device %s\n",
+-						pci_name(temp));
+-					pci_dev_put(temp);
+-					continue;
+-				}
++		if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
++			pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
++			if (bctl & PCI_BRIDGE_CTL_VGA) {
++				err("Cannot remove display device %s\n",
++				    pci_name(temp));
++				pci_dev_put(temp);
++				continue;
+ 			}
+ 		}
+ 		pci_remove_bus_device(temp);
++		/*
++		 * Ensure that no new Requests will be generated from
++		 * the device.
++		 */
++		if (presence) {
++			pci_read_config_word(temp, PCI_COMMAND, &command);
++			command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
++			command |= PCI_COMMAND_INTX_DISABLE;
++			pci_write_config_word(temp, PCI_COMMAND, command);
++		}
+ 		pci_dev_put(temp);
+ 	}
+ 	/*
+@@ -288,4 +292,3 @@ int pciehp_unconfigure_device(struct slot *p_slot)
+ 
+ 	return rc;
+ }
+-
 diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
 index b169b0e..191954b 100644
 --- a/drivers/pci/hotplug/rpadlpar_core.c
@@ -656134,8 +680645,351 @@
 +	sysfs_remove_group(dlpar_kobj, &dlpar_attr_group);
 +	kobject_put(dlpar_kobj);
  }
+diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
+index c822a77..7d5921b 100644
+--- a/drivers/pci/hotplug/rpaphp.h
++++ b/drivers/pci/hotplug/rpaphp.h
+@@ -74,7 +74,6 @@ struct slot {
+ 	u32 type;
+ 	u32 power_domain;
+ 	char *name;
+-	char *location;
+ 	struct device_node *dn;
+ 	struct pci_bus *bus;
+ 	struct list_head *pci_devs;
+diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
+index 0de8453..6571e9b 100644
+--- a/drivers/pci/hotplug/rpaphp_pci.c
++++ b/drivers/pci/hotplug/rpaphp_pci.c
+@@ -64,19 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state)
+ 	return rc;
+ }
+ 
+-static void set_slot_name(struct slot *slot)
+-{
+-	struct pci_bus *bus = slot->bus;
+-	struct pci_dev *bridge;
+-
+-	bridge = bus->self;
+-	if (bridge)
+-		strcpy(slot->name, pci_name(bridge));
+-	else
+-		sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus),
+-			bus->number);
+-}
+-
+ /**
+  * rpaphp_enable_slot - record slot state, config pci device
+  * @slot: target &slot
+@@ -115,7 +102,6 @@ int rpaphp_enable_slot(struct slot *slot)
+ 	info->adapter_status = EMPTY;
+ 	slot->bus = bus;
+ 	slot->pci_devs = &bus->devices;
+-	set_slot_name(slot);
+ 
+ 	/* if there's an adapter in the slot, go add the pci devices */
+ 	if (state == PRESENT) {
+diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
+index d4ee872..8ad3deb 100644
+--- a/drivers/pci/hotplug/rpaphp_slot.c
++++ b/drivers/pci/hotplug/rpaphp_slot.c
+@@ -33,23 +33,31 @@
+ #include <asm/rtas.h>
+ #include "rpaphp.h"
+ 
+-static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
++static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf)
+ {
+-	char *value;
+-	int retval = -ENOENT;
++	int retval;
+ 	struct slot *slot = (struct slot *)php_slot->private;
++	struct pci_bus *bus;
+ 
+ 	if (!slot)
+-		return retval;
++		return -ENOENT;
++
++	bus = slot->bus;
++	if (!bus)
++		return -ENOENT;
++
++	if (bus->self)
++		retval = sprintf(buf, pci_name(bus->self));
++	else
++		retval = sprintf(buf, "%04x:%02x:00.0",
++		        pci_domain_nr(bus), bus->number);
+ 
+-	value = slot->location;
+-	retval = sprintf (buf, "%s\n", value);
+ 	return retval;
+ }
+ 
+-static struct hotplug_slot_attribute php_attr_location = {
+-	.attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
+-	.show = location_read_file,
++static struct hotplug_slot_attribute php_attr_address = {
++	.attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
++	.show = address_read_file,
+ };
+ 
+ /* free up the memory used by a slot */
+@@ -64,7 +72,6 @@ void dealloc_slot_struct(struct slot *slot)
+ 	kfree(slot->hotplug_slot->info);
+ 	kfree(slot->hotplug_slot->name);
+ 	kfree(slot->hotplug_slot);
+-	kfree(slot->location);
+ 	kfree(slot);
+ }
+ 
+@@ -83,16 +90,13 @@ struct slot *alloc_slot_struct(struct device_node *dn,
+ 					   GFP_KERNEL);
+ 	if (!slot->hotplug_slot->info)
+ 		goto error_hpslot;
+-	slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
++	slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
+ 	if (!slot->hotplug_slot->name)
+ 		goto error_info;	
+-	slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
+-	if (!slot->location)
+-		goto error_name;
+ 	slot->name = slot->hotplug_slot->name;
++	strcpy(slot->name, drc_name);
+ 	slot->dn = dn;
+ 	slot->index = drc_index;
+-	strcpy(slot->location, drc_name);
+ 	slot->power_domain = power_domain;
+ 	slot->hotplug_slot->private = slot;
+ 	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
+@@ -100,8 +104,6 @@ struct slot *alloc_slot_struct(struct device_node *dn,
+ 	
+ 	return (slot);
+ 
+-error_name:
+-	kfree(slot->hotplug_slot->name);
+ error_info:
+ 	kfree(slot->hotplug_slot->info);
+ error_hpslot:
+@@ -133,8 +135,8 @@ int rpaphp_deregister_slot(struct slot *slot)
+ 
+ 	list_del(&slot->rpaphp_slot_list);
+ 	
+-	/* remove "phy_location" file */
+-	sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr);
++	/* remove "address" file */
++	sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr);
+ 
+ 	retval = pci_hp_deregister(php_slot);
+ 	if (retval)
+@@ -166,8 +168,8 @@ int rpaphp_register_slot(struct slot *slot)
+ 		return retval;
+ 	}
+ 
+-	/* create "phy_location" file */
+-	retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr);
++	/* create "address" file */
++	retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr);
+ 	if (retval) {
+ 		err("sysfs_create_file failed with error %d\n", retval);
+ 		goto sysfs_fail;
+@@ -175,8 +177,7 @@ int rpaphp_register_slot(struct slot *slot)
+ 
+ 	/* add slot to our internal list */
+ 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
+-	info("Slot [%s](PCI location=%s) registered\n", slot->name,
+-			slot->location);
++	info("Slot [%s] registered\n", slot->name);
+ 	return 0;
+ 
+ sysfs_fail:
+diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
+index 5183a45..e8aa138 100644
+--- a/drivers/pci/hotplug/shpchp_hpc.c
++++ b/drivers/pci/hotplug/shpchp_hpc.c
+@@ -597,7 +597,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
+ 	cleanup_slots(ctrl);
+ 
+ 	/*
+-	 * Mask SERR and System Interrut generation
++	 * Mask SERR and System Interrupt generation
+ 	 */
+ 	serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
+ 	serr_int |= (GLOBAL_INTR_MASK  | GLOBAL_SERR_MASK |
+diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
+index e079a52..4e01df9 100644
+--- a/drivers/pci/intel-iommu.c
++++ b/drivers/pci/intel-iommu.c
+@@ -1781,7 +1781,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
+ 		/*
+ 		 * First try to allocate an io virtual address in
+ 		 * DMA_32BIT_MASK and if that fails then try allocating
+-		 * from higer range
++		 * from higher range
+ 		 */
+ 		iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
+ 		if (!iova)
+diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
+index 07c9f09..26938da 100644
+--- a/drivers/pci/msi.c
++++ b/drivers/pci/msi.c
+@@ -25,6 +25,51 @@
+ 
+ static int pci_msi_enable = 1;
+ 
++/* Arch hooks */
++
++int __attribute__ ((weak))
++arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
++{
++	return 0;
++}
++
++int __attribute__ ((weak))
++arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
++{
++	return 0;
++}
++
++int __attribute__ ((weak))
++arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
++{
++	struct msi_desc *entry;
++	int ret;
++
++	list_for_each_entry(entry, &dev->msi_list, list) {
++		ret = arch_setup_msi_irq(dev, entry);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
++{
++	return;
++}
++
++void __attribute__ ((weak))
++arch_teardown_msi_irqs(struct pci_dev *dev)
++{
++	struct msi_desc *entry;
++
++	list_for_each_entry(entry, &dev->msi_list, list) {
++		if (entry->irq != 0)
++			arch_teardown_msi_irq(entry->irq);
++	}
++}
++
+ static void msi_set_enable(struct pci_dev *dev, int enable)
+ {
+ 	int pos;
+@@ -230,7 +275,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
+ 		pci_intx(dev, enable);
+ }
+ 
+-#ifdef CONFIG_PM
+ static void __pci_restore_msi_state(struct pci_dev *dev)
+ {
+ 	int pos;
+@@ -288,7 +332,7 @@ void pci_restore_msi_state(struct pci_dev *dev)
+ 	__pci_restore_msi_state(dev);
+ 	__pci_restore_msix_state(dev);
+ }
+-#endif	/* CONFIG_PM */
++EXPORT_SYMBOL_GPL(pci_restore_msi_state);
+ 
+ /**
+  * msi_capability_init - configure device's MSI capability structure
+@@ -683,49 +727,3 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
+ {
+ 	INIT_LIST_HEAD(&dev->msi_list);
+ }
+-
+-
+-/* Arch hooks */
+-
+-int __attribute__ ((weak))
+-arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+-{
+-	return 0;
+-}
+-
+-int __attribute__ ((weak))
+-arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
+-{
+-	return 0;
+-}
+-
+-int __attribute__ ((weak))
+-arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+-{
+-	struct msi_desc *entry;
+-	int ret;
+-
+-	list_for_each_entry(entry, &dev->msi_list, list) {
+-		ret = arch_setup_msi_irq(dev, entry);
+-		if (ret)
+-			return ret;
+-	}
+-
+-	return 0;
+-}
+-
+-void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
+-{
+-	return;
+-}
+-
+-void __attribute__ ((weak))
+-arch_teardown_msi_irqs(struct pci_dev *dev)
+-{
+-	struct msi_desc *entry;
+-
+-	list_for_each_entry(entry, &dev->msi_list, list) {
+-		if (entry->irq != 0)
+-			arch_teardown_msi_irq(entry->irq);
+-	}
+-}
+diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
+index 5c6a5d0..e569645 100644
+--- a/drivers/pci/pci-acpi.c
++++ b/drivers/pci/pci-acpi.c
+@@ -156,13 +156,13 @@ run_osc_out:
+ }
+ 
+ /**
+- * pci_osc_support_set - register OS support to Firmware
++ * __pci_osc_support_set - register OS support to Firmware
+  * @flags: OS support bits
+  *
+  * Update OS support fields and doing a _OSC Query to obtain an update
+  * from Firmware on supported control bits.
+  **/
+-acpi_status pci_osc_support_set(u32 flags)
++acpi_status __pci_osc_support_set(u32 flags, const char *hid)
+ {
+ 	u32 temp;
+ 	acpi_status retval;
+@@ -176,7 +176,7 @@ acpi_status pci_osc_support_set(u32 flags)
+ 	temp = ctrlset_buf[OSC_CONTROL_TYPE];
+ 	ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+ 	ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+-	acpi_get_devices ( PCI_ROOT_HID_STRING,
++	acpi_get_devices(hid,
+ 			acpi_query_osc,
+ 			ctrlset_buf,
+ 			(void **) &retval );
+@@ -188,7 +188,6 @@ acpi_status pci_osc_support_set(u32 flags)
+ 	}
+ 	return AE_OK;
+ }
+-EXPORT_SYMBOL(pci_osc_support_set);
+ 
+ /**
+  * pci_osc_control_set - commit requested control to Firmware
 diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index 6d1a216..c4fa35d 100644
+index 6d1a216..e571c72 100644
 --- a/drivers/pci/pci-driver.c
 +++ b/drivers/pci/pci-driver.c
 @@ -1,6 +1,11 @@
@@ -656174,7 +681028,22 @@
  #endif
  
  /**
-@@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev)
+@@ -177,13 +186,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
+ 	    set_cpus_allowed(current, node_to_cpumask(node));
+ 	/* And set default memory allocation policy */
+ 	oldpol = current->mempolicy;
+-	current->mempolicy = &default_policy;
+-	mpol_get(current->mempolicy);
++	current->mempolicy = NULL;	/* fall back to system default policy */
+ #endif
+ 	error = drv->probe(dev, id);
+ #ifdef CONFIG_NUMA
+ 	set_cpus_allowed(current, oldmask);
+-	mpol_free(current->mempolicy);
+ 	current->mempolicy = oldpol;
+ #endif
+ 	return error;
+@@ -352,50 +359,6 @@ static void pci_device_shutdown(struct device *dev)
  		drv->shutdown(pci_dev);
  }
  
@@ -656225,7 +681094,7 @@
  /**
   * __pci_register_driver - register a new pci driver
   * @drv: the driver structure to register
-@@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+@@ -417,7 +380,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
  	drv->driver.bus = &pci_bus_type;
  	drv->driver.owner = owner;
  	drv->driver.mod_name = mod_name;
@@ -656233,7 +681102,7 @@
  
  	spin_lock_init(&drv->dynids.lock);
  	INIT_LIST_HEAD(&drv->dynids.list);
-@@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+@@ -447,6 +409,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
  void
  pci_unregister_driver(struct pci_driver *drv)
  {
@@ -656241,34 +681110,2914 @@
  	driver_unregister(&drv->driver);
  	pci_free_dynids(drv);
  }
-diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
-index c5ca313..5fd5852 100644
---- a/drivers/pci/probe.c
-+++ b/drivers/pci/probe.c
-@@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void)
- 	struct klist_node *n;
- 	struct device *dev;
- 	struct pci_dev *pdev;
-+	struct klist *device_klist;
+diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
+index 7d18773..abf4203 100644
+--- a/drivers/pci/pci-sysfs.c
++++ b/drivers/pci/pci-sysfs.c
+@@ -21,6 +21,7 @@
+ #include <linux/topology.h>
+ #include <linux/mm.h>
+ #include <linux/capability.h>
++#include <linux/aspm.h>
+ #include "pci.h"
  
--	spin_lock(&pci_bus_type.klist_devices.k_lock);
--	list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
-+	device_klist = bus_get_device_klist(&pci_bus_type);
+ static int sysfs_initialized;	/* = 0 */
+@@ -358,7 +359,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 		   char *buf, loff_t off, size_t count)
+ {
+         struct pci_bus *bus = to_pci_bus(container_of(kobj,
+-                                                      struct class_device,
++                                                      struct device,
+ 						      kobj));
+ 
+         /* Only support 1, 2 or 4 byte accesses */
+@@ -383,7 +384,7 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
+ 		    char *buf, loff_t off, size_t count)
+ {
+         struct pci_bus *bus = to_pci_bus(container_of(kobj,
+-						      struct class_device,
++						      struct device,
+ 						      kobj));
+         /* Only support 1, 2 or 4 byte accesses */
+         if (count != 1 && count != 2 && count != 4)
+@@ -407,7 +408,7 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
+                     struct vm_area_struct *vma)
+ {
+         struct pci_bus *bus = to_pci_bus(container_of(kobj,
+-                                                      struct class_device,
++                                                      struct device,
+ 						      kobj));
+ 
+         return pci_mmap_legacy_page_range(bus, vma);
+@@ -650,6 +651,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
+ 	if (pcibios_add_platform_entries(pdev))
+ 		goto err_rom_file;
+ 
++	pcie_aspm_create_sysfs_dev_files(pdev);
 +
-+	spin_lock(&device_klist->k_lock);
-+	list_for_each_safe(pos, tmp, &device_klist->k_list) {
- 		n = container_of(pos, struct klist_node, n_node);
- 		dev = container_of(n, struct device, knode_bus);
- 		pdev = to_pci_dev(dev);
- 		pci_insertion_sort_klist(pdev, &sorted_devices);
- 	}
--	list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
--	spin_unlock(&pci_bus_type.klist_devices.k_lock);
-+	list_splice(&sorted_devices, &device_klist->k_list);
-+	spin_unlock(&device_klist->k_lock);
+ 	return 0;
+ 
+ err_rom_file:
+@@ -679,6 +682,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
+ 	if (!sysfs_initialized)
+ 		return;
+ 
++	pcie_aspm_remove_sysfs_dev_files(pdev);
++
+ 	if (pdev->cfg_size < 4096)
+ 		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ 	else
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 71d561f..b3e9294 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -18,6 +18,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/string.h>
+ #include <linux/log2.h>
++#include <linux/aspm.h>
+ #include <asm/dma.h>	/* isa_dma_bridge_buggy */
+ #include "pci.h"
+ 
+@@ -314,6 +315,24 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
  }
+ EXPORT_SYMBOL_GPL(pci_find_ht_capability);
  
- static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
++void pcie_wait_pending_transaction(struct pci_dev *dev)
++{
++	int pos;
++	u16 reg16;
++
++	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++	if (!pos)
++		return;
++	while (1) {
++		pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
++		if (!(reg16 & PCI_EXP_DEVSTA_TRPND))
++			break;
++		cpu_relax();
++	}
++
++}
++EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction);
++
+ /**
+  * pci_find_parent_resource - return resource region of parent bus of given region
+  * @dev: PCI device structure contains resources to be searched
+@@ -353,7 +372,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
+  * Restore the BAR values for a given device, so as to make it
+  * accessible by its driver.
+  */
+-void
++static void
+ pci_restore_bars(struct pci_dev *dev)
+ {
+ 	int i, numres;
+@@ -501,6 +520,9 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+ 	if (need_restore)
+ 		pci_restore_bars(dev);
+ 
++	if (dev->bus->self)
++		pcie_aspm_pm_state_change(dev->bus->self);
++
+ 	return 0;
+ }
+ 
+@@ -551,6 +573,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
+ 	int pos, i = 0;
+ 	struct pci_cap_saved_state *save_state;
+ 	u16 *cap;
++	int found = 0;
+ 
+ 	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ 	if (pos <= 0)
+@@ -559,6 +582,8 @@ static int pci_save_pcie_state(struct pci_dev *dev)
+ 	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ 	if (!save_state)
+ 		save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
++	else
++		found = 1;
+ 	if (!save_state) {
+ 		dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
+ 		return -ENOMEM;
+@@ -569,7 +594,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
+ 	pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
+ 	pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
+ 	pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+-	pci_add_saved_cap(dev, save_state);
++	save_state->cap_nr = PCI_CAP_ID_EXP;
++	if (!found)
++		pci_add_saved_cap(dev, save_state);
+ 	return 0;
+ }
+ 
+@@ -597,14 +624,17 @@ static int pci_save_pcix_state(struct pci_dev *dev)
+ 	int pos, i = 0;
+ 	struct pci_cap_saved_state *save_state;
+ 	u16 *cap;
++	int found = 0;
+ 
+ 	pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ 	if (pos <= 0)
+ 		return 0;
+ 
+-	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
++	save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
+ 	if (!save_state)
+ 		save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
++	else
++		found = 1;
+ 	if (!save_state) {
+ 		dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
+ 		return -ENOMEM;
+@@ -612,7 +642,9 @@ static int pci_save_pcix_state(struct pci_dev *dev)
+ 	cap = (u16 *)&save_state->data[0];
+ 
+ 	pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]);
+-	pci_add_saved_cap(dev, save_state);
++	save_state->cap_nr = PCI_CAP_ID_PCIX;
++	if (!found)
++		pci_add_saved_cap(dev, save_state);
+ 	return 0;
+ }
+ 
+@@ -713,23 +745,19 @@ int pci_reenable_device(struct pci_dev *dev)
+ 	return 0;
+ }
+ 
+-/**
+- * pci_enable_device_bars - Initialize some of a device for use
+- * @dev: PCI device to be initialized
+- * @bars: bitmask of BAR's that must be configured
+- *
+- *  Initialize device before it's used by a driver. Ask low-level code
+- *  to enable selected I/O and memory resources. Wake up the device if it
+- *  was suspended. Beware, this function can fail.
+- */
+-int
+-pci_enable_device_bars(struct pci_dev *dev, int bars)
++static int __pci_enable_device_flags(struct pci_dev *dev,
++				     resource_size_t flags)
+ {
+ 	int err;
++	int i, bars = 0;
+ 
+ 	if (atomic_add_return(1, &dev->enable_cnt) > 1)
+ 		return 0;		/* already enabled */
+ 
++	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
++		if (dev->resource[i].flags & flags)
++			bars |= (1 << i);
++
+ 	err = do_pci_enable_device(dev, bars);
+ 	if (err < 0)
+ 		atomic_dec(&dev->enable_cnt);
+@@ -737,6 +765,32 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
+ }
+ 
+ /**
++ * pci_enable_device_io - Initialize a device for use with IO space
++ * @dev: PCI device to be initialized
++ *
++ *  Initialize device before it's used by a driver. Ask low-level code
++ *  to enable I/O resources. Wake up the device if it was suspended.
++ *  Beware, this function can fail.
++ */
++int pci_enable_device_io(struct pci_dev *dev)
++{
++	return __pci_enable_device_flags(dev, IORESOURCE_IO);
++}
++
++/**
++ * pci_enable_device_mem - Initialize a device for use with Memory space
++ * @dev: PCI device to be initialized
++ *
++ *  Initialize device before it's used by a driver. Ask low-level code
++ *  to enable Memory resources. Wake up the device if it was suspended.
++ *  Beware, this function can fail.
++ */
++int pci_enable_device_mem(struct pci_dev *dev)
++{
++	return __pci_enable_device_flags(dev, IORESOURCE_MEM);
++}
++
++/**
+  * pci_enable_device - Initialize device before it's used by a driver.
+  * @dev: PCI device to be initialized
+  *
+@@ -749,7 +803,7 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
+  */
+ int pci_enable_device(struct pci_dev *dev)
+ {
+-	return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
++	return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
+ }
+ 
+ /*
+@@ -823,7 +877,8 @@ int pcim_enable_device(struct pci_dev *pdev)
+ 	dr = get_pci_dr(pdev);
+ 	if (unlikely(!dr))
+ 		return -ENOMEM;
+-	WARN_ON(!!dr->enabled);
++	if (dr->enabled)
++		return 0;
+ 
+ 	rc = pci_enable_device(pdev);
+ 	if (!rc) {
+@@ -884,6 +939,9 @@ pci_disable_device(struct pci_dev *dev)
+ 	if (atomic_sub_return(1, &dev->enable_cnt) != 0)
+ 		return;
+ 
++	/* Wait for all transactions are finished before disabling the device */
++	pcie_wait_pending_transaction(dev);
++
+ 	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+ 	if (pci_command & PCI_COMMAND_MASTER) {
+ 		pci_command &= ~PCI_COMMAND_MASTER;
+@@ -1618,9 +1676,9 @@ early_param("pci", pci_setup);
+ 
+ device_initcall(pci_init);
+ 
+-EXPORT_SYMBOL_GPL(pci_restore_bars);
+ EXPORT_SYMBOL(pci_reenable_device);
+-EXPORT_SYMBOL(pci_enable_device_bars);
++EXPORT_SYMBOL(pci_enable_device_io);
++EXPORT_SYMBOL(pci_enable_device_mem);
+ EXPORT_SYMBOL(pci_enable_device);
+ EXPORT_SYMBOL(pcim_enable_device);
+ EXPORT_SYMBOL(pcim_pin_device);
+diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
+index fc87e14..eabeb1f 100644
+--- a/drivers/pci/pci.h
++++ b/drivers/pci/pci.h
+@@ -6,8 +6,10 @@ extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
+ extern void pci_cleanup_rom(struct pci_dev *dev);
+ 
+ /* Firmware callbacks */
+-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+-extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
++extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev,
++						pm_message_t state);
++extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
++						pci_power_t state);
+ 
+ extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
+ extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
+@@ -45,12 +47,6 @@ static inline void pci_no_msi(void) { }
+ static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
+ #endif
+ 
+-#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
+-void pci_restore_msi_state(struct pci_dev *dev);
+-#else
+-static inline void pci_restore_msi_state(struct pci_dev *dev) {}
+-#endif
+-
+ #ifdef CONFIG_PCIEAER
+ void pci_no_aer(void);
+ #else
+@@ -68,14 +64,14 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
+ }
+ extern int pcie_mch_quirk;
+ extern struct device_attribute pci_dev_attrs[];
+-extern struct class_device_attribute class_device_attr_cpuaffinity;
++extern struct device_attribute dev_attr_cpuaffinity;
+ 
+ /**
+  * pci_match_one_device - Tell if a PCI device structure has a matching
+  *                        PCI device id structure
+  * @id: single PCI device id structure to match
+  * @dev: the PCI device structure to match against
+- * 
++ *
+  * Returns the matching pci_device_id structure or %NULL if there is no match.
+  */
+ static inline const struct pci_device_id *
+diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
+index 287a931..60104cf 100644
+--- a/drivers/pci/pcie/Kconfig
++++ b/drivers/pci/pcie/Kconfig
+@@ -26,3 +26,23 @@ config HOTPLUG_PCI_PCIE
+ 	  When in doubt, say N.
+ 
+ source "drivers/pci/pcie/aer/Kconfig"
++
++#
++# PCI Express ASPM
++#
++config PCIEASPM
++	bool "PCI Express ASPM support(Experimental)"
++	depends on PCI && EXPERIMENTAL
++	default y
++	help
++	  This enables PCI Express ASPM (Active State Power Management) and
++	  Clock Power Management. ASPM supports state L0/L0s/L1.
++
++	  When in doubt, say N.
++config PCIEASPM_DEBUG
++	bool "Debug PCI Express ASPM"
++	depends on PCIEASPM
++	default n
++	help
++	  This enables PCI Express ASPM debug support. It will add per-device
++	  interface to control ASPM.
+diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
+index e00fb99..11f6bb1 100644
+--- a/drivers/pci/pcie/Makefile
++++ b/drivers/pci/pcie/Makefile
+@@ -2,6 +2,9 @@
+ # Makefile for PCI-Express PORT Driver
+ #
+ 
++# Build PCI Express ASPM if needed
++obj-$(CONFIG_PCIEASPM)		+= aspm.o
++
+ pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+ 
+ obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
+diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
+index 1a1eb45..8c199ae 100644
+--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
++++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
+@@ -31,26 +31,16 @@ int aer_osc_setup(struct pcie_device *pciedev)
+ {
+ 	acpi_status status = AE_NOT_FOUND;
+ 	struct pci_dev *pdev = pciedev->port;
+-	acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev);
+-	struct pci_bus *parent;
++	acpi_handle handle = 0;
+ 
+-	while (!handle) {
+-		if (!pdev || !pdev->bus->parent)
+-			break;
+-		parent = pdev->bus->parent;
+-		if (!parent->self)
+-			/* Parent must be a host bridge */
+-			handle = acpi_get_pci_rootbridge_handle(
+-					pci_domain_nr(parent),
+-					parent->number);
+-		else
+-			handle = DEVICE_ACPI_HANDLE(
+-					&(parent->self->dev));
+-		pdev = parent->self;
+-	}
++	/* Find root host bridge */
++	while (pdev->bus && pdev->bus->self)
++		pdev = pdev->bus->self;
++	handle = acpi_get_pci_rootbridge_handle(
++		pci_domain_nr(pdev->bus), pdev->bus->number);
+ 
+ 	if (handle) {
+-		pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
++		pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+ 		status = pci_osc_control_set(handle,
+ 					OSC_PCI_EXPRESS_AER_CONTROL |
+ 					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+new file mode 100644
+index 0000000..1a5adeb
+--- /dev/null
++++ b/drivers/pci/pcie/aspm.c
+@@ -0,0 +1,802 @@
++/*
++ * File:	drivers/pci/pcie/aspm.c
++ * Enabling PCIE link L0s/L1 state and Clock Power Management
++ *
++ * Copyright (C) 2007 Intel
++ * Copyright (C) Zhang Yanmin (yanmin.zhang at intel.com)
++ * Copyright (C) Shaohua Li (shaohua.li at intel.com)
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/errno.h>
++#include <linux/pm.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/aspm.h>
++#include <acpi/acpi_bus.h>
++#include <linux/pci-acpi.h>
++#include "../pci.h"
++
++#ifdef MODULE_PARAM_PREFIX
++#undef MODULE_PARAM_PREFIX
++#endif
++#define MODULE_PARAM_PREFIX "pcie_aspm."
++
++struct endpoint_state {
++	unsigned int l0s_acceptable_latency;
++	unsigned int l1_acceptable_latency;
++};
++
++struct pcie_link_state {
++	struct list_head sibiling;
++	struct pci_dev *pdev;
++
++	/* ASPM state */
++	unsigned int support_state;
++	unsigned int enabled_state;
++	unsigned int bios_aspm_state;
++	/* upstream component */
++	unsigned int l0s_upper_latency;
++	unsigned int l1_upper_latency;
++	/* downstream component */
++	unsigned int l0s_down_latency;
++	unsigned int l1_down_latency;
++	/* Clock PM state*/
++	unsigned int clk_pm_capable;
++	unsigned int clk_pm_enabled;
++	unsigned int bios_clk_state;
++
++	/*
++	 * A pcie downstream port only has one slot under it, so at most there
++	 * are 8 functions
++	 */
++	struct endpoint_state endpoints[8];
++};
++
++static int aspm_disabled;
++static DEFINE_MUTEX(aspm_lock);
++static LIST_HEAD(link_list);
++
++#define POLICY_DEFAULT 0	/* BIOS default setting */
++#define POLICY_PERFORMANCE 1	/* high performance */
++#define POLICY_POWERSAVE 2	/* high power saving */
++static int aspm_policy;
++static const char *policy_str[] = {
++	[POLICY_DEFAULT] = "default",
++	[POLICY_PERFORMANCE] = "performance",
++	[POLICY_POWERSAVE] = "powersave"
++};
++
++static int policy_to_aspm_state(struct pci_dev *pdev)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	switch (aspm_policy) {
++	case POLICY_PERFORMANCE:
++		/* Disable ASPM and Clock PM */
++		return 0;
++	case POLICY_POWERSAVE:
++		/* Enable ASPM L0s/L1 */
++		return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
++	case POLICY_DEFAULT:
++		return link_state->bios_aspm_state;
++	}
++	return 0;
++}
++
++static int policy_to_clkpm_state(struct pci_dev *pdev)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	switch (aspm_policy) {
++	case POLICY_PERFORMANCE:
++		/* Disable ASPM and Clock PM */
++		return 0;
++	case POLICY_POWERSAVE:
++		/* Disable Clock PM */
++		return 1;
++	case POLICY_DEFAULT:
++		return link_state->bios_clk_state;
++	}
++	return 0;
++}
++
++static void pcie_set_clock_pm(struct pci_dev *pdev, int enable)
++{
++	struct pci_dev *child_dev;
++	int pos;
++	u16 reg16;
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
++		if (!pos)
++			return;
++		pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, &reg16);
++		if (enable)
++			reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN;
++		else
++			reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
++		pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16);
++	}
++	link_state->clk_pm_enabled = !!enable;
++}
++
++static void pcie_check_clock_pm(struct pci_dev *pdev)
++{
++	int pos;
++	u32 reg32;
++	u16 reg16;
++	int capable = 1, enabled = 1;
++	struct pci_dev *child_dev;
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	/* All functions should have the same cap and state, take the worst */
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
++		if (!pos)
++			return;
++		pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, &reg32);
++		if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
++			capable = 0;
++			enabled = 0;
++			break;
++		}
++		pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, &reg16);
++		if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
++			enabled = 0;
++	}
++	link_state->clk_pm_capable = capable;
++	link_state->clk_pm_enabled = enabled;
++	link_state->bios_clk_state = enabled;
++	pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
++}
++
++/*
++ * pcie_aspm_configure_common_clock: check if the 2 ends of a link
++ *   could use common clock. If they are, configure them to use the
++ *   common clock. That will reduce the ASPM state exit latency.
++ */
++static void pcie_aspm_configure_common_clock(struct pci_dev *pdev)
++{
++	int pos, child_pos;
++	u16 reg16 = 0;
++	struct pci_dev *child_dev;
++	int same_clock = 1;
++
++	/*
++	 * all functions of a slot should have the same Slot Clock
++	 * Configuration, so just check one function
++	 * */
++	child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev,
++		bus_list);
++	BUG_ON(!child_dev->is_pcie);
++
++	/* Check downstream component if bit Slot Clock Configuration is 1 */
++	child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
++	pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, &reg16);
++	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
++		same_clock = 0;
++
++	/* Check upstream component if bit Slot Clock Configuration is 1 */
++	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
++	pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
++	if (!(reg16 & PCI_EXP_LNKSTA_SLC))
++		same_clock = 0;
++
++	/* Configure downstream component, all functions */
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
++		pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL,
++			&reg16);
++		if (same_clock)
++			reg16 |= PCI_EXP_LNKCTL_CCC;
++		else
++			reg16 &= ~PCI_EXP_LNKCTL_CCC;
++		pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL,
++			reg16);
++	}
++
++	/* Configure upstream component */
++	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
++	if (same_clock)
++		reg16 |= PCI_EXP_LNKCTL_CCC;
++	else
++		reg16 &= ~PCI_EXP_LNKCTL_CCC;
++	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
++
++	/* retrain link */
++	reg16 |= PCI_EXP_LNKCTL_RL;
++	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
++
++	/* Wait for link training end */
++	while (1) {
++		pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
++		if (!(reg16 & PCI_EXP_LNKSTA_LT))
++			break;
++		cpu_relax();
++	}
++}
++
++/*
++ * calc_L0S_latency: Convert L0s latency encoding to ns
++ */
++static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac)
++{
++	unsigned int ns = 64;
++
++	if (latency_encoding == 0x7) {
++		if (ac)
++			ns = -1U;
++		else
++			ns = 5*1000; /* > 4us */
++	} else
++		ns *= (1 << latency_encoding);
++	return ns;
++}
++
++/*
++ * calc_L1_latency: Convert L1 latency encoding to ns
++ */
++static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac)
++{
++	unsigned int ns = 1000;
++
++	if (latency_encoding == 0x7) {
++		if (ac)
++			ns = -1U;
++		else
++			ns = 65*1000; /* > 64us */
++	} else
++		ns *= (1 << latency_encoding);
++	return ns;
++}
++
++static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state,
++	unsigned int *l0s, unsigned int *l1, unsigned int *enabled)
++{
++	int pos;
++	u16 reg16;
++	u32 reg32;
++	unsigned int latency;
++
++	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
++	pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32);
++	*state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
++	if (*state != PCIE_LINK_STATE_L0S &&
++		*state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S))
++		* state = 0;
++	if (*state == 0)
++		return;
++
++	latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
++	*l0s = calc_L0S_latency(latency, 0);
++	if (*state & PCIE_LINK_STATE_L1) {
++		latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
++		*l1 = calc_L1_latency(latency, 0);
++	}
++	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
++	*enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1);
++}
++
++static void pcie_aspm_cap_init(struct pci_dev *pdev)
++{
++	struct pci_dev *child_dev;
++	u32 state, tmp;
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	/* upstream component states */
++	pcie_aspm_get_cap_device(pdev, &link_state->support_state,
++		&link_state->l0s_upper_latency,
++		&link_state->l1_upper_latency,
++		&link_state->enabled_state);
++	/* downstream component states, all functions have the same setting */
++	child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev,
++		bus_list);
++	pcie_aspm_get_cap_device(child_dev, &state,
++		&link_state->l0s_down_latency,
++		&link_state->l1_down_latency,
++		&tmp);
++	link_state->support_state &= state;
++	if (!link_state->support_state)
++		return;
++	link_state->enabled_state &= link_state->support_state;
++	link_state->bios_aspm_state = link_state->enabled_state;
++
++	/* ENDPOINT states*/
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		int pos;
++		u32 reg32;
++		unsigned int latency;
++		struct endpoint_state *ep_state =
++			&link_state->endpoints[PCI_FUNC(child_dev->devfn)];
++
++		if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
++			child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)
++			continue;
++
++		pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
++		pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, &reg32);
++		latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
++		latency = calc_L0S_latency(latency, 1);
++		ep_state->l0s_acceptable_latency = latency;
++		if (link_state->support_state & PCIE_LINK_STATE_L1) {
++			latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9;
++			latency = calc_L1_latency(latency, 1);
++			ep_state->l1_acceptable_latency = latency;
++		}
++	}
++}
++
++static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev,
++	unsigned int state)
++{
++	struct pci_dev *parent_dev, *tmp_dev;
++	unsigned int latency, l1_latency = 0;
++	struct pcie_link_state *link_state;
++	struct endpoint_state *ep_state;
++
++	parent_dev = pdev->bus->self;
++	link_state = parent_dev->link_state;
++	state &= link_state->support_state;
++	if (state == 0)
++		return 0;
++	ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)];
++
++	/*
++	 * Check latency for endpoint device.
++	 * TBD: The latency from the endpoint to root complex vary per
++	 * switch's upstream link state above the device. Here we just do a
++	 * simple check which assumes all links above the device can be in L1
++	 * state, that is we just consider the worst case. If switch's upstream
++	 * link can't be put into L0S/L1, then our check is too strictly.
++	 */
++	tmp_dev = pdev;
++	while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
++		parent_dev = tmp_dev->bus->self;
++		link_state = parent_dev->link_state;
++		if (state & PCIE_LINK_STATE_L0S) {
++			latency = max_t(unsigned int,
++					link_state->l0s_upper_latency,
++					link_state->l0s_down_latency);
++			if (latency > ep_state->l0s_acceptable_latency)
++				state &= ~PCIE_LINK_STATE_L0S;
++		}
++		if (state & PCIE_LINK_STATE_L1) {
++			latency = max_t(unsigned int,
++					link_state->l1_upper_latency,
++					link_state->l1_down_latency);
++			if (latency + l1_latency >
++					ep_state->l1_acceptable_latency)
++				state &= ~PCIE_LINK_STATE_L1;
++		}
++		if (!parent_dev->bus->self) /* parent_dev is a root port */
++			break;
++		else {
++			/*
++			 * parent_dev is the downstream port of a switch, make
++			 * tmp_dev the upstream port of the switch
++			 */
++			tmp_dev = parent_dev->bus->self;
++			/*
++			 * every switch on the path to root complex need 1 more
++			 * microsecond for L1. Spec doesn't mention L0S.
++			 */
++			if (state & PCIE_LINK_STATE_L1)
++				l1_latency += 1000;
++		}
++	}
++	return state;
++}
++
++static unsigned int pcie_aspm_check_state(struct pci_dev *pdev,
++	unsigned int state)
++{
++	struct pci_dev *child_dev;
++
++	/* If no child, disable the link */
++	if (list_empty(&pdev->subordinate->devices))
++		return 0;
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
++			/*
++			 * If downstream component of a link is pci bridge, we
++			 * disable ASPM for now for the link
++			 * */
++			state = 0;
++			break;
++		}
++		if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT &&
++			child_dev->pcie_type != PCI_EXP_TYPE_LEG_END))
++			continue;
++		/* Device not in D0 doesn't need check latency */
++		if (child_dev->current_state == PCI_D1 ||
++			child_dev->current_state == PCI_D2 ||
++			child_dev->current_state == PCI_D3hot ||
++			child_dev->current_state == PCI_D3cold)
++			continue;
++		state = __pcie_aspm_check_state_one(child_dev, state);
++	}
++	return state;
++}
++
++static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state)
++{
++	u16 reg16;
++	int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
++
++	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
++	reg16 &= ~0x3;
++	reg16 |= state;
++	pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
++}
++
++static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
++{
++	struct pci_dev *child_dev;
++	int valid = 1;
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	/*
++	 * if the downstream component has pci bridge function, don't do ASPM
++	 * now
++	 */
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
++		if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
++			valid = 0;
++			break;
++		}
++	}
++	if (!valid)
++		return;
++
++	/*
++	 * spec 2.0 suggests all functions should be configured the same
++	 * setting for ASPM. Enabling ASPM L1 should be done in upstream
++	 * component first and then downstream, and vice versa for disabling
++	 * ASPM L1. Spec doesn't mention L0S.
++	 */
++	if (state & PCIE_LINK_STATE_L1)
++		__pcie_aspm_config_one_dev(pdev, state);
++
++	list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list)
++		__pcie_aspm_config_one_dev(child_dev, state);
++
++	if (!(state & PCIE_LINK_STATE_L1))
++		__pcie_aspm_config_one_dev(pdev, state);
++
++	link_state->enabled_state = state;
++}
++
++static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
++	unsigned int state)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	if (link_state->support_state == 0)
++		return;
++	state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
++
++	/* state 0 means disabling aspm */
++	state = pcie_aspm_check_state(pdev, state);
++	if (link_state->enabled_state == state)
++		return;
++	__pcie_aspm_config_link(pdev, state);
++}
++
++/*
++ * pcie_aspm_configure_link_state: enable/disable PCI express link state
++ * @pdev: the root port or switch downstream port
++ */
++static void pcie_aspm_configure_link_state(struct pci_dev *pdev,
++	unsigned int state)
++{
++	down_read(&pci_bus_sem);
++	mutex_lock(&aspm_lock);
++	__pcie_aspm_configure_link_state(pdev, state);
++	mutex_unlock(&aspm_lock);
++	up_read(&pci_bus_sem);
++}
++
++static void free_link_state(struct pci_dev *pdev)
++{
++	kfree(pdev->link_state);
++	pdev->link_state = NULL;
++}
++
++/*
++ * pcie_aspm_init_link_state: Initiate PCI express link state.
++ * It is called after the pcie and its children devices are scaned.
++ * @pdev: the root port or switch downstream port
++ */
++void pcie_aspm_init_link_state(struct pci_dev *pdev)
++{
++	unsigned int state;
++	struct pcie_link_state *link_state;
++	int error = 0;
++
++	if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
++		return;
++	if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
++		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
++		return;
++	down_read(&pci_bus_sem);
++	if (list_empty(&pdev->subordinate->devices))
++		goto out;
++
++	mutex_lock(&aspm_lock);
++
++	link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
++	if (!link_state)
++		goto unlock_out;
++	pdev->link_state = link_state;
++
++	pcie_aspm_configure_common_clock(pdev);
++
++	pcie_aspm_cap_init(pdev);
++
++	/* config link state to avoid BIOS error */
++	state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev));
++	__pcie_aspm_config_link(pdev, state);
++
++	pcie_check_clock_pm(pdev);
++
++	link_state->pdev = pdev;
++	list_add(&link_state->sibiling, &link_list);
++
++unlock_out:
++	if (error)
++		free_link_state(pdev);
++	mutex_unlock(&aspm_lock);
++out:
++	up_read(&pci_bus_sem);
++}
++
++/* @pdev: the endpoint device */
++void pcie_aspm_exit_link_state(struct pci_dev *pdev)
++{
++	struct pci_dev *parent = pdev->bus->self;
++	struct pcie_link_state *link_state = parent->link_state;
++
++	if (aspm_disabled || !pdev->is_pcie || !parent || !link_state)
++		return;
++	if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
++		parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
++		return;
++	down_read(&pci_bus_sem);
++	mutex_lock(&aspm_lock);
++
++	/*
++	 * All PCIe functions are in one slot, remove one function will remove
++	 * the the whole slot, so just wait
++	 */
++	if (!list_empty(&parent->subordinate->devices))
++		goto out;
++
++	/* All functions are removed, so just disable ASPM for the link */
++	__pcie_aspm_config_one_dev(parent, 0);
++	list_del(&link_state->sibiling);
++	/* Clock PM is for endpoint device */
++
++	free_link_state(parent);
++out:
++	mutex_unlock(&aspm_lock);
++	up_read(&pci_bus_sem);
++}
++
++/* @pdev: the root port or switch downstream port */
++void pcie_aspm_pm_state_change(struct pci_dev *pdev)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	if (aspm_disabled || !pdev->is_pcie || !pdev->link_state)
++		return;
++	if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
++		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
++		return;
++	/*
++	 * devices changed PM state, we should recheck if latency meets all
++	 * functions' requirement
++	 */
++	pcie_aspm_configure_link_state(pdev, link_state->enabled_state);
++}
++
++/*
++ * pci_disable_link_state - disable pci device's link state, so the link will
++ * never enter specific states
++ */
++void pci_disable_link_state(struct pci_dev *pdev, int state)
++{
++	struct pci_dev *parent = pdev->bus->self;
++	struct pcie_link_state *link_state;
++
++	if (aspm_disabled || !pdev->is_pcie)
++		return;
++	if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
++	    pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
++		parent = pdev;
++	if (!parent)
++		return;
++
++	down_read(&pci_bus_sem);
++	mutex_lock(&aspm_lock);
++	link_state = parent->link_state;
++	link_state->support_state &=
++		~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1));
++	if (state & PCIE_LINK_STATE_CLKPM)
++		link_state->clk_pm_capable = 0;
++
++	__pcie_aspm_configure_link_state(parent, link_state->enabled_state);
++	if (!link_state->clk_pm_capable && link_state->clk_pm_enabled)
++		pcie_set_clock_pm(parent, 0);
++	mutex_unlock(&aspm_lock);
++	up_read(&pci_bus_sem);
++}
++EXPORT_SYMBOL(pci_disable_link_state);
++
++static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
++{
++	int i;
++	struct pci_dev *pdev;
++	struct pcie_link_state *link_state;
++
++	for (i = 0; i < ARRAY_SIZE(policy_str); i++)
++		if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
++			break;
++	if (i >= ARRAY_SIZE(policy_str))
++		return -EINVAL;
++	if (i == aspm_policy)
++		return 0;
++
++	down_read(&pci_bus_sem);
++	mutex_lock(&aspm_lock);
++	aspm_policy = i;
++	list_for_each_entry(link_state, &link_list, sibiling) {
++		pdev = link_state->pdev;
++		__pcie_aspm_configure_link_state(pdev,
++			policy_to_aspm_state(pdev));
++		if (link_state->clk_pm_capable &&
++		    link_state->clk_pm_enabled != policy_to_clkpm_state(pdev))
++			pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
++
++	}
++	mutex_unlock(&aspm_lock);
++	up_read(&pci_bus_sem);
++	return 0;
++}
++
++static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp)
++{
++	int i, cnt = 0;
++	for (i = 0; i < ARRAY_SIZE(policy_str); i++)
++		if (i == aspm_policy)
++			cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
++		else
++			cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
++	return cnt;
++}
++
++module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
++	NULL, 0644);
++
++#ifdef CONFIG_PCIEASPM_DEBUG
++static ssize_t link_state_show(struct device *dev,
++		struct device_attribute *attr,
++		char *buf)
++{
++	struct pci_dev *pci_device = to_pci_dev(dev);
++	struct pcie_link_state *link_state = pci_device->link_state;
++
++	return sprintf(buf, "%d\n", link_state->enabled_state);
++}
++
++static ssize_t link_state_store(struct device *dev,
++		struct device_attribute *attr,
++		const char *buf,
++		size_t n)
++{
++	struct pci_dev *pci_device = to_pci_dev(dev);
++	int state;
++
++	if (n < 1)
++		return -EINVAL;
++	state = buf[0]-'0';
++	if (state >= 0 && state <= 3) {
++		/* setup link aspm state */
++		pcie_aspm_configure_link_state(pci_device, state);
++		return n;
++	}
++
++	return -EINVAL;
++}
++
++static ssize_t clk_ctl_show(struct device *dev,
++		struct device_attribute *attr,
++		char *buf)
++{
++	struct pci_dev *pci_device = to_pci_dev(dev);
++	struct pcie_link_state *link_state = pci_device->link_state;
++
++	return sprintf(buf, "%d\n", link_state->clk_pm_enabled);
++}
++
++static ssize_t clk_ctl_store(struct device *dev,
++		struct device_attribute *attr,
++		const char *buf,
++		size_t n)
++{
++	struct pci_dev *pci_device = to_pci_dev(dev);
++	int state;
++
++	if (n < 1)
++		return -EINVAL;
++	state = buf[0]-'0';
++
++	down_read(&pci_bus_sem);
++	mutex_lock(&aspm_lock);
++	pcie_set_clock_pm(pci_device, !!state);
++	mutex_unlock(&aspm_lock);
++	up_read(&pci_bus_sem);
++
++	return n;
++}
++
++static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store);
++static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store);
++
++static char power_group[] = "power";
++void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
++		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
++		return;
++
++	if (link_state->support_state)
++		sysfs_add_file_to_group(&pdev->dev.kobj,
++			&dev_attr_link_state.attr, power_group);
++	if (link_state->clk_pm_capable)
++		sysfs_add_file_to_group(&pdev->dev.kobj,
++			&dev_attr_clk_ctl.attr, power_group);
++}
++
++void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
++{
++	struct pcie_link_state *link_state = pdev->link_state;
++
++	if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
++		pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
++		return;
++
++	if (link_state->support_state)
++		sysfs_remove_file_from_group(&pdev->dev.kobj,
++			&dev_attr_link_state.attr, power_group);
++	if (link_state->clk_pm_capable)
++		sysfs_remove_file_from_group(&pdev->dev.kobj,
++			&dev_attr_clk_ctl.attr, power_group);
++}
++#endif
++
++static int __init pcie_aspm_disable(char *str)
++{
++	aspm_disabled = 1;
++	return 1;
++}
++
++__setup("pcie_noaspm", pcie_aspm_disable);
++
++static int __init pcie_aspm_init(void)
++{
++	if (aspm_disabled)
++		return 0;
++	pci_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT|
++		OSC_CLOCK_PWR_CAPABILITY_SUPPORT);
++	return 0;
++}
++
++fs_initcall(pcie_aspm_init);
+diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
+index b20a9b8..23d9eb0 100644
+--- a/drivers/pci/pcie/portdrv_core.c
++++ b/drivers/pci/pcie/portdrv_core.c
+@@ -192,9 +192,8 @@ static int get_port_device_capability(struct pci_dev *dev)
+ 		if (reg32 & SLOT_HP_CAPABLE_MASK)
+ 			services |= PCIE_PORT_SERVICE_HP;
+ 	} 
+-	/* PME Capable */
+-	pos = pci_find_capability(dev, PCI_CAP_ID_PME);
+-	if (pos) 
++	/* PME Capable - root port capability */
++	if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
+ 		services |= PCIE_PORT_SERVICE_PME;
+ 	
+ 	pos = PCI_CFG_SPACE_SIZE;
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index c5ca313..8b505bd 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -9,6 +9,7 @@
+ #include <linux/slab.h>
+ #include <linux/module.h>
+ #include <linux/cpumask.h>
++#include <linux/aspm.h>
+ #include "pci.h"
+ 
+ #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
+@@ -53,7 +54,7 @@ static void pci_create_legacy_files(struct pci_bus *b)
+ 		b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+ 		b->legacy_io->read = pci_read_legacy_io;
+ 		b->legacy_io->write = pci_write_legacy_io;
+-		class_device_create_bin_file(&b->class_dev, b->legacy_io);
++		device_create_bin_file(&b->dev, b->legacy_io);
+ 
+ 		/* Allocated above after the legacy_io struct */
+ 		b->legacy_mem = b->legacy_io + 1;
+@@ -61,15 +62,15 @@ static void pci_create_legacy_files(struct pci_bus *b)
+ 		b->legacy_mem->size = 1024*1024;
+ 		b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+ 		b->legacy_mem->mmap = pci_mmap_legacy_mem;
+-		class_device_create_bin_file(&b->class_dev, b->legacy_mem);
++		device_create_bin_file(&b->dev, b->legacy_mem);
+ 	}
+ }
+ 
+ void pci_remove_legacy_files(struct pci_bus *b)
+ {
+ 	if (b->legacy_io) {
+-		class_device_remove_bin_file(&b->class_dev, b->legacy_io);
+-		class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
++		device_remove_bin_file(&b->dev, b->legacy_io);
++		device_remove_bin_file(&b->dev, b->legacy_mem);
+ 		kfree(b->legacy_io); /* both are allocated here */
+ 	}
+ }
+@@ -81,26 +82,27 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; }
+ /*
+  * PCI Bus Class Devices
+  */
+-static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev,
++static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
++					struct device_attribute *attr,
+ 					char *buf)
+ {
+ 	int ret;
+ 	cpumask_t cpumask;
+ 
+-	cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
++	cpumask = pcibus_to_cpumask(to_pci_bus(dev));
+ 	ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
+ 	if (ret < PAGE_SIZE)
+ 		buf[ret++] = '\n';
+ 	return ret;
+ }
+-CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
++DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+ 
+ /*
+  * PCI Bus Class
+  */
+-static void release_pcibus_dev(struct class_device *class_dev)
++static void release_pcibus_dev(struct device *dev)
+ {
+-	struct pci_bus *pci_bus = to_pci_bus(class_dev);
++	struct pci_bus *pci_bus = to_pci_bus(dev);
+ 
+ 	if (pci_bus->bridge)
+ 		put_device(pci_bus->bridge);
+@@ -109,7 +111,7 @@ static void release_pcibus_dev(struct class_device *class_dev)
+ 
+ static struct class pcibus_class = {
+ 	.name		= "pci_bus",
+-	.release	= &release_pcibus_dev,
++	.dev_release	= &release_pcibus_dev,
+ };
+ 
+ static int __init pcibus_class_init(void)
+@@ -392,7 +394,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
+ {
+ 	struct pci_bus *child;
+ 	int i;
+-	int retval;
+ 
+ 	/*
+ 	 * Allocate a new bus, and inherit stuff from the parent..
+@@ -408,15 +409,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
+ 	child->bus_flags = parent->bus_flags;
+ 	child->bridge = get_device(&bridge->dev);
+ 
+-	child->class_dev.class = &pcibus_class;
+-	sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
+-	retval = class_device_register(&child->class_dev);
+-	if (retval)
+-		goto error_register;
+-	retval = class_device_create_file(&child->class_dev,
+-					  &class_device_attr_cpuaffinity);
+-	if (retval)
+-		goto error_file_create;
++	/* initialize some portions of the bus device, but don't register it
++	 * now as the parent is not properly set up yet.  This device will get
++	 * registered later in pci_bus_add_devices()
++	 */
++	child->dev.class = &pcibus_class;
++	sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr);
+ 
+ 	/*
+ 	 * Set up the primary, secondary and subordinate
+@@ -434,12 +432,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
+ 	bridge->subordinate = child;
+ 
+ 	return child;
+-
+-error_file_create:
+-	class_device_unregister(&child->class_dev);
+-error_register:
+-	kfree(child);
+-	return NULL;
+ }
+ 
+ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+@@ -471,8 +463,6 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
+ 	}
+ }
+ 
+-unsigned int pci_scan_child_bus(struct pci_bus *bus);
+-
+ /*
+  * If it's a bridge, configure it and scan the bus behind it.
+  * For CardBus bridges, we don't scan behind as the devices will
+@@ -641,13 +631,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
+ 		    (child->number > bus->subordinate) ||
+ 		    (child->number < bus->number) ||
+ 		    (child->subordinate < bus->number)) {
+-			pr_debug("PCI: Bus #%02x (-#%02x) is %s"
++			pr_debug("PCI: Bus #%02x (-#%02x) is %s "
+ 				"hidden behind%s bridge #%02x (-#%02x)\n",
+ 				child->number, child->subordinate,
+ 				(bus->number > child->subordinate &&
+ 				 bus->subordinate < child->number) ?
+-					"wholly " : " partially",
+-				bus->self->transparent ? " transparent" : " ",
++					"wholly" : "partially",
++				bus->self->transparent ? " transparent" : "",
+ 				bus->number, bus->subordinate);
+ 		}
+ 		bus = bus->parent;
+@@ -971,6 +961,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
+ 
+ 	return dev;
+ }
++EXPORT_SYMBOL(pci_scan_single_device);
+ 
+ /**
+  * pci_scan_slot - scan a PCI slot on a bus for devices.
+@@ -1011,6 +1002,10 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
+ 				break;
+ 		}
+ 	}
++
++	if (bus->self)
++		pcie_aspm_init_link_state(bus->self);
++
+ 	return nr;
+ }
+ 
+@@ -1103,32 +1098,27 @@ struct pci_bus * pci_create_bus(struct device *parent,
+ 		goto dev_reg_err;
+ 	b->bridge = get_device(dev);
+ 
+-	b->class_dev.class = &pcibus_class;
+-	sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus);
+-	error = class_device_register(&b->class_dev);
++	b->dev.class = &pcibus_class;
++	b->dev.parent = b->bridge;
++	sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
++	error = device_register(&b->dev);
+ 	if (error)
+ 		goto class_dev_reg_err;
+-	error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
++	error = device_create_file(&b->dev, &dev_attr_cpuaffinity);
+ 	if (error)
+-		goto class_dev_create_file_err;
++		goto dev_create_file_err;
+ 
+ 	/* Create legacy_io and legacy_mem files for this bus */
+ 	pci_create_legacy_files(b);
+ 
+-	error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
+-	if (error)
+-		goto sys_create_link_err;
+-
+ 	b->number = b->secondary = bus;
+ 	b->resource[0] = &ioport_resource;
+ 	b->resource[1] = &iomem_resource;
+ 
+ 	return b;
+ 
+-sys_create_link_err:
+-	class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);
+-class_dev_create_file_err:
+-	class_device_unregister(&b->class_dev);
++dev_create_file_err:
++	device_unregister(&b->dev);
+ class_dev_reg_err:
+ 	device_unregister(dev);
+ dev_reg_err:
+@@ -1140,7 +1130,6 @@ err_out:
+ 	kfree(b);
+ 	return NULL;
+ }
+-EXPORT_SYMBOL_GPL(pci_create_bus);
+ 
+ struct pci_bus *pci_scan_bus_parented(struct device *parent,
+ 		int bus, struct pci_ops *ops, void *sysdata)
+@@ -1159,7 +1148,6 @@ EXPORT_SYMBOL(pci_add_new_bus);
+ EXPORT_SYMBOL(pci_do_scan_bus);
+ EXPORT_SYMBOL(pci_scan_slot);
+ EXPORT_SYMBOL(pci_scan_bridge);
+-EXPORT_SYMBOL(pci_scan_single_device);
+ EXPORT_SYMBOL_GPL(pci_scan_child_bus);
+ #endif
+ 
+@@ -1210,16 +1198,19 @@ static void __init pci_sort_breadthfirst_klist(void)
+ 	struct klist_node *n;
+ 	struct device *dev;
+ 	struct pci_dev *pdev;
++	struct klist *device_klist;
++
++	device_klist = bus_get_device_klist(&pci_bus_type);
+ 
+-	spin_lock(&pci_bus_type.klist_devices.k_lock);
+-	list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
++	spin_lock(&device_klist->k_lock);
++	list_for_each_safe(pos, tmp, &device_klist->k_list) {
+ 		n = container_of(pos, struct klist_node, n_node);
+ 		dev = container_of(n, struct device, knode_bus);
+ 		pdev = to_pci_dev(dev);
+ 		pci_insertion_sort_klist(pdev, &sorted_devices);
+ 	}
+-	list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
+-	spin_unlock(&pci_bus_type.klist_devices.k_lock);
++	list_splice(&sorted_devices, &device_klist->k_list);
++	spin_unlock(&device_klist->k_lock);
+ }
+ 
+ static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
+diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
+index 716439e..68aeeb7 100644
+--- a/drivers/pci/proc.c
++++ b/drivers/pci/proc.c
+@@ -11,6 +11,7 @@
+ #include <linux/module.h>
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
++#include <linux/smp_lock.h>
+ #include <linux/capability.h>
+ #include <asm/uaccess.h>
+ #include <asm/byteorder.h>
+@@ -202,15 +203,18 @@ struct pci_filp_private {
+ 	int write_combine;
+ };
+ 
+-static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
++			       unsigned long arg)
+ {
+-	const struct proc_dir_entry *dp = PDE(inode);
++	const struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ 	struct pci_dev *dev = dp->data;
+ #ifdef HAVE_PCI_MMAP
+ 	struct pci_filp_private *fpriv = file->private_data;
+ #endif /* HAVE_PCI_MMAP */
+ 	int ret = 0;
+ 
++	lock_kernel();
++
+ 	switch (cmd) {
+ 	case PCIIOC_CONTROLLER:
+ 		ret = pci_domain_nr(dev->bus);
+@@ -239,6 +243,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i
+ 		break;
+ 	};
+ 
++	unlock_kernel();
+ 	return ret;
+ }
+ 
+@@ -291,7 +296,7 @@ static const struct file_operations proc_bus_pci_operations = {
+ 	.llseek		= proc_bus_pci_lseek,
+ 	.read		= proc_bus_pci_read,
+ 	.write		= proc_bus_pci_write,
+-	.ioctl		= proc_bus_pci_ioctl,
++	.unlocked_ioctl	= proc_bus_pci_ioctl,
+ #ifdef HAVE_PCI_MMAP
+ 	.open		= proc_bus_pci_open,
+ 	.release	= proc_bus_pci_release,
+@@ -370,7 +375,7 @@ static int show_device(struct seq_file *m, void *v)
+ 	return 0;
+ }
+ 
+-static struct seq_operations proc_bus_pci_devices_op = {
++static const struct seq_operations proc_bus_pci_devices_op = {
+ 	.start	= pci_seq_start,
+ 	.next	= pci_seq_next,
+ 	.stop	= pci_seq_stop,
+@@ -480,7 +485,3 @@ static int __init pci_proc_init(void)
+ 
+ __initcall(pci_proc_init);
+ 
+-#ifdef CONFIG_HOTPLUG
+-EXPORT_SYMBOL(pci_proc_detach_bus);
+-#endif
+-
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 72e0bd5..0a953d4 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -21,6 +21,7 @@
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/acpi.h>
++#include <linux/kallsyms.h>
+ #include "pci.h"
+ 
+ /* The Mellanox Tavor device gives false positive parity errors
+@@ -46,14 +47,14 @@ static void quirk_passive_release(struct pci_dev *dev)
+ 	while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
+ 		pci_read_config_byte(d, 0x82, &dlc);
+ 		if (!(dlc & 1<<1)) {
+-			printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
++			dev_err(&d->dev, "PIIX3: Enabling Passive Release\n");
+ 			dlc |= 1<<1;
+ 			pci_write_config_byte(d, 0x82, dlc);
+ 		}
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release);
+ 
+ /*  The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
+     but VIA don't answer queries. If you happen to have good contacts at VIA
+@@ -68,20 +69,20 @@ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
+ {
+ 	if (!isa_dma_bridge_buggy) {
+ 		isa_dma_bridge_buggy=1;
+-		printk(KERN_INFO "Activating ISA DMA hang workarounds.\n");
++		dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n");
+ 	}
+ }
+ 	/*
+ 	 * Its not totally clear which chipsets are the problematic ones
+ 	 * We know 82C586 and 82C596 variants are affected.
+ 	 */
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C596,	quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M1533, 	quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_1,	quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_2,	quirk_isa_dma_hangs );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_3,	quirk_isa_dma_hangs );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C596,	quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M1533, 	quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_1,	quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_2,	quirk_isa_dma_hangs);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_3,	quirk_isa_dma_hangs);
+ 
+ int pci_pci_problems;
+ EXPORT_SYMBOL(pci_pci_problems);
+@@ -92,12 +93,12 @@ EXPORT_SYMBOL(pci_pci_problems);
+ static void __devinit quirk_nopcipci(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems & PCIPCI_FAIL)==0) {
+-		printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_FAIL;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci);
+ 
+ static void __devinit quirk_nopciamd(struct pci_dev *dev)
+ {
+@@ -105,11 +106,11 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
+ 	pci_read_config_byte(dev, 0x08, &rev);
+ 	if (rev == 0x13) {
+ 		/* Erratum 24 */
+-		printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n");
++		dev_info(&dev->dev, "Chipset erratum: Disabling direct PCI/AGP transfers\n");
+ 		pci_pci_problems |= PCIAGP_FAIL;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8151_0,	quirk_nopciamd );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8151_0,	quirk_nopciamd);
+ 
+ /*
+  *	Triton requires workarounds to be used by the drivers
+@@ -117,14 +118,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8151_0,	quirk_nopci
+ static void __devinit quirk_triton(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems&PCIPCI_TRITON)==0) {
+-		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_TRITON;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437, 	quirk_triton ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437VX, 	quirk_triton ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439, 	quirk_triton ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439TX, 	quirk_triton ); 
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437, 	quirk_triton);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437VX, 	quirk_triton);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439, 	quirk_triton);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439TX, 	quirk_triton);
+ 
+ /*
+  *	VIA Apollo KT133 needs PCI latency patch
+@@ -139,25 +140,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439TX, 	quir
+ static void quirk_vialatency(struct pci_dev *dev)
+ {
+ 	struct pci_dev *p;
+-	u8 rev;
+ 	u8 busarb;
+ 	/* Ok we have a potential problem chipset here. Now see if we have
+ 	   a buggy southbridge */
+ 	   
+ 	p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+ 	if (p!=NULL) {
+-		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+ 		/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
+ 		/* Check for buggy part revisions */
+-		if (rev < 0x40 || rev > 0x42)
++		if (p->revision < 0x40 || p->revision > 0x42)
+ 			goto exit;
+ 	} else {
+ 		p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
+ 		if (p==NULL)	/* No problem parts */
+ 			goto exit;
+-		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+ 		/* Check for buggy part revisions */
+-		if (rev < 0x10 || rev > 0x12) 
++		if (p->revision < 0x10 || p->revision > 0x12)
+ 			goto exit;
+ 	}
+ 	
+@@ -180,17 +178,17 @@ static void quirk_vialatency(struct pci_dev *dev)
+ 	busarb &= ~(1<<5);
+ 	busarb |= (1<<4);
+ 	pci_write_config_byte(dev, 0x76, busarb);
+-	printk(KERN_INFO "Applying VIA southbridge workaround.\n");
++	dev_info(&dev->dev, "Applying VIA southbridge workaround\n");
+ exit:
+ 	pci_dev_put(p);
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_vialatency );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_vialatency);
+ /* Must restore this on a resume from RAM */
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_vialatency );
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_vialatency);
+ 
+ /*
+  *	VIA Apollo VP3 needs ETBF on BT848/878
+@@ -198,20 +196,20 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_viala
+ static void __devinit quirk_viaetbf(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems&PCIPCI_VIAETBF)==0) {
+-		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_VIAETBF;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf);
+ 
+ static void __devinit quirk_vsfx(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems&PCIPCI_VSFX)==0) {
+-		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_VSFX;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx);
+ 
+ /*
+  *	Ali Magik requires workarounds to be used by the drivers
+@@ -222,12 +220,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx
+ static void __init quirk_alimagik(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) {
+-		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik);
+ 
+ /*
+  *	Natoma has some interesting boundary conditions with Zoran stuff
+@@ -236,16 +234,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimag
+ static void __devinit quirk_natoma(struct pci_dev *dev)
+ {
+ 	if ((pci_pci_problems&PCIPCI_NATOMA)==0) {
+-		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
++		dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
+ 		pci_pci_problems |= PCIPCI_NATOMA;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82441, 	quirk_natoma ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_0, 	quirk_natoma ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_1, 	quirk_natoma ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_0, 	quirk_natoma ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_1, 	quirk_natoma ); 
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82441, 	quirk_natoma);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_0, 	quirk_natoma);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_1, 	quirk_natoma);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_0, 	quirk_natoma);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_1, 	quirk_natoma);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma);
+ 
+ /*
+  *  This chip can cause PCI parity errors if config register 0xA0 is read
+@@ -255,7 +253,7 @@ static void __devinit quirk_citrine(struct pci_dev *dev)
+ {
+ 	dev->cfg_size = 0xA0;
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CITRINE,	quirk_citrine );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CITRINE,	quirk_citrine);
+ 
+ /*
+  *  S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
+@@ -270,8 +268,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev)
+ 		r->end = 0x3ffffff;
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M);
+ 
+ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
+ 	unsigned size, int nr, const char *name)
+@@ -292,7 +290,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
+ 		pcibios_bus_to_resource(dev, res, &bus_region);
+ 
+ 		pci_claim_resource(dev, nr);
+-		printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
++		dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
+ 	}
+ }	
+ 
+@@ -302,12 +300,12 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
+  */
+ static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
+ {
+-	printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
++	dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n");
+ 	/* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
+ 	request_region(0x3b0, 0x0C, "RadeonIGP");
+ 	request_region(0x3d3, 0x01, "RadeonIGP");
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI,	PCI_DEVICE_ID_ATI_RS100,   quirk_ati_exploding_mce );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI,	PCI_DEVICE_ID_ATI_RS100,   quirk_ati_exploding_mce);
+ 
+ /*
+  * Let's make the southbridge information explicit instead
+@@ -329,7 +327,7 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
+ 	pci_read_config_word(dev, 0xE2, &region);
+ 	quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101_acpi);
+ 
+ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
+ {
+@@ -354,7 +352,7 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
+ 	 * let's get enough confirmation reports first. 
+ 	 */
+ 	base &= -size;
+-	printk("%s PIO at %04x-%04x\n", name, base, base + size - 1);
++	dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
+ }
+ 
+ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
+@@ -379,7 +377,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
+ 	 * reserve it, but let's get enough confirmation reports first. 
+ 	 */
+ 	base &= -size;
+-	printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1);
++	dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
+ }
+ 
+ /*
+@@ -418,8 +416,8 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
+ 	piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20);
+ 	piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20);
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	quirk_piix4_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82443MX_3,	quirk_piix4_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	quirk_piix4_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82443MX_3,	quirk_piix4_acpi);
+ 
+ /*
+  * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
+@@ -436,16 +434,16 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0x58, &region);
+ 	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO");
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_10,	quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,	quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,	quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,		quirk_ich4_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,		quirk_ich4_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_10,	quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,	quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,	quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,		quirk_ich4_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,		quirk_ich4_lpc_acpi);
+ 
+ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
+ {
+@@ -457,20 +455,20 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0x48, &region);
+ 	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi);
+ 
+ /*
+  * VIA ACPI: One IO region pointed to by longword at
+@@ -486,7 +484,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
+ 		quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi);
+ 
+ /*
+  * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
+@@ -509,7 +507,7 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
+ 	smb &= PCI_BASE_ADDRESS_IO_MASK;
+ 	quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_vt82c686_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_vt82c686_acpi);
+ 
+ /*
+  * VIA VT8235 ISA Bridge: Two IO regions pointed to by words at
+@@ -551,14 +549,14 @@ static void quirk_via_ioapic(struct pci_dev *dev)
+ 	else
+ 		tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
+ 		
+-	printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
++	dev_info(&dev->dev, "%sbling VIA external APIC routing\n",
+ 	       tmp == 0 ? "Disa" : "Ena");
+ 
+ 	/* Offset 0x58: External APIC IRQ output control */
+ 	pci_write_config_byte (dev, 0x58, tmp);
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic);
+ 
+ /*
+  * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
+@@ -573,7 +571,7 @@ static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
+ 
+ 	pci_read_config_byte(dev, 0x5B, &misc_control2);
+ 	if (!(misc_control2 & BYPASS_APIC_DEASSERT)) {
+-		printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n");
++		dev_info(&dev->dev, "Bypassing VIA 8237 APIC De-Assert Message\n");
+ 		pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT);
+ 	}
+ }
+@@ -592,18 +590,18 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237,		quirk_via_v
+ static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
+ {
+ 	if (dev->revision >= 0x02) {
+-		printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
+-		printk(KERN_WARNING "        : booting with the \"noapic\" option.\n");
++		dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
++		dev_warn(&dev->dev, "        : booting with the \"noapic\" option\n");
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic);
+ 
+ static void __init quirk_ioapic_rmw(struct pci_dev *dev)
+ {
+ 	if (dev->devfn == 0 && dev->bus->number == 0)
+ 		sis_apic_bug = 1;
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw);
+ 
+ #define AMD8131_revA0        0x01
+ #define AMD8131_revB0        0x11
+@@ -617,7 +615,7 @@ static void quirk_amd_8131_ioapic(struct pci_dev *dev)
+                 return;
+ 
+         if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) {
+-                printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); 
++                dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n");
+                 pci_read_config_byte( dev, AMD8131_MISC, &tmp);
+                 tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
+                 pci_write_config_byte( dev, AMD8131_MISC, tmp);
+@@ -634,8 +632,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
+ static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
+ {
+ 	if (dev->subordinate && dev->revision <= 0x12) {
+-		printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
+-				"MMRBC\n", dev->revision);
++		dev_info(&dev->dev, "AMD8131 rev %x detected; "
++			"disabling PCI-X MMRBC\n", dev->revision);
+ 		dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
+ 	}
+ }
+@@ -660,8 +658,8 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
+ 	if (irq && (irq != 2))
+ 		d->irq = irq;
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_via_acpi );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_via_acpi);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi);
+ 
+ 
+ /*
+@@ -742,8 +740,8 @@ static void quirk_via_vlink(struct pci_dev *dev)
+ 
+ 	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ 	if (new_irq != irq) {
+-		printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n",
+-			pci_name(dev), irq, new_irq);
++		dev_info(&dev->dev, "VIA VLink IRQ fixup, from %d to %d\n",
++			irq, new_irq);
+ 		udelay(15);	/* unknown if delay really needed */
+ 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+ 	}
+@@ -761,7 +759,7 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
+ 	pci_write_config_byte(dev, 0xfc, 0);
+ 	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id);
+ 
+ /*
+  * CardBus controllers have a legacy base address that enables them
+@@ -791,15 +789,15 @@ static void quirk_amd_ordering(struct pci_dev *dev)
+ 	pci_read_config_dword(dev, 0x4C, &pcic);
+ 	if ((pcic&6)!=6) {
+ 		pcic |= 6;
+-		printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
++		dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n");
+ 		pci_write_config_dword(dev, 0x4C, pcic);
+ 		pci_read_config_dword(dev, 0x84, &pcic);
+ 		pcic |= (1<<23);	/* Required in this mode */
+ 		pci_write_config_dword(dev, 0x84, pcic);
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
+ 
+ /*
+  *	DreamWorks provided workaround for Dunord I-3000 problem
+@@ -814,7 +812,7 @@ static void __devinit quirk_dunord ( struct pci_dev * dev )
+ 	r->start = 0;
+ 	r->end = 0xffffff;
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD,	PCI_DEVICE_ID_DUNORD_I3000,	quirk_dunord );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD,	PCI_DEVICE_ID_DUNORD_I3000,	quirk_dunord);
+ 
+ /*
+  * i82380FB mobile docking controller: its PCI-to-PCI bridge
+@@ -826,8 +824,8 @@ static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
+ {
+ 	dev->transparent = 1;
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA,	0x605,	quirk_transparent_bridge );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA,	0x605,	quirk_transparent_bridge);
+ 
+ /*
+  * Common misconfiguration of the MediaGX/Geode PCI master that will
+@@ -841,12 +839,12 @@ static void quirk_mediagx_master(struct pci_dev *dev)
+ 	pci_read_config_byte(dev, 0x41, &reg);
+ 	if (reg & 2) {
+ 		reg &= ~2;
+-		printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
++		dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+                 pci_write_config_byte(dev, 0x41, reg);
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
+ 
+ /*
+  *	Ensure C0 rev restreaming is off. This is normally done by
+@@ -863,11 +861,11 @@ static void quirk_disable_pxb(struct pci_dev *pdev)
+ 	if (config & (1<<6)) {
+ 		config &= ~(1<<6);
+ 		pci_write_config_word(pdev, 0x40, config);
+-		printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
++		dev_info(&pdev->dev, "C0 revision 450NX. Disabling PCI restreaming\n");
+ 	}
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb);
+ 
+ 
+ static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
+@@ -902,7 +900,7 @@ static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev)
+ 		/* PCI layer will sort out resources */
+ 	}
+ }
+-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide);
+ 
+ /*
+  *	Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
+@@ -914,7 +912,7 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev)
+ 	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+ 
+ 	if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) {
+-		printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n");
++		dev_info(&pdev->dev, "IDE mode mismatch; forcing legacy mode\n");
+ 		prog &= ~5;
+ 		pdev->class &= ~5;
+ 		pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
+@@ -929,7 +927,7 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
+ {
+ 	dev->class = PCI_CLASS_BRIDGE_EISA << 8;
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_eisa_bridge );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_eisa_bridge);
+ 
+ 
+ /*
+@@ -1022,6 +1020,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
+ 			case 0x12bd: /* HP D530 */
+ 				asus_hides_smbus = 1;
+ 			}
++		else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
++			switch (dev->subsystem_device) {
++			case 0x12bf: /* HP xw4100 */
++				asus_hides_smbus = 1;
++			}
+ 		else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
+ 			switch (dev->subsystem_device) {
+ 			case 0x099c: /* HP Compaq nx6110 */
+@@ -1049,17 +1052,18 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
+ 			}
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845G_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82850_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82865_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_7205_0,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7501_MCH,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855PM_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855GM_HB,	asus_hides_smbus_hostbridge );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845G_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82850_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82865_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82875_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_7205_0,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7501_MCH,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855PM_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855GM_HB,	asus_hides_smbus_hostbridge);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge);
+ 
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82810_IG3,	asus_hides_smbus_hostbridge );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82810_IG3,	asus_hides_smbus_hostbridge);
+ 
+ static void asus_hides_smbus_lpc(struct pci_dev *dev)
+ {
+@@ -1073,25 +1077,25 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev)
+ 		pci_write_config_word(dev, 0xF2, val & (~0x8));
+ 		pci_read_config_word(dev, 0xF2, &val);
+ 		if (val & 0x8)
+-			printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
++			dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
+ 		else
+-			printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
++			dev_info(&dev->dev, "Enabled i801 SMBus device\n");
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc);
+ 
+ static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
+ {
+@@ -1106,10 +1110,10 @@ static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
+ 	val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */
+ 	writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */
+ 	iounmap(base);
+-	printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n");
++	dev_info(&dev->dev, "Enabled ICH6/i801 SMBus device\n");
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1,	asus_hides_smbus_lpc_ich6 );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1,	asus_hides_smbus_lpc_ich6 );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1,	asus_hides_smbus_lpc_ich6);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_ICH6_1,	asus_hides_smbus_lpc_ich6);
+ 
+ /*
+  * SiS 96x south bridge: BIOS typically hides SMBus device...
+@@ -1119,18 +1123,18 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
+ 	u8 val = 0;
+ 	pci_read_config_byte(dev, 0x77, &val);
+ 	if (val & 0x10) {
+-		printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
++		dev_info(&dev->dev, "Enabling SiS 96x SMBus\n");
+ 		pci_write_config_byte(dev, 0x77, val & ~0x10);
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus);
+ 
+ /*
+  * ... This is further complicated by the fact that some SiS96x south
+@@ -1163,8 +1167,8 @@ static void quirk_sis_503(struct pci_dev *dev)
+ 	dev->device = devid;
+ 	quirk_sis_96x_smbus(dev);
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503);
+ 
+ 
+ /*
+@@ -1191,13 +1195,13 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
+ 		pci_write_config_byte(dev, 0x50, val & (~0xc0));
+ 		pci_read_config_byte(dev, 0x50, &val);
+ 		if (val & 0xc0)
+-			printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
++			dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
+ 		else
+-			printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n");
++			dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n");
+ 	}
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
+-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
+ 
+ #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
+ 
+@@ -1292,7 +1296,7 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
+ 	}
+ 
+ }
+-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic );
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic);
+ #endif
+ 
+ int pcie_mch_quirk;
+@@ -1302,9 +1306,9 @@ static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
+ {
+ 	pcie_mch_quirk = 1;
+ }
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7520_MCH,	quirk_pcie_mch );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7320_MCH,	quirk_pcie_mch );
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_pcie_mch );
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7520_MCH,	quirk_pcie_mch);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7320_MCH,	quirk_pcie_mch);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_pcie_mch);
+ 
+ 
+ /*
+@@ -1314,11 +1318,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quir
+ static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
+ {
+ 	pci_msi_off(dev);
+-
+ 	dev->no_msi = 1;
+-
+-	printk(KERN_WARNING "PCI: PXH quirk detected, "
+-		"disabling MSI for SHPC device\n");
++	dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n");
+ }
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHD_0,	quirk_pcie_pxh);
+ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHD_1,	quirk_pcie_pxh);
+@@ -1399,7 +1400,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
+ 	case PCI_DEVICE_ID_NETMOS_9855:
+ 		if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+ 		    num_parallel) {
+-			printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
++			dev_info(&dev->dev, "Netmos %04x (%u parallel, "
+ 				"%u serial); changing class SERIAL to OTHER "
+ 				"(use parport_serial)\n",
+ 				dev->device, num_parallel, num_serial);
+@@ -1412,9 +1413,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+ 
+ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
+ {
+-	u16 command;
++	u16 command, pmcsr;
+ 	u8 __iomem *csr;
+ 	u8 cmd_hi;
++	int pm;
+ 
+ 	switch (dev->device) {
+ 	/* PCI IDs taken from drivers/net/e100.c */
+@@ -1448,18 +1450,28 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
+ 	if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0))
+ 		return;
+ 
++	/*
++	 * Check that the device is in the D0 power state. If it's not,
++	 * there is no point to look any further.
++	 */
++	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
++	if (pm) {
++		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
++		if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0)
++			return;
++	}
++
+ 	/* Convert from PCI bus to resource space.  */
+ 	csr = ioremap(pci_resource_start(dev, 0), 8);
+ 	if (!csr) {
+-		printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
+-			pci_name(dev));
++		dev_warn(&dev->dev, "Can't map e100 registers\n");
+ 		return;
+ 	}
+ 
+ 	cmd_hi = readb(csr + 3);
+ 	if (cmd_hi == 0) {
+-		printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts "
+-			"enabled, disabling\n", pci_name(dev));
++		dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; "
++			"disabling\n");
+ 		writeb(1, csr + 3);
+ 	}
+ 
+@@ -1474,7 +1486,7 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
+ 	 */
+ 
+ 	if (dev->class == PCI_CLASS_NOT_DEFINED) {
+-		printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n");
++		dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n");
+ 		dev->class = PCI_CLASS_STORAGE_SCSI;
+ 	}
+ }
+@@ -1485,7 +1497,11 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f
+ 	while (f < end) {
+ 		if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
+  		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+-			pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
++#ifdef DEBUG
++			dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook);
++			print_fn_descriptor_symbol(": %s()\n",
++				(unsigned long) f->hook);
++#endif
+ 			f->hook(dev);
+ 		}
+ 		f++;
+@@ -1553,7 +1569,7 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
+ 	pci_read_config_word(dev, 0x40, &en1k);
+ 
+ 	if (en1k & 0x200) {
+-		printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n");
++		dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n");
+ 
+ 		pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+ 		pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+@@ -1585,7 +1601,7 @@ static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+ 		iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+ 
+ 		if (iobl_adr != iobl_adr_1k) {
+-			printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
++			dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n",
+ 				iobl_adr,iobl_adr_1k);
+ 			pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+ 		}
+@@ -1603,9 +1619,8 @@ static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
+ 	if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
+ 		if (!(b & 0x20)) {
+ 			pci_write_config_byte(dev, 0xf41, b | 0x20);
+-			printk(KERN_INFO
+-			       "PCI: Linking AER extended capability on %s\n",
+-			       pci_name(dev));
++			dev_info(&dev->dev,
++			       "Linking AER extended capability\n");
+ 		}
+ 	}
+ }
+@@ -1614,6 +1629,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ 			quirk_nvidia_ck804_pcie_aer_ext_cap);
+ 
++static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
++{
++	/*
++	 * Disable PCI Bus Parking and PCI Master read caching on CX700
++	 * which causes unspecified timing errors with a VT6212L on the PCI
++	 * bus leading to USB2.0 packet loss. The defaults are that these
++	 * features are turned off but some BIOSes turn them on.
++	 */
++
++	uint8_t b;
++	if (pci_read_config_byte(dev, 0x76, &b) == 0) {
++		if (b & 0x40) {
++			/* Turn off PCI Bus Parking */
++			pci_write_config_byte(dev, 0x76, b ^ 0x40);
++
++			/* Turn off PCI Master read caching */
++			pci_write_config_byte(dev, 0x72, 0x0);
++			pci_write_config_byte(dev, 0x75, 0x1);
++			pci_write_config_byte(dev, 0x77, 0x0);
++
++			printk(KERN_INFO
++				"PCI: VIA CX700 PCI parking/caching fixup on %s\n",
++				pci_name(dev));
++		}
++	}
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
++
+ #ifdef CONFIG_PCI_MSI
+ /* Some chipsets do not support MSI. We cannot easily rely on setting
+  * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
+@@ -1624,7 +1667,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ static void __init quirk_disable_all_msi(struct pci_dev *dev)
+ {
+ 	pci_no_msi();
+-	printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
++	dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n");
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
+@@ -1635,9 +1678,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab
+ static void __devinit quirk_disable_msi(struct pci_dev *dev)
+ {
+ 	if (dev->subordinate) {
+-		printk(KERN_WARNING "PCI: MSI quirk detected. "
+-		       "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
+-		       pci_name(dev));
++		dev_warn(&dev->dev, "MSI quirk detected; "
++			"subordinate MSI disabled\n");
+ 		dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ 	}
+ }
+@@ -1656,9 +1698,9 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
+ 		if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ 					 &flags) == 0)
+ 		{
+-			printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
++			dev_info(&dev->dev, "Found %s HT MSI Mapping\n",
+ 				flags & HT_MSI_FLAGS_ENABLE ?
+-				"enabled" : "disabled", pci_name(dev));
++				"enabled" : "disabled");
+ 			return (flags & HT_MSI_FLAGS_ENABLE) != 0;
+ 		}
+ 
+@@ -1672,17 +1714,40 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
+ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
+ {
+ 	if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
+-		printk(KERN_WARNING "PCI: MSI quirk detected. "
+-		       "MSI disabled on chipset %s.\n",
+-		       pci_name(dev));
++		dev_warn(&dev->dev, "MSI quirk detected; "
++			"subordinate MSI disabled\n");
+ 		dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ 	}
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
+ 			quirk_msi_ht_cap);
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS,
+-			PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
+-			quirk_msi_ht_cap);
++
++
++/*
++ *  Force enable MSI mapping capability on HT bridges
++ */
++static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev)
++{
++	int pos, ttl = 48;
++
++	pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
++	while (pos && ttl--) {
++		u8 flags;
++
++		if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) {
++			printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n",
++			       pci_name(dev));
++
++			pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
++					      flags | HT_MSI_FLAGS_ENABLE);
++		}
++		pos = pci_find_next_ht_capability(dev, pos,
++						  HT_CAPTYPE_MSI_MAPPING);
++	}
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
++			 PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
++			 quirk_msi_ht_cap_enable);
+ 
+ /* The nVidia CK804 chipset may have 2 HT MSI mappings.
+  * MSI are supported if the MSI capability set in any of these mappings.
+@@ -1701,9 +1766,8 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
+ 	if (!pdev)
+ 		return;
+ 	if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) {
+-		printk(KERN_WARNING "PCI: MSI quirk detected. "
+-		       "MSI disabled on chipset %s.\n",
+-		       pci_name(dev));
++		dev_warn(&dev->dev, "MSI quirk detected; "
++			"subordinate MSI disabled\n");
+ 		dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ 	}
+ 	pci_dev_put(pdev);
+@@ -1715,6 +1779,23 @@ static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
+ {
+ 	dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+ }
++static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev)
++{
++	struct pci_dev *p;
++
++	/* SB700 MSI issue will be fixed at HW level from revision A21,
++	 * we need check PCI REVISION ID of SMBus controller to get SB700
++	 * revision.
++	 */
++	p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
++			   NULL);
++	if (!p)
++		return;
++
++	if ((p->revision < 0x3B) && (p->revision >= 0x30))
++		dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
++	pci_dev_put(p);
++}
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ 			PCI_DEVICE_ID_TIGON3_5780,
+ 			quirk_msi_intx_disable_bug);
+@@ -1735,17 +1816,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ 			quirk_msi_intx_disable_bug);
+ 
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390,
+-			quirk_msi_intx_disable_bug);
++			quirk_msi_intx_disable_ati_bug);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391,
+-			quirk_msi_intx_disable_bug);
++			quirk_msi_intx_disable_ati_bug);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392,
+-			quirk_msi_intx_disable_bug);
++			quirk_msi_intx_disable_ati_bug);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393,
+-			quirk_msi_intx_disable_bug);
++			quirk_msi_intx_disable_ati_bug);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394,
+-			quirk_msi_intx_disable_bug);
+-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395,
+-			quirk_msi_intx_disable_bug);
++			quirk_msi_intx_disable_ati_bug);
+ 
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373,
+ 			quirk_msi_intx_disable_bug);
+diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
+index 430281b..ec4a82b 100644
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -1,5 +1,6 @@
+ #include <linux/pci.h>
+ #include <linux/module.h>
++#include <linux/aspm.h>
+ #include "pci.h"
+ 
+ static void pci_free_resources(struct pci_dev *dev)
+@@ -30,6 +31,9 @@ static void pci_stop_dev(struct pci_dev *dev)
+ 		dev->global_list.next = dev->global_list.prev = NULL;
+ 		up_write(&pci_bus_sem);
+ 	}
++
++	if (dev->bus->self)
++		pcie_aspm_exit_link_state(dev);
+ }
+ 
+ static void pci_destroy_dev(struct pci_dev *dev)
+@@ -74,10 +78,8 @@ void pci_remove_bus(struct pci_bus *pci_bus)
+ 	list_del(&pci_bus->node);
+ 	up_write(&pci_bus_sem);
+ 	pci_remove_legacy_files(pci_bus);
+-	class_device_remove_file(&pci_bus->class_dev,
+-		&class_device_attr_cpuaffinity);
+-	sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge");
+-	class_device_unregister(&pci_bus->class_dev);
++	device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
++	device_unregister(&pci_bus->dev);
+ }
+ EXPORT_SYMBOL(pci_remove_bus);
+ 
+diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
+index dbbcc04..a98b247 100644
+--- a/drivers/pci/rom.c
++++ b/drivers/pci/rom.c
+@@ -162,6 +162,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
+ 	return rom;
+ }
+ 
++#if 0
+ /**
+  * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
+  * @pdev: pointer to pci device struct
+@@ -196,6 +197,7 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
+ 
+ 	return (void __iomem *)(unsigned long)res->start;
+ }
++#endif  /*  0  */
+ 
+ /**
+  * pci_unmap_rom - unmap the ROM from kernel space
+@@ -218,6 +220,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
+ 		pci_disable_rom(pdev);
+ }
+ 
++#if 0
+ /**
+  * pci_remove_rom - disable the ROM and remove its sysfs attribute
+  * @pdev: pointer to pci device struct
+@@ -236,6 +239,7 @@ void pci_remove_rom(struct pci_dev *pdev)
+ 			    IORESOURCE_ROM_COPY)))
+ 		pci_disable_rom(pdev);
+ }
++#endif  /*  0  */
+ 
+ /**
+  * pci_cleanup_rom - internal routine for freeing the ROM copy created
+@@ -256,6 +260,4 @@ void pci_cleanup_rom(struct pci_dev *pdev)
+ }
+ 
+ EXPORT_SYMBOL(pci_map_rom);
+-EXPORT_SYMBOL(pci_map_rom_copy);
+ EXPORT_SYMBOL(pci_unmap_rom);
+-EXPORT_SYMBOL(pci_remove_rom);
+diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
+index 401e03c..8a7232f 100644
+--- a/drivers/pci/setup-bus.c
++++ b/drivers/pci/setup-bus.c
+@@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
+ 		 * The IO resource is allocated a range twice as large as it
+ 		 * would normally need.  This allows us to set both IO regs.
+ 		 */
+-		printk("  IO window: %08lx-%08lx\n",
+-			region.start, region.end);
++		printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
++		       (unsigned long)region.start,
++		       (unsigned long)region.end);
+ 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
+ 					region.start);
+ 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
+@@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
+ 
+ 	pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
+ 	if (bus->resource[1]->flags & IORESOURCE_IO) {
+-		printk("  IO window: %08lx-%08lx\n",
+-			region.start, region.end);
++		printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
++		       (unsigned long)region.start,
++		       (unsigned long)region.end);
+ 		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
+ 					region.start);
+ 		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
+@@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
+ 
+ 	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
+ 	if (bus->resource[2]->flags & IORESOURCE_MEM) {
+-		printk("  PREFETCH window: %08lx-%08lx\n",
+-			region.start, region.end);
++		printk(KERN_INFO "  PREFETCH window: 0x%08lx-0x%08lx\n",
++		       (unsigned long)region.start,
++		       (unsigned long)region.end);
+ 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
+ 					region.start);
+ 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
+@@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
+ 
+ 	pcibios_resource_to_bus(bridge, &region, bus->resource[3]);
+ 	if (bus->resource[3]->flags & IORESOURCE_MEM) {
+-		printk("  MEM window: %08lx-%08lx\n",
+-			region.start, region.end);
++		printk(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
++		       (unsigned long)region.start,
++		       (unsigned long)region.end);
+ 		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
+ 					region.start);
+ 		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
+@@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus)
+ {
+ 	struct pci_dev *bridge = bus->self;
+ 	struct pci_bus_region region;
+-	u32 l, io_upper16;
++	u32 l, bu, lu, io_upper16;
+ 
+ 	DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
+ 
+@@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus)
+ 		/* Set up upper 16 bits of I/O base/limit. */
+ 		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
+ 		DBG(KERN_INFO "  IO window: %04lx-%04lx\n",
+-				region.start, region.end);
++		    (unsigned long)region.start,
++		    (unsigned long)region.end);
+ 	}
+ 	else {
+ 		/* Clear upper 16 bits of I/O base/limit. */
+@@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus)
+ 	if (bus->resource[1]->flags & IORESOURCE_MEM) {
+ 		l = (region.start >> 16) & 0xfff0;
+ 		l |= region.end & 0xfff00000;
+-		DBG(KERN_INFO "  MEM window: %08lx-%08lx\n",
+-				region.start, region.end);
++		DBG(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
++		    (unsigned long)region.start,
++		    (unsigned long)region.end);
+ 	}
+ 	else {
+ 		l = 0x0000fff0;
+@@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus)
+ 	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+ 
+ 	/* Set up PREF base/limit. */
++	bu = lu = 0;
+ 	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
+ 	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+ 		l = (region.start >> 16) & 0xfff0;
+ 		l |= region.end & 0xfff00000;
+-		DBG(KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
+-				region.start, region.end);
++#ifdef CONFIG_RESOURCES_64BIT
++		bu = region.start >> 32;
++		lu = region.end >> 32;
++#endif
++		DBG(KERN_INFO "  PREFETCH window: 0x%016llx-0x%016llx\n",
++		    (unsigned long long)region.start,
++		    (unsigned long long)region.end);
+ 	}
+ 	else {
+ 		l = 0x0000fff0;
+@@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus)
+ 	}
+ 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+ 
+-	/* Clear out the upper 32 bits of PREF base. */
+-	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
++	/* Set the upper 32 bits of PREF base & limit. */
++	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
++	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
+ 
+ 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
+ }
+@@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus *bus)
+ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+ {
+ 	struct pci_dev *dev;
+-	unsigned long min_align, align, size;
+-	unsigned long aligns[12];	/* Alignments from 1Mb to 2Gb */
++	resource_size_t min_align, align, size;
++	resource_size_t aligns[12];	/* Alignments from 1Mb to 2Gb */
+ 	int order, max_order;
+ 	struct resource *b_res = find_free_bus_resource(bus, type);
+ 
+@@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
+ 		
+ 		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ 			struct resource *r = &dev->resource[i];
+-			unsigned long r_size;
++			resource_size_t r_size;
+ 
+ 			if (r->parent || (r->flags & mask) != type)
+ 				continue;
+@@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
+ 			order = __ffs(align) - 20;
+ 			if (order > 11) {
+ 				printk(KERN_WARNING "PCI: region %s/%d "
+-				       "too large: %llx-%llx\n",
++				       "too large: 0x%016llx-0x%016llx\n",
+ 					pci_name(dev), i,
+-					(unsigned long long)r->start,
+-					(unsigned long long)r->end);
++				       (unsigned long long)r->start,
++				       (unsigned long long)r->end);
+ 				r->flags = 0;
+ 				continue;
+ 			}
+@@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
+ 	align = 0;
+ 	min_align = 0;
+ 	for (order = 0; order <= max_order; order++) {
+-		unsigned long align1 = 1UL << (order + 20);
+-
++#ifdef CONFIG_RESOURCES_64BIT
++		resource_size_t align1 = 1ULL << (order + 20);
++#else
++		resource_size_t align1 = 1U << (order + 20);
++#endif
+ 		if (!align)
+ 			min_align = align1;
+ 		else if (ALIGN(align + min_align, min_align) < align1)
+diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
+index 6dfd861..4be7ccf 100644
+--- a/drivers/pci/setup-res.c
++++ b/drivers/pci/setup-res.c
+@@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
+ 
+ 	pcibios_resource_to_bus(dev, &region, res);
+ 
+-	pr_debug("  got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
++	pr_debug("  got res [%llx:%llx] bus [%llx:%llx] flags %lx for "
+ 		 "BAR %d of %s\n", (unsigned long long)res->start,
+ 		 (unsigned long long)res->end,
+-		 region.start, region.end, res->flags, resno, pci_name(dev));
++		 (unsigned long long)region.start,
++		 (unsigned long long)region.end,
++		 (unsigned long)res->flags, resno, pci_name(dev));
+ 
+ 	new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
+ 	if (res->flags & IORESOURCE_IO)
+@@ -125,7 +127,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
+ 
+ 	return err;
+ }
+-EXPORT_SYMBOL_GPL(pci_claim_resource);
+ 
+ int pci_assign_resource(struct pci_dev *dev, int resno)
+ {
+diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
+index 2ac050d..645d7a6 100644
+--- a/drivers/pci/syscall.c
++++ b/drivers/pci/syscall.c
+@@ -34,7 +34,6 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ 	if (!dev)
+ 		goto error;
+ 
+-	lock_kernel();
+ 	switch (len) {
+ 	case 1:
+ 		cfg_ret = pci_user_read_config_byte(dev, off, &byte);
+@@ -47,10 +46,8 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ 		break;
+ 	default:
+ 		err = -EINVAL;
+-		unlock_kernel();
+ 		goto error;
+ 	};
+-	unlock_kernel();
+ 
+ 	err = -EIO;
+ 	if (cfg_ret != PCIBIOS_SUCCESSFUL)
+@@ -107,7 +104,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ 	if (!dev)
+ 		return -ENODEV;
+ 
+-	lock_kernel();
+ 	switch(len) {
+ 	case 1:
+ 		err = get_user(byte, (u8 __user *)buf);
+@@ -140,7 +136,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ 		err = -EINVAL;
+ 		break;
+ 	}
+-	unlock_kernel();
+ 	pci_dev_put(dev);
+ 	return err;
+ }
 diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
 index 5cf89a9..15c18f5 100644
 --- a/drivers/pcmcia/ds.c
@@ -656319,19 +684068,22 @@
  	_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
  	for (i = 0; i < NR_CPUS; i++) {
 diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
-index bbf3ee1..7e29b90 100644
+index bbf3ee1..a489227 100644
 --- a/drivers/power/apm_power.c
 +++ b/drivers/power/apm_power.c
 @@ -13,6 +13,7 @@
  #include <linux/power_supply.h>
  #include <linux/apm-emulation.h>
  
-+static DEFINE_MUTEX(apm_mutex);
++
  #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
  			 POWER_SUPPLY_PROP_##prop, val)
  
-@@ -23,67 +24,86 @@
+@@ -21,73 +22,99 @@
  
+ #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
+ 
++static DEFINE_MUTEX(apm_mutex);
  static struct power_supply *main_battery;
  
 -static void find_main_battery(void)
@@ -656340,6 +684092,12 @@
 -	struct power_supply *bat = NULL;
 -	struct power_supply *max_charge_bat = NULL;
 -	struct power_supply *max_energy_bat = NULL;
++enum apm_source {
++	SOURCE_ENERGY,
++	SOURCE_CHARGE,
++	SOURCE_VOLTAGE,
++};
++
 +struct find_bat_param {
 +	struct power_supply *main;
 +	struct power_supply *bat;
@@ -656399,7 +684157,9 @@
  	}
 +	return 0;
 +}
-+
+ 
+-	if ((max_energy_bat && max_charge_bat) &&
+-			(max_energy_bat != max_charge_bat)) {
 +static void find_main_battery(void)
 +{
 +	struct find_bat_param bp;
@@ -656415,9 +684175,7 @@
 +		main_battery = bp.main;
 +		return;
 +	}
- 
--	if ((max_energy_bat && max_charge_bat) &&
--			(max_energy_bat != max_charge_bat)) {
++
 +	if ((bp.max_energy_bat && bp.max_charge_bat) &&
 +			(bp.max_energy_bat != bp.max_charge_bat)) {
  		/* try guess battery with more capacity */
@@ -656462,7 +684220,116 @@
  	}
  }
  
-@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+-static int calculate_time(int status, int using_charge)
++static int do_calculate_time(int status, enum apm_source source)
+ {
+ 	union power_supply_propval full;
+ 	union power_supply_propval empty;
+@@ -106,20 +133,37 @@ static int calculate_time(int status, int using_charge)
+ 			return -1;
+ 	}
+ 
+-	if (using_charge) {
++	if (!I.intval)
++		return 0;
++
++	switch (source) {
++	case SOURCE_CHARGE:
+ 		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+ 		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+ 		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ 		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ 		cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+ 		cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+-	} else {
++		break;
++	case SOURCE_ENERGY:
+ 		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+ 		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+ 		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+ 		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ 		cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+ 		cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
++		break;
++	case SOURCE_VOLTAGE:
++		full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
++		full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
++		empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
++		empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
++		cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
++		cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
++		break;
++	default:
++		printk(KERN_ERR "Unsupported source: %d\n", source);
++		return -1;
+ 	}
+ 
+ 	if (_MPSY_PROP(full_prop, &full)) {
+@@ -146,7 +190,26 @@ static int calculate_time(int status, int using_charge)
+ 		return -((cur.intval - empty.intval) * 60L) / I.intval;
+ }
+ 
+-static int calculate_capacity(int using_charge)
++static int calculate_time(int status)
++{
++	int time;
++
++	time = do_calculate_time(status, SOURCE_ENERGY);
++	if (time != -1)
++		return time;
++
++	time = do_calculate_time(status, SOURCE_CHARGE);
++	if (time != -1)
++		return time;
++
++	time = do_calculate_time(status, SOURCE_VOLTAGE);
++	if (time != -1)
++		return time;
++
++	return -1;
++}
++
++static int calculate_capacity(enum apm_source source)
+ {
+ 	enum power_supply_property full_prop, empty_prop;
+ 	enum power_supply_property full_design_prop, empty_design_prop;
+@@ -154,20 +217,33 @@ static int calculate_capacity(int using_charge)
+ 	union power_supply_propval empty, full, cur;
+ 	int ret;
+ 
+-	if (using_charge) {
++	switch (source) {
++	case SOURCE_CHARGE:
+ 		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+ 		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ 		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+ 		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
+ 		now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+ 		avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+-	} else {
++		break;
++	case SOURCE_ENERGY:
+ 		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+ 		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+ 		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+ 		empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
+ 		now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
+ 		avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
++	case SOURCE_VOLTAGE:
++		full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
++		empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
++		full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
++		empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
++		now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
++		avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
++		break;
++	default:
++		printk(KERN_ERR "Unsupported source: %d\n", source);
++		return -1;
+ 	}
+ 
+ 	if (_MPSY_PROP(full_prop, &full)) {
+@@ -207,10 +283,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
  	union power_supply_propval status;
  	union power_supply_propval capacity, time_to_full, time_to_empty;
  
@@ -656475,8 +684342,47 @@
  		return;
  	}
  
-@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
- 		}
+@@ -234,10 +310,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+ 		info->battery_life = capacity.intval;
+ 	} else {
+ 		/* try calculate using energy */
+-		info->battery_life = calculate_capacity(0);
++		info->battery_life = calculate_capacity(SOURCE_ENERGY);
+ 		/* if failed try calculate using charge instead */
+ 		if (info->battery_life == -1)
+-			info->battery_life = calculate_capacity(1);
++			info->battery_life = calculate_capacity(SOURCE_CHARGE);
++		if (info->battery_life == -1)
++			info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
+ 	}
+ 
+ 	/* charging status */
+@@ -260,25 +338,19 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+ 
+ 	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
+ 		if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
+-				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
++				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
+ 			info->time = time_to_full.intval / 60;
+-		} else {
+-			info->time = calculate_time(status.intval, 0);
+-			if (info->time == -1)
+-				info->time = calculate_time(status.intval, 1);
+-		}
++		else
++			info->time = calculate_time(status.intval);
+ 	} else {
+ 		if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
+-			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
++			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
+ 			info->time = time_to_empty.intval / 60;
+-		} else {
+-			info->time = calculate_time(status.intval, 0);
+-			if (info->time == -1)
+-				info->time = calculate_time(status.intval, 1);
+-		}
++		else
++			info->time = calculate_time(status.intval);
  	}
  
 -	up(&power_supply_class->sem);
@@ -656484,6 +684390,419 @@
  }
  
  static int __init apm_battery_init(void)
+diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
+index c998e68..af7a231 100644
+--- a/drivers/power/olpc_battery.c
++++ b/drivers/power/olpc_battery.c
+@@ -226,14 +226,6 @@ static int olpc_bat_get_property(struct power_supply *psy,
+ 			return ret;
+ 		val->intval = ec_byte;
+ 		break;
+-	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+-		if (ec_byte & BAT_STAT_FULL)
+-			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+-		else if (ec_byte & BAT_STAT_LOW)
+-			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+-		else
+-			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+-		break;
+ 	case POWER_SUPPLY_PROP_TEMP:
+ 		ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
+ 		if (ret)
+@@ -265,7 +257,6 @@ static enum power_supply_property olpc_bat_props[] = {
+ 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ 	POWER_SUPPLY_PROP_CURRENT_AVG,
+ 	POWER_SUPPLY_PROP_CAPACITY,
+-	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ 	POWER_SUPPLY_PROP_TEMP,
+ 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ 	POWER_SUPPLY_PROP_MANUFACTURER,
+diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
+index c058f28..c8aa55b 100644
+--- a/drivers/power/pda_power.c
++++ b/drivers/power/pda_power.c
+@@ -32,6 +32,18 @@ static struct pda_power_pdata *pdata;
+ static struct resource *ac_irq, *usb_irq;
+ static struct timer_list charger_timer;
+ static struct timer_list supply_timer;
++static struct timer_list polling_timer;
++static int polling;
++
++enum {
++	PDA_PSY_OFFLINE = 0,
++	PDA_PSY_ONLINE = 1,
++	PDA_PSY_TO_CHANGE,
++};
++static int new_ac_status = -1;
++static int new_usb_status = -1;
++static int ac_status = -1;
++static int usb_status = -1;
+ 
+ static int pda_power_get_property(struct power_supply *psy,
+ 				  enum power_supply_property psp,
+@@ -61,36 +73,44 @@ static char *pda_power_supplied_to[] = {
+ 	"backup-battery",
+ };
+ 
+-static struct power_supply pda_power_supplies[] = {
+-	{
+-		.name = "ac",
+-		.type = POWER_SUPPLY_TYPE_MAINS,
+-		.supplied_to = pda_power_supplied_to,
+-		.num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+-		.properties = pda_power_props,
+-		.num_properties = ARRAY_SIZE(pda_power_props),
+-		.get_property = pda_power_get_property,
+-	},
+-	{
+-		.name = "usb",
+-		.type = POWER_SUPPLY_TYPE_USB,
+-		.supplied_to = pda_power_supplied_to,
+-		.num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+-		.properties = pda_power_props,
+-		.num_properties = ARRAY_SIZE(pda_power_props),
+-		.get_property = pda_power_get_property,
+-	},
++static struct power_supply pda_psy_ac = {
++	.name = "ac",
++	.type = POWER_SUPPLY_TYPE_MAINS,
++	.supplied_to = pda_power_supplied_to,
++	.num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
++	.properties = pda_power_props,
++	.num_properties = ARRAY_SIZE(pda_power_props),
++	.get_property = pda_power_get_property,
+ };
+ 
++static struct power_supply pda_psy_usb = {
++	.name = "usb",
++	.type = POWER_SUPPLY_TYPE_USB,
++	.supplied_to = pda_power_supplied_to,
++	.num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
++	.properties = pda_power_props,
++	.num_properties = ARRAY_SIZE(pda_power_props),
++	.get_property = pda_power_get_property,
++};
++
++static void update_status(void)
++{
++	if (pdata->is_ac_online)
++		new_ac_status = !!pdata->is_ac_online();
++
++	if (pdata->is_usb_online)
++		new_usb_status = !!pdata->is_usb_online();
++}
++
+ static void update_charger(void)
+ {
+ 	if (!pdata->set_charge)
+ 		return;
+ 
+-	if (pdata->is_ac_online && pdata->is_ac_online()) {
++	if (new_ac_status > 0) {
+ 		dev_dbg(dev, "charger on (AC)\n");
+ 		pdata->set_charge(PDA_POWER_CHARGE_AC);
+-	} else if (pdata->is_usb_online && pdata->is_usb_online()) {
++	} else if (new_usb_status > 0) {
+ 		dev_dbg(dev, "charger on (USB)\n");
+ 		pdata->set_charge(PDA_POWER_CHARGE_USB);
+ 	} else {
+@@ -99,34 +119,81 @@ static void update_charger(void)
+ 	}
+ }
+ 
+-static void supply_timer_func(unsigned long power_supply_ptr)
++static void supply_timer_func(unsigned long unused)
+ {
+-	void *power_supply = (void *)power_supply_ptr;
++	if (ac_status == PDA_PSY_TO_CHANGE) {
++		ac_status = new_ac_status;
++		power_supply_changed(&pda_psy_ac);
++	}
+ 
+-	power_supply_changed(power_supply);
++	if (usb_status == PDA_PSY_TO_CHANGE) {
++		usb_status = new_usb_status;
++		power_supply_changed(&pda_psy_usb);
++	}
+ }
+ 
+-static void charger_timer_func(unsigned long power_supply_ptr)
++static void psy_changed(void)
+ {
+ 	update_charger();
+ 
+-	/* Okay, charger set. Now wait a bit before notifying supplicants,
+-	 * charge power should stabilize. */
+-	supply_timer.data = power_supply_ptr;
++	/*
++	 * Okay, charger set. Now wait a bit before notifying supplicants,
++	 * charge power should stabilize.
++	 */
+ 	mod_timer(&supply_timer,
+ 		  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
+ }
+ 
++static void charger_timer_func(unsigned long unused)
++{
++	update_status();
++	psy_changed();
++}
++
+ static irqreturn_t power_changed_isr(int irq, void *power_supply)
+ {
+-	/* Wait a bit before reading ac/usb line status and setting charger,
+-	 * because ac/usb status readings may lag from irq. */
+-	charger_timer.data = (unsigned long)power_supply;
++	if (power_supply == &pda_psy_ac)
++		ac_status = PDA_PSY_TO_CHANGE;
++	else if (power_supply == &pda_psy_usb)
++		usb_status = PDA_PSY_TO_CHANGE;
++	else
++		return IRQ_NONE;
++
++	/*
++	 * Wait a bit before reading ac/usb line status and setting charger,
++	 * because ac/usb status readings may lag from irq.
++	 */
+ 	mod_timer(&charger_timer,
+ 		  jiffies + msecs_to_jiffies(pdata->wait_for_status));
++
+ 	return IRQ_HANDLED;
+ }
+ 
++static void polling_timer_func(unsigned long unused)
++{
++	int changed = 0;
++
++	dev_dbg(dev, "polling...\n");
++
++	update_status();
++
++	if (!ac_irq && new_ac_status != ac_status) {
++		ac_status = PDA_PSY_TO_CHANGE;
++		changed = 1;
++	}
++
++	if (!usb_irq && new_usb_status != usb_status) {
++		usb_status = PDA_PSY_TO_CHANGE;
++		changed = 1;
++	}
++
++	if (changed)
++		psy_changed();
++
++	mod_timer(&polling_timer,
++		  jiffies + msecs_to_jiffies(pdata->polling_interval));
++}
++
+ static int pda_power_probe(struct platform_device *pdev)
+ {
+ 	int ret = 0;
+@@ -142,6 +209,7 @@ static int pda_power_probe(struct platform_device *pdev)
+ 
+ 	pdata = pdev->dev.platform_data;
+ 
++	update_status();
+ 	update_charger();
+ 
+ 	if (!pdata->wait_for_status)
+@@ -150,86 +218,138 @@ static int pda_power_probe(struct platform_device *pdev)
+ 	if (!pdata->wait_for_charger)
+ 		pdata->wait_for_charger = 500;
+ 
++	if (!pdata->polling_interval)
++		pdata->polling_interval = 2000;
++
+ 	setup_timer(&charger_timer, charger_timer_func, 0);
+ 	setup_timer(&supply_timer, supply_timer_func, 0);
+ 
+ 	ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
+ 	usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
+-	if (!ac_irq && !usb_irq) {
+-		dev_err(dev, "no ac/usb irq specified\n");
+-		ret = -ENODEV;
+-		goto noirqs;
+-	}
+ 
+ 	if (pdata->supplied_to) {
+-		pda_power_supplies[0].supplied_to = pdata->supplied_to;
+-		pda_power_supplies[1].supplied_to = pdata->supplied_to;
+-		pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
+-		pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
++		pda_psy_ac.supplied_to = pdata->supplied_to;
++		pda_psy_ac.num_supplicants = pdata->num_supplicants;
++		pda_psy_usb.supplied_to = pdata->supplied_to;
++		pda_psy_usb.num_supplicants = pdata->num_supplicants;
+ 	}
+ 
+-	ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
+-	if (ret) {
+-		dev_err(dev, "failed to register %s power supply\n",
+-			pda_power_supplies[0].name);
+-		goto supply0_failed;
+-	}
++	if (pdata->is_ac_online) {
++		ret = power_supply_register(&pdev->dev, &pda_psy_ac);
++		if (ret) {
++			dev_err(dev, "failed to register %s power supply\n",
++				pda_psy_ac.name);
++			goto ac_supply_failed;
++		}
+ 
+-	ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
+-	if (ret) {
+-		dev_err(dev, "failed to register %s power supply\n",
+-			pda_power_supplies[1].name);
+-		goto supply1_failed;
++		if (ac_irq) {
++			ret = request_irq(ac_irq->start, power_changed_isr,
++					  get_irq_flags(ac_irq), ac_irq->name,
++					  &pda_psy_ac);
++			if (ret) {
++				dev_err(dev, "request ac irq failed\n");
++				goto ac_irq_failed;
++			}
++		} else {
++			polling = 1;
++		}
+ 	}
+ 
+-	if (ac_irq) {
+-		ret = request_irq(ac_irq->start, power_changed_isr,
+-				  get_irq_flags(ac_irq), ac_irq->name,
+-				  &pda_power_supplies[0]);
++	if (pdata->is_usb_online) {
++		ret = power_supply_register(&pdev->dev, &pda_psy_usb);
+ 		if (ret) {
+-			dev_err(dev, "request ac irq failed\n");
+-			goto ac_irq_failed;
++			dev_err(dev, "failed to register %s power supply\n",
++				pda_psy_usb.name);
++			goto usb_supply_failed;
+ 		}
+-	}
+ 
+-	if (usb_irq) {
+-		ret = request_irq(usb_irq->start, power_changed_isr,
+-				  get_irq_flags(usb_irq), usb_irq->name,
+-				  &pda_power_supplies[1]);
+-		if (ret) {
+-			dev_err(dev, "request usb irq failed\n");
+-			goto usb_irq_failed;
++		if (usb_irq) {
++			ret = request_irq(usb_irq->start, power_changed_isr,
++					  get_irq_flags(usb_irq),
++					  usb_irq->name, &pda_psy_usb);
++			if (ret) {
++				dev_err(dev, "request usb irq failed\n");
++				goto usb_irq_failed;
++			}
++		} else {
++			polling = 1;
+ 		}
+ 	}
+ 
+-	goto success;
++	if (polling) {
++		dev_dbg(dev, "will poll for status\n");
++		setup_timer(&polling_timer, polling_timer_func, 0);
++		mod_timer(&polling_timer,
++			  jiffies + msecs_to_jiffies(pdata->polling_interval));
++	}
++
++	if (ac_irq || usb_irq)
++		device_init_wakeup(&pdev->dev, 1);
++
++	return 0;
+ 
+ usb_irq_failed:
+-	if (ac_irq)
+-		free_irq(ac_irq->start, &pda_power_supplies[0]);
++	if (pdata->is_usb_online)
++		power_supply_unregister(&pda_psy_usb);
++usb_supply_failed:
++	if (pdata->is_ac_online && ac_irq)
++		free_irq(ac_irq->start, &pda_psy_ac);
+ ac_irq_failed:
+-	power_supply_unregister(&pda_power_supplies[1]);
+-supply1_failed:
+-	power_supply_unregister(&pda_power_supplies[0]);
+-supply0_failed:
+-noirqs:
++	if (pdata->is_ac_online)
++		power_supply_unregister(&pda_psy_ac);
++ac_supply_failed:
+ wrongid:
+-success:
+ 	return ret;
+ }
+ 
+ static int pda_power_remove(struct platform_device *pdev)
+ {
+-	if (usb_irq)
+-		free_irq(usb_irq->start, &pda_power_supplies[1]);
+-	if (ac_irq)
+-		free_irq(ac_irq->start, &pda_power_supplies[0]);
++	if (pdata->is_usb_online && usb_irq)
++		free_irq(usb_irq->start, &pda_psy_usb);
++	if (pdata->is_ac_online && ac_irq)
++		free_irq(ac_irq->start, &pda_psy_ac);
++
++	if (polling)
++		del_timer_sync(&polling_timer);
+ 	del_timer_sync(&charger_timer);
+ 	del_timer_sync(&supply_timer);
+-	power_supply_unregister(&pda_power_supplies[1]);
+-	power_supply_unregister(&pda_power_supplies[0]);
++
++	if (pdata->is_usb_online)
++		power_supply_unregister(&pda_psy_usb);
++	if (pdata->is_ac_online)
++		power_supply_unregister(&pda_psy_ac);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	if (device_may_wakeup(&pdev->dev)) {
++		if (ac_irq)
++			enable_irq_wake(ac_irq->start);
++		if (usb_irq)
++			enable_irq_wake(usb_irq->start);
++	}
++
++	return 0;
++}
++
++static int pda_power_resume(struct platform_device *pdev)
++{
++	if (device_may_wakeup(&pdev->dev)) {
++		if (usb_irq)
++			disable_irq_wake(usb_irq->start);
++		if (ac_irq)
++			disable_irq_wake(ac_irq->start);
++	}
++
+ 	return 0;
+ }
++#else
++#define pda_power_suspend NULL
++#define pda_power_resume NULL
++#endif /* CONFIG_PM */
+ 
+ static struct platform_driver pda_power_pdrv = {
+ 	.driver = {
+@@ -237,6 +357,8 @@ static struct platform_driver pda_power_pdrv = {
+ 	},
+ 	.probe = pda_power_probe,
+ 	.remove = pda_power_remove,
++	.suspend = pda_power_suspend,
++	.resume = pda_power_resume,
+ };
+ 
+ static int __init pda_power_init(void)
 diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
 index a63b75c..03d6a38 100644
 --- a/drivers/power/power_supply_core.c
@@ -656589,6 +684908,137 @@
  }
  
  int power_supply_register(struct device *parent, struct power_supply *psy)
+diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
+index 7f8f359..fa3034f 100644
+--- a/drivers/power/power_supply_leds.c
++++ b/drivers/power/power_supply_leds.c
+@@ -10,8 +10,11 @@
+  *  You may use this code as per GPL version 2
+  */
+ 
++#include <linux/kernel.h>
+ #include <linux/power_supply.h>
+ 
++#include "power_supply.h"
++
+ /* Battery specific LEDs triggers. */
+ 
+ static void power_supply_update_bat_leds(struct power_supply *psy)
+@@ -46,28 +49,20 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
+ {
+ 	int rc = 0;
+ 
+-	psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
+-				  sizeof("-charging-or-full"), GFP_KERNEL);
++	psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
++					"%s-charging-or-full", psy->name);
+ 	if (!psy->charging_full_trig_name)
+ 		goto charging_full_failed;
+ 
+-	psy->charging_trig_name = kmalloc(strlen(psy->name) +
+-					  sizeof("-charging"), GFP_KERNEL);
++	psy->charging_trig_name = kasprintf(GFP_KERNEL,
++					"%s-charging", psy->name);
+ 	if (!psy->charging_trig_name)
+ 		goto charging_failed;
+ 
+-	psy->full_trig_name = kmalloc(strlen(psy->name) +
+-				      sizeof("-full"), GFP_KERNEL);
++	psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name);
+ 	if (!psy->full_trig_name)
+ 		goto full_failed;
+ 
+-	strcpy(psy->charging_full_trig_name, psy->name);
+-	strcat(psy->charging_full_trig_name, "-charging-or-full");
+-	strcpy(psy->charging_trig_name, psy->name);
+-	strcat(psy->charging_trig_name, "-charging");
+-	strcpy(psy->full_trig_name, psy->name);
+-	strcat(psy->full_trig_name, "-full");
+-
+ 	led_trigger_register_simple(psy->charging_full_trig_name,
+ 				    &psy->charging_full_trig);
+ 	led_trigger_register_simple(psy->charging_trig_name,
+@@ -118,14 +113,10 @@ static int power_supply_create_gen_triggers(struct power_supply *psy)
+ {
+ 	int rc = 0;
+ 
+-	psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
+-					GFP_KERNEL);
++	psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name);
+ 	if (!psy->online_trig_name)
+ 		goto online_failed;
+ 
+-	strcpy(psy->online_trig_name, psy->name);
+-	strcat(psy->online_trig_name, "-online");
+-
+ 	led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
+ 
+ 	goto success;
+diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
+index 249f61b..d482484 100644
+--- a/drivers/power/power_supply_sysfs.c
++++ b/drivers/power/power_supply_sysfs.c
+@@ -14,6 +14,8 @@
+ #include <linux/ctype.h>
+ #include <linux/power_supply.h>
+ 
++#include "power_supply.h"
++
+ /*
+  * This is because the name "current" breaks the device attr macro.
+  * The "current" word resolves to "(get_current())" so instead of
+@@ -46,10 +48,8 @@ static ssize_t power_supply_show_property(struct device *dev,
+ 		"Unspecified failure"
+ 	};
+ 	static char *technology_text[] = {
+-		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd"
+-	};
+-	static char *capacity_level_text[] = {
+-		"Unknown", "Critical", "Low", "Normal", "High", "Full"
++		"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
++		"LiMn"
+ 	};
+ 	ssize_t ret;
+ 	struct power_supply *psy = dev_get_drvdata(dev);
+@@ -71,9 +71,6 @@ static ssize_t power_supply_show_property(struct device *dev,
+ 		return sprintf(buf, "%s\n", health_text[value.intval]);
+ 	else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
+ 		return sprintf(buf, "%s\n", technology_text[value.intval]);
+-	else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
+-		return sprintf(buf, "%s\n",
+-			       capacity_level_text[value.intval]);
+ 	else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
+ 		return sprintf(buf, "%s\n", value.strval);
+ 
+@@ -88,6 +85,8 @@ static struct device_attribute power_supply_attrs[] = {
+ 	POWER_SUPPLY_ATTR(present),
+ 	POWER_SUPPLY_ATTR(online),
+ 	POWER_SUPPLY_ATTR(technology),
++	POWER_SUPPLY_ATTR(voltage_max),
++	POWER_SUPPLY_ATTR(voltage_min),
+ 	POWER_SUPPLY_ATTR(voltage_max_design),
+ 	POWER_SUPPLY_ATTR(voltage_min_design),
+ 	POWER_SUPPLY_ATTR(voltage_now),
+@@ -159,8 +158,7 @@ dynamics_failed:
+ 			   &power_supply_attrs[psy->properties[j]]);
+ statics_failed:
+ 	while (i--)
+-		device_remove_file(psy->dev,
+-			   &power_supply_static_attrs[psy->properties[i]]);
++		device_remove_file(psy->dev, &power_supply_static_attrs[i]);
+ succeed:
+ 	return rc;
+ }
+@@ -170,8 +168,7 @@ void power_supply_remove_attrs(struct power_supply *psy)
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
+-		device_remove_file(psy->dev,
+-			    &power_supply_static_attrs[i]);
++		device_remove_file(psy->dev, &power_supply_static_attrs[i]);
+ 
+ 	for (i = 0; i < psy->num_properties; i++)
+ 		device_remove_file(psy->dev,
 diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
 index 1f5a2d3..ccea15c 100644
 --- a/drivers/ps3/Makefile
@@ -679736,10 +708186,20 @@
  
  	spin_lock_irqsave(&target->lock, flags);
 diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
-index 9706de9..db8bc20 100644
+index 9706de9..5ed0006 100644
 --- a/drivers/scsi/ide-scsi.c
 +++ b/drivers/scsi/ide-scsi.c
-@@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive)
+@@ -1,7 +1,6 @@
+ /*
+- * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
+- *
+- * Copyright (C) 1996 - 1999 Gadi Oxman <gadio at netvision.net.il>
++ * Copyright (C) 1996-1999  Gadi Oxman <gadio at netvision.net.il>
++ * Copyright (C) 2004-2005  Bartlomiej Zolnierkiewicz
+  */
+ 
+ /*
+@@ -395,14 +394,12 @@ static int idescsi_expiry(ide_drive_t *drive)
  static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
  {
  	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
@@ -679758,7 +708218,7 @@
  
  #if IDESCSI_DEBUG_LOG
  	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
-@@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+@@ -425,30 +422,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
  		(void) HWIF(drive)->ide_dma_end(drive);
  	}
  
@@ -679798,7 +708258,7 @@
  		if (temp > pc->request_transfer) {
  			if (temp > pc->buffer_size) {
  				printk(KERN_ERR "ide-scsi: The scsi wants to "
-@@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+@@ -461,11 +457,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
  						idescsi_input_buffers(drive, pc, temp);
  					else
  						drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
@@ -679814,7 +708274,7 @@
  				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
  				return ide_started;
  			}
-@@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+@@ -474,22 +472,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
  #endif /* IDESCSI_DEBUG_LOG */
  		}
  	}
@@ -679846,7 +708306,7 @@
  
  	/* And set the interrupt handler again */
  	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
-@@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
+@@ -501,16 +501,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
  	ide_hwif_t *hwif = drive->hwif;
  	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
  	idescsi_pc_t *pc = scsi->pc;
@@ -679866,7 +708326,7 @@
  		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
  				"issuing a packet command\n");
  		return ide_do_reset (drive);
-@@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+@@ -573,30 +573,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
  {
  	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
  	ide_hwif_t *hwif = drive->hwif;
@@ -679904,7 +708364,7 @@
  		set_bit(PC_DMA_OK, &pc->flags);
  
  	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-@@ -922,8 +919,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
+@@ -922,8 +918,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
  	}
  
  	/* kill current request */
@@ -679915,7 +708375,7 @@
  	if (blk_sense_request(req))
  		kfree(scsi->pc->buffer);
  	kfree(scsi->pc);
-@@ -932,8 +929,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
+@@ -932,8 +928,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
  
  	/* now nuke the drive queue */
  	while ((req = elv_next_request(drive->queue))) {
@@ -690222,7 +718682,7 @@
  		return 1;
  	else
 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
-index ecebdfa..3205f74 100644
+index ecebdfa..29b4cf9 100644
 --- a/drivers/scsi/lpfc/lpfc_init.c
 +++ b/drivers/scsi/lpfc/lpfc_init.c
 @@ -212,6 +212,18 @@ out_free_mbox:
@@ -690383,11 +718843,7 @@
  		}
 +	}
 +	phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
- 
--		lpfc_heart_beat(phba, pmboxq);
--		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
--		pmboxq->vport = phba->pport;
--		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
++
 +	/* If there is no heart beat outstanding, issue a heartbeat command */
 +	if (phba->cfg_enable_hba_heartbeat) {
 +		if (!phba->hb_outstanding) {
@@ -690398,13 +718854,17 @@
 +				return;
 +			}
  
--		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
--			mempool_free(pmboxq, phba->mbox_mem_pool);
+-		lpfc_heart_beat(phba, pmboxq);
+-		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+-		pmboxq->vport = phba->pport;
+-		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 +			lpfc_heart_beat(phba, pmboxq);
 +			pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
 +			pmboxq->vport = phba->pport;
 +			retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
-+
+ 
+-		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+-			mempool_free(pmboxq, phba->mbox_mem_pool);
 +			if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
 +				mempool_free(pmboxq, phba->mbox_mem_pool);
 +				mod_timer(&phba->hb_tmofunc,
@@ -690980,7 +719440,19 @@
  	pci_disable_device(pdev);
  }
  
-@@ -2239,12 +2435,22 @@ lpfc_init(void)
+@@ -2100,10 +2296,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
+ 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ 	struct lpfc_sli *psli = &phba->sli;
+-	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ 
+ 	dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+-	if (pci_enable_device_bars(pdev, bars)) {
++	if (pci_enable_device_mem(pdev)) {
+ 		printk(KERN_ERR "lpfc: Cannot re-enable "
+ 			"PCI device after reset.\n");
+ 		return PCI_ERS_RESULT_DISCONNECT;
+@@ -2239,12 +2434,22 @@ lpfc_init(void)
  	printk(LPFC_MODULE_DESC "\n");
  	printk(LPFC_COPYRIGHT "\n");
  
@@ -691006,7 +719478,7 @@
  	error = pci_register_driver(&lpfc_driver);
  	if (error) {
  		fc_release_transport(lpfc_transport_template);
-@@ -2259,7 +2465,8 @@ lpfc_exit(void)
+@@ -2259,7 +2464,8 @@ lpfc_exit(void)
  {
  	pci_unregister_driver(&lpfc_driver);
  	fc_release_transport(lpfc_transport_template);
@@ -695460,7 +723932,7 @@
  	uint8_t signature[4];
  	uint32_t version;
 diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
-index 04e8cbc..6f129da 100644
+index 04e8cbc..b72c7f1 100644
 --- a/drivers/scsi/qla2xxx/qla_def.h
 +++ b/drivers/scsi/qla2xxx/qla_def.h
 @@ -623,9 +623,6 @@ typedef struct {
@@ -695525,9 +723997,11 @@
  	} flags;
  
  	atomic_t	loop_state;
-@@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host {
+@@ -2272,9 +2268,9 @@ typedef struct scsi_qla_host {
+ 	spinlock_t		hardware_lock ____cacheline_aligned;
  
  	int		bars;
++	int		mem_only;
  	device_reg_t __iomem *iobase;		/* Base I/O address */
 -	unsigned long	pio_address;
 -	unsigned long	pio_length;
@@ -695535,7 +724009,7 @@
  #define MIN_IOBASE_LEN		0x100
  
  	/* ISP ring lock, rings, and indexes */
-@@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host {
+@@ -2416,9 +2412,9 @@ typedef struct scsi_qla_host {
  #define MBX_INTR_WAIT	2
  #define MBX_UPDATE_FLASH_ACTIVE	3
  
@@ -695547,7 +724021,7 @@
  
  	uint32_t	mbx_flags;
  #define  MBX_IN_PROGRESS	BIT_0
-@@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host {
+@@ -2455,6 +2451,15 @@ typedef struct scsi_qla_host {
  	dma_addr_t	eft_dma;
  	void		*eft;
  
@@ -695563,7 +724037,7 @@
  	uint8_t		host_str[16];
  	uint32_t	pci_attr;
  	uint16_t	chip_revision;
-@@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host {
+@@ -2507,7 +2512,7 @@ typedef struct scsi_qla_host {
  
  	struct list_head	vp_list;	/* list of VP */
  	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
@@ -697161,7 +725635,7 @@
  	up(&ha->vport_sem);
  
 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
-index 8ecc047..3954ed2 100644
+index 8ecc047..8f69caf 100644
 --- a/drivers/scsi/qla2xxx/qla_os.c
 +++ b/drivers/scsi/qla2xxx/qla_os.c
 @@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *);
@@ -697298,7 +725772,43 @@
  	if (!ha->iobase) {
  		qla_printk(KERN_ERR, ha,
  		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
-@@ -1701,9 +1682,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+@@ -1583,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	char pci_info[30];
+ 	char fw_str[30];
+ 	struct scsi_host_template *sht;
+-	int bars;
++	int bars, mem_only = 0;
+ 
+ 	bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
+ 	sht = &qla2x00_driver_template;
+@@ -1594,10 +1575,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
+ 		bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ 		sht = &qla24xx_driver_template;
++		mem_only = 1;
+ 	}
+ 
+-	if (pci_enable_device_bars(pdev, bars))
+-		goto probe_out;
++	if (mem_only) {
++		if (pci_enable_device_mem(pdev))
++			goto probe_out;
++	} else {
++		if (pci_enable_device(pdev))
++			goto probe_out;
++	}
+ 
+ 	if (pci_find_aer_capability(pdev))
+ 		if (pci_enable_pcie_error_reporting(pdev))
+@@ -1620,6 +1607,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+ 	ha->parent = NULL;
+ 	ha->bars = bars;
++	ha->mem_only = mem_only;
+ 
+ 	/* Set ISP-type information. */
+ 	qla2x00_set_isp_flags(ha);
+@@ -1701,9 +1689,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
  	/* load the F/W, read paramaters, and init the H/W */
  	ha->instance = num_hosts;
  
@@ -697311,7 +725821,7 @@
  
  	INIT_LIST_HEAD(&ha->list);
  	INIT_LIST_HEAD(&ha->fcports);
-@@ -1807,6 +1789,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+@@ -1807,6 +1796,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
  
  	qla2x00_init_host_attr(ha);
  
@@ -697320,7 +725830,7 @@
  	qla_printk(KERN_INFO, ha, "\n"
  	    " QLogic Fibre Channel HBA Driver: %s\n"
  	    "  QLogic %s - %s\n"
-@@ -1838,6 +1822,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
+@@ -1838,6 +1829,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
  
  	ha = pci_get_drvdata(pdev);
  
@@ -697329,7 +725839,7 @@
  	qla2x00_free_sysfs_attr(ha);
  
  	fc_remove_host(ha->host);
-@@ -1871,8 +1857,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
+@@ -1871,8 +1864,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
  		kthread_stop(t);
  	}
  
@@ -697342,7 +725852,7 @@
  
  	ha->flags.online = 0;
  
-@@ -2016,7 +2005,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
+@@ -2016,7 +2012,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
  *      0  = success.
  *      1  = failure.
  */
@@ -697351,7 +725861,7 @@
  qla2x00_mem_alloc(scsi_qla_host_t *ha)
  {
  	char	name[16];
-@@ -2213,7 +2202,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
+@@ -2213,7 +2209,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
  * Input:
  *      ha = adapter block pointer.
  */
@@ -697360,7 +725870,7 @@
  qla2x00_mem_free(scsi_qla_host_t *ha)
  {
  	struct list_head	*fcpl, *fcptemp;
-@@ -2228,6 +2217,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
+@@ -2228,6 +2224,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
  	/* free sp pool */
  	qla2x00_free_sp_pool(ha);
  
@@ -697371,7 +725881,7 @@
  	if (ha->fw_dump) {
  		if (ha->eft)
  			dma_free_coherent(&ha->pdev->dev,
-@@ -2748,23 +2741,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
+@@ -2748,23 +2748,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
  	qla2x00_restart_timer(ha, WATCH_INTERVAL);
  }
  
@@ -697395,6 +725905,22 @@
  /* Firmware interface routines. */
  
  #define FW_BLOBS	6
+@@ -2899,8 +2882,14 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+ {
+ 	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+ 	scsi_qla_host_t *ha = pci_get_drvdata(pdev);
++	int rc;
++
++	if (ha->mem_only)
++		rc = pci_enable_device_mem(pdev);
++	else
++		rc = pci_enable_device(pdev);
+ 
+-	if (pci_enable_device_bars(pdev, ha->bars)) {
++	if (rc) {
+ 		qla_printk(KERN_WARNING, ha,
+ 		    "Can't re-enable PCI device after reset.\n");
+ 
 diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
 index ad2fa01..b68fb73 100644
 --- a/drivers/scsi/qla2xxx/qla_sup.c
@@ -705116,11 +733642,55 @@
  	/*
  	 * Which character status flags should we ignore?
  	 */
+diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
+index aad4012..0d99120 100644
+--- a/drivers/serial/68328serial.c
++++ b/drivers/serial/68328serial.c
+@@ -1410,7 +1410,7 @@ rs68328_init(void)
+ 
+ 	    if (request_irq(uart_irqs[i],
+ 			    rs_interrupt,
+-			    IRQ_FLG_STD,
++			    IRQF_DISABLED,
+ 			    "M68328_UART", NULL))
+                 panic("Unable to attach 68328 serial interrupt\n");
+ 	}
 diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
-index d7e1996..d962b74 100644
+index d7e1996..8a053ea 100644
 --- a/drivers/serial/Kconfig
 +++ b/drivers/serial/Kconfig
-@@ -1284,4 +1284,14 @@ config SERIAL_OF_PLATFORM
+@@ -960,6 +960,30 @@ config SERIAL_COLDFIRE
+ 	  This driver supports the built-in serial ports of the Motorola ColdFire
+ 	  family of CPUs.
+ 
++config SERIAL_MCF
++	bool "Coldfire serial support (new style driver)"
++	depends on COLDFIRE
++	select SERIAL_CORE
++	help
++	  This new serial driver supports the Freescale Coldfire serial ports
++	  using the new serial driver subsystem.
++
++config SERIAL_MCF_BAUDRATE
++	int "Default baudrate for Coldfire serial ports"
++	depends on SERIAL_MCF
++	default 19200
++	help
++	  This setting lets you define what the default baudrate is for the
++	  ColdFire serial ports. The usual default varies from board to board,
++	  and this setting is a way of catering for that.
++
++config SERIAL_MCF_CONSOLE
++	bool "Coldfire serial console support"
++	depends on SERIAL_MCF
++	select SERIAL_CORE_CONSOLE
++	help
++	  Enable a ColdFire internal serial port to be the system console.
++
+ config SERIAL_68360_SMC
+ 	bool "68360 SMC uart support"
+ 	depends on M68360
+@@ -1284,4 +1308,14 @@ config SERIAL_OF_PLATFORM
  	  Currently, only 8250 compatible ports are supported, but
  	  others can easily be added.
  
@@ -705136,10 +733706,18 @@
 +
  endmenu
 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
-index af6377d..7eb4553 100644
+index af6377d..2dd41b4 100644
 --- a/drivers/serial/Makefile
 +++ b/drivers/serial/Makefile
-@@ -64,3 +64,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+@@ -39,6 +39,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
+ obj-$(CONFIG_SERIAL_68328) += 68328serial.o
+ obj-$(CONFIG_SERIAL_68360) += 68360serial.o
+ obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
++obj-$(CONFIG_SERIAL_MCF) += mcf.o
+ obj-$(CONFIG_V850E_UART) += v850e_uart.o
+ obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+ obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
+@@ -64,3 +65,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
  obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
  obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
  obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
@@ -705334,6 +733912,100 @@
  };
  
  /* prototype */
+diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
+index a7d4360..051fcc2 100644
+--- a/drivers/serial/mcf.c
++++ b/drivers/serial/mcf.c
+@@ -69,7 +69,7 @@ static unsigned int mcf_tx_empty(struct uart_port *port)
+ 
+ static unsigned int mcf_get_mctrl(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 	unsigned int sigs;
+ 
+@@ -87,7 +87,7 @@ static unsigned int mcf_get_mctrl(struct uart_port *port)
+ 
+ static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -104,7 +104,7 @@ static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+ 
+ static void mcf_start_tx(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -117,7 +117,7 @@ static void mcf_start_tx(struct uart_port *port)
+ 
+ static void mcf_stop_tx(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -130,7 +130,7 @@ static void mcf_stop_tx(struct uart_port *port)
+ 
+ static void mcf_stop_rx(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -163,7 +163,7 @@ static void mcf_enable_ms(struct uart_port *port)
+ 
+ static int mcf_startup(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -189,7 +189,7 @@ static int mcf_startup(struct uart_port *port)
+ 
+ static void mcf_shutdown(struct uart_port *port)
+ {
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned long flags;
+ 
+ 	spin_lock_irqsave(&port->lock, flags);
+@@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
+ 
+ static void mcf_rx_chars(struct mcf_uart *pp)
+ {
+-	struct uart_port *port = (struct uart_port *) pp;
++	struct uart_port *port = &pp->port;
+ 	unsigned char status, ch, flag;
+ 
+ 	while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
+@@ -319,7 +319,7 @@ static void mcf_rx_chars(struct mcf_uart *pp)
+ 
+ static void mcf_tx_chars(struct mcf_uart *pp)
+ {
+-	struct uart_port *port = (struct uart_port *) pp;
++	struct uart_port *port = &pp->port;
+ 	struct circ_buf *xmit = &port->info->xmit;
+ 
+ 	if (port->x_char) {
+@@ -352,7 +352,7 @@ static void mcf_tx_chars(struct mcf_uart *pp)
+ static irqreturn_t mcf_interrupt(int irq, void *data)
+ {
+ 	struct uart_port *port = data;
+-	struct mcf_uart *pp = (struct mcf_uart *) port;
++	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
+ 	unsigned int isr;
+ 
+ 	isr = readb(port->membase + MCFUART_UISR) & pp->imr;
 diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
 index ec36ad7..3c4d29e 100644
 --- a/drivers/serial/mpc52xx_uart.c
@@ -707845,1321 +736517,18161 @@
 +	struct ssp_device *ssp = drv_data->ssp;
  	unsigned int clk_div;
  
- 	if (!spi->bits_per_word)
-@@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi)
- 		}
- 	}
+ 	if (!spi->bits_per_word)
+@@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi)
+ 		}
+ 	}
+ 
+-	if (drv_data->ioaddr == SSP1_VIRT)
+-		clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
+-	else if (drv_data->ioaddr == SSP2_VIRT)
+-		clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
+-	else if (drv_data->ioaddr == SSP3_VIRT)
+-		clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
+-	else
+-	{
+-		dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
+-			drv_data->ioaddr);
+-		return -ENODEV;
+-	}
++	clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
+ 	chip->speed_hz = spi->max_speed_hz;
+ 
+ 	chip->cr0 = clk_div
+@@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi)
+ 
+ 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
+ 	if (drv_data->ssp_type != PXA25x_SSP)
+-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ 				spi->bits_per_word,
+-				(CLOCK_SPEED_HZ)
++				clk_get_rate(ssp->clk)
+ 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ 				spi->mode & 0x3);
+ 	else
+-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
++		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ 				spi->bits_per_word,
+-				(CLOCK_SPEED_HZ/2)
++				clk_get_rate(ssp->clk)
+ 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
+ 				spi->mode & 0x3);
+ 
+@@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	struct pxa2xx_spi_master *platform_info;
+ 	struct spi_master *master;
+ 	struct driver_data *drv_data = 0;
+-	struct resource *memory_resource;
+-	int irq;
++	struct ssp_device *ssp;
+ 	int status = 0;
+ 
+ 	platform_info = dev->platform_data;
+ 
+-	if (platform_info->ssp_type == SSP_UNDEFINED) {
+-		dev_err(&pdev->dev, "undefined SSP\n");
++	ssp = ssp_request(pdev->id, pdev->name);
++	if (ssp == NULL) {
++		dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
+ 		return -ENODEV;
+ 	}
+ 
+@@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+ 	if (!master) {
+ 		dev_err(&pdev->dev, "can not alloc spi_master\n");
++		ssp_free(ssp);
+ 		return -ENOMEM;
+ 	}
+ 	drv_data = spi_master_get_devdata(master);
+ 	drv_data->master = master;
+ 	drv_data->master_info = platform_info;
+ 	drv_data->pdev = pdev;
++	drv_data->ssp = ssp;
+ 
+ 	master->bus_num = pdev->id;
+ 	master->num_chipselect = platform_info->num_chipselect;
+@@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 	master->setup = setup;
+ 	master->transfer = transfer;
+ 
+-	drv_data->ssp_type = platform_info->ssp_type;
++	drv_data->ssp_type = ssp->type;
+ 	drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
+ 						sizeof(struct driver_data)), 8);
+ 
+-	/* Setup register addresses */
+-	memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!memory_resource) {
+-		dev_err(&pdev->dev, "memory resources not defined\n");
+-		status = -ENODEV;
+-		goto out_error_master_alloc;
+-	}
+-
+-	drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
+-	drv_data->ssdr_physical = memory_resource->start + 0x00000010;
+-	if (platform_info->ssp_type == PXA25x_SSP) {
++	drv_data->ioaddr = ssp->mmio_base;
++	drv_data->ssdr_physical = ssp->phys_base + SSDR;
++	if (ssp->type == PXA25x_SSP) {
+ 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
+ 		drv_data->dma_cr1 = 0;
+ 		drv_data->clear_sr = SSSR_ROR;
+@@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
+ 	}
+ 
+-	/* Attach to IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(&pdev->dev, "irq resource not defined\n");
+-		status = -ENODEV;
+-		goto out_error_master_alloc;
+-	}
+-
+-	status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
++	status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
+ 	if (status < 0) {
+ 		dev_err(&pdev->dev, "can not get IRQ\n");
+ 		goto out_error_master_alloc;
+@@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
+ 			goto out_error_dma_alloc;
+ 		}
+ 
+-		if (drv_data->ioaddr == SSP1_VIRT) {
+-				DRCMRRXSSDR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSSDR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else if (drv_data->ioaddr == SSP2_VIRT) {
+-				DRCMRRXSS2DR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSS2DR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else if (drv_data->ioaddr == SSP3_VIRT) {
+-				DRCMRRXSS3DR = DRCMR_MAPVLD
+-						| drv_data->rx_channel;
+-				DRCMRTXSS3DR = DRCMR_MAPVLD
+-						| drv_data->tx_channel;
+-		} else {
+-			dev_err(dev, "bad SSP type\n");
+-			goto out_error_dma_alloc;
+-		}
++		DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
++		DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
+ 	}
+ 
+ 	/* Enable SOC clock */
+-	pxa_set_cken(platform_info->clock_enable, 1);
++	clk_enable(ssp->clk);
+ 
+ 	/* Load default SSP configuration */
+ 	write_SSCR0(0, drv_data->ioaddr);
+@@ -1479,7 +1450,7 @@ out_error_queue_alloc:
+ 	destroy_queue(drv_data);
+ 
+ out_error_clock_enabled:
+-	pxa_set_cken(platform_info->clock_enable, 0);
++	clk_disable(ssp->clk);
+ 
+ out_error_dma_alloc:
+ 	if (drv_data->tx_channel != -1)
+@@ -1488,17 +1459,18 @@ out_error_dma_alloc:
+ 		pxa_free_dma(drv_data->rx_channel);
+ 
+ out_error_irq_alloc:
+-	free_irq(irq, drv_data);
++	free_irq(ssp->irq, drv_data);
+ 
+ out_error_master_alloc:
+ 	spi_master_put(master);
++	ssp_free(ssp);
+ 	return status;
+ }
+ 
+ static int pxa2xx_spi_remove(struct platform_device *pdev)
+ {
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-	int irq;
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
+ 
+ 	if (!drv_data)
+@@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
+ 
+ 	/* Disable the SSP at the peripheral and SOC level */
+ 	write_SSCR0(0, drv_data->ioaddr);
+-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
++	clk_disable(ssp->clk);
+ 
+ 	/* Release DMA */
+ 	if (drv_data->master_info->enable_dma) {
+-		if (drv_data->ioaddr == SSP1_VIRT) {
+-			DRCMRRXSSDR = 0;
+-			DRCMRTXSSDR = 0;
+-		} else if (drv_data->ioaddr == SSP2_VIRT) {
+-			DRCMRRXSS2DR = 0;
+-			DRCMRTXSS2DR = 0;
+-		} else if (drv_data->ioaddr == SSP3_VIRT) {
+-			DRCMRRXSS3DR = 0;
+-			DRCMRTXSS3DR = 0;
+-		}
++		DRCMR(ssp->drcmr_rx) = 0;
++		DRCMR(ssp->drcmr_tx) = 0;
+ 		pxa_free_dma(drv_data->tx_channel);
+ 		pxa_free_dma(drv_data->rx_channel);
+ 	}
+ 
+ 	/* Release IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq >= 0)
+-		free_irq(irq, drv_data);
++	free_irq(ssp->irq, drv_data);
++
++	/* Release SSP */
++	ssp_free(ssp);
+ 
+ 	/* Disconnect from the SPI framework */
+ 	spi_unregister_master(drv_data->master);
+@@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message)
+ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
+ 
+ 	/* Check all childern for current power state */
+@@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ 	if (status != 0)
+ 		return status;
+ 	write_SSCR0(0, drv_data->ioaddr);
+-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
++	clk_disable(ssp->clk);
+ 
+ 	return 0;
+ }
+@@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+ static int pxa2xx_spi_resume(struct platform_device *pdev)
+ {
+ 	struct driver_data *drv_data = platform_get_drvdata(pdev);
++	struct ssp_device *ssp = drv_data->ssp;
+ 	int status = 0;
+ 
+ 	/* Enable the SSP clock */
+-	pxa_set_cken(drv_data->master_info->clock_enable, 1);
++	clk_disable(ssp->clk);
+ 
+ 	/* Start the queue running */
+ 	status = start_queue(drv_data);
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 93e9de4..682a6a4 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
+ }
+ EXPORT_SYMBOL_GPL(spi_unregister_master);
+ 
++static int __spi_master_match(struct device *dev, void *data)
++{
++	struct spi_master *m;
++	u16 *bus_num = data;
++
++	m = container_of(dev, struct spi_master, dev);
++	return m->bus_num == *bus_num;
++}
++
+ /**
+  * spi_busnum_to_master - look up master associated with bus_num
+  * @bus_num: the master's bus number
+@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
+ {
+ 	struct device		*dev;
+ 	struct spi_master	*master = NULL;
+-	struct spi_master	*m;
+-
+-	down(&spi_master_class.sem);
+-	list_for_each_entry(dev, &spi_master_class.children, node) {
+-		m = container_of(dev, struct spi_master, dev);
+-		if (m->bus_num == bus_num) {
+-			master = spi_master_get(m);
+-			break;
+-		}
+-	}
+-	up(&spi_master_class.sem);
++
++	dev = class_find_device(&spi_master_class, &bus_num,
++				__spi_master_match);
++	if (dev)
++		master = container_of(dev, struct spi_master, dev);
++	/* reference got in class_find_device */
+ 	return master;
+ }
+ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
+index 4580b9c..04f7cd9 100644
+--- a/drivers/spi/spi_mpc83xx.c
++++ b/drivers/spi/spi_mpc83xx.c
+@@ -436,11 +436,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
+ 	mpc83xx_spi->qe_mode = pdata->qe_mode;
+ 	mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
+ 	mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+-
+-	if (mpc83xx_spi->qe_mode)
+-		mpc83xx_spi->spibrg = pdata->sysclk / 2;
+-	else
+-		mpc83xx_spi->spibrg = pdata->sysclk;
++	mpc83xx_spi->spibrg = pdata->sysclk;
+ 
+ 	mpc83xx_spi->rx_shift = 0;
+ 	mpc83xx_spi->tx_shift = 0;
+diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
+index f145d8a..1a31f7a 100644
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -27,6 +27,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
+ 	{ 0, },
+ };
+ MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
+diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
+index 85a2054..9028ed5 100644
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -872,14 +872,22 @@ EXPORT_SYMBOL(ssb_clockspeed);
+ 
+ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
+ {
++	u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
++
+ 	/* The REJECT bit changed position in TMSLOW between
+ 	 * Backplane revisions. */
+-	switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
++	switch (rev) {
+ 	case SSB_IDLOW_SSBREV_22:
+ 		return SSB_TMSLOW_REJECT_22;
+ 	case SSB_IDLOW_SSBREV_23:
+ 		return SSB_TMSLOW_REJECT_23;
++	case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
++	case SSB_IDLOW_SSBREV_25:     /* same here */
++	case SSB_IDLOW_SSBREV_26:     /* same here */
++	case SSB_IDLOW_SSBREV_27:     /* same here */
++		return SSB_TMSLOW_REJECT_23;	/* this is a guess */
+ 	default:
++		printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+ 		WARN_ON(1);
+ 	}
+ 	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
+index 0ab095c..b434df7 100644
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -212,29 +212,29 @@ static inline u8 ssb_crc8(u8 crc, u8 data)
+ 	return t[crc ^ data];
+ }
+ 
+-static u8 ssb_sprom_crc(const u16 *sprom)
++static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
+ {
+ 	int word;
+ 	u8 crc = 0xFF;
+ 
+-	for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
++	for (word = 0; word < size - 1; word++) {
+ 		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
+ 		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+ 	}
+-	crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
++	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
+ 	crc ^= 0xFF;
+ 
+ 	return crc;
+ }
+ 
+-static int sprom_check_crc(const u16 *sprom)
++static int sprom_check_crc(const u16 *sprom, u16 size)
+ {
+ 	u8 crc;
+ 	u8 expected_crc;
+ 	u16 tmp;
+ 
+-	crc = ssb_sprom_crc(sprom);
+-	tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
++	crc = ssb_sprom_crc(sprom, size);
++	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
+ 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+ 	if (crc != expected_crc)
+ 		return -EPROTO;
+@@ -246,8 +246,8 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+ {
+ 	int i;
+ 
+-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
+-		sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
++	for (i = 0; i < bus->sprom_size; i++)
++		sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
+ }
+ 
+ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+@@ -255,6 +255,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+ 	struct pci_dev *pdev = bus->host_pci;
+ 	int i, err;
+ 	u32 spromctl;
++	u16 size = bus->sprom_size;
+ 
+ 	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+ 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+@@ -266,12 +267,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+ 		goto err_ctlreg;
+ 	ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ 	msleep(500);
+-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+-		if (i == SSB_SPROMSIZE_WORDS / 4)
++	for (i = 0; i < size; i++) {
++		if (i == size / 4)
+ 			ssb_printk("25%%");
+-		else if (i == SSB_SPROMSIZE_WORDS / 2)
++		else if (i == size / 2)
+ 			ssb_printk("50%%");
+-		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
++		else if (i == (size * 3) / 4)
+ 			ssb_printk("75%%");
+ 		else if (i % 2)
+ 			ssb_printk(".");
+@@ -296,24 +297,53 @@ err_ctlreg:
+ 	return err;
+ }
+ 
+-static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
++static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
++			       u16 mask, u16 shift)
++{
++	u16 v;
++	u8 gain;
++
++	v = in[SPOFF(SSB_SPROM1_AGAIN)];
++	gain = (v & mask) >> shift;
++	if (gain == 0xFF)
++		gain = 2; /* If unset use 2dBm */
++	if (sprom_revision == 1) {
++		/* Convert to Q5.2 */
++		gain <<= 2;
++	} else {
++		/* Q5.2 Fractional part is stored in 0xC0 */
++		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
++	}
++
++	return (s8)gain;
++}
++
++static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+ 	u16 v;
++	s8 gain;
++	u16 loc[3];
+ 
+-	SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
+-	SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
+-	SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
++	if (out->revision == 3) {			/* rev 3 moved MAC */
++		loc[0] = SSB_SPROM3_IL0MAC;
++		loc[1] = SSB_SPROM3_ET0MAC;
++		loc[2] = SSB_SPROM3_ET1MAC;
++	} else {
++		loc[0] = SSB_SPROM1_IL0MAC;
++		loc[1] = SSB_SPROM1_ET0MAC;
++		loc[2] = SSB_SPROM1_ET1MAC;
++	}
+ 	for (i = 0; i < 3; i++) {
+-		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
++		v = in[SPOFF(loc[0]) + i];
+ 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+ 	}
+ 	for (i = 0; i < 3; i++) {
+-		v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
++		v = in[SPOFF(loc[1]) + i];
+ 		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+ 	}
+ 	for (i = 0; i < 3; i++) {
+-		v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
++		v = in[SPOFF(loc[2]) + i];
+ 		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+ 	}
+ 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+@@ -324,9 +354,9 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+ 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+ 	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+ 	     SSB_SPROM1_BINF_CCODE_SHIFT);
+-	SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
++	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+ 	     SSB_SPROM1_BINF_ANTA_SHIFT);
+-	SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
++	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+ 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
+ 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
+ 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
+@@ -347,100 +377,108 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+ 	     SSB_SPROM1_ITSSI_A_SHIFT);
+ 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
+ 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
+-	SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
+-	SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
+-	     SSB_SPROM1_AGAIN_BG_SHIFT);
+-	for (i = 0; i < 4; i++) {
+-		v = in[SPOFF(SSB_SPROM1_OEM) + i];
+-		*(((__le16 *)out->oem) + i) = cpu_to_le16(v);
+-	}
++	if (out->revision >= 2)
++		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
++
++	/* Extract the antenna gain values. */
++	gain = r123_extract_antgain(out->revision, in,
++				    SSB_SPROM1_AGAIN_BG,
++				    SSB_SPROM1_AGAIN_BG_SHIFT);
++	out->antenna_gain.ghz24.a0 = gain;
++	out->antenna_gain.ghz24.a1 = gain;
++	out->antenna_gain.ghz24.a2 = gain;
++	out->antenna_gain.ghz24.a3 = gain;
++	gain = r123_extract_antgain(out->revision, in,
++				    SSB_SPROM1_AGAIN_A,
++				    SSB_SPROM1_AGAIN_A_SHIFT);
++	out->antenna_gain.ghz5.a0 = gain;
++	out->antenna_gain.ghz5.a1 = gain;
++	out->antenna_gain.ghz5.a2 = gain;
++	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
+-static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
++static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+ 	u16 v;
+ 
+-	SPEX(boardflags_hi, SSB_SPROM2_BFLHI,  0xFFFF, 0);
+-	SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+-	SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+-	     SSB_SPROM2_MAXP_A_LO_SHIFT);
+-	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+-	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+-	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+-	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+-	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+-	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+-	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+-	for (i = 0; i < 4; i++) {
+-		v = in[SPOFF(SSB_SPROM2_CCODE) + i];
+-		*(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
++	/* extract the equivalent of the r1 variables */
++	for (i = 0; i < 3; i++) {
++		v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
++		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+ 	}
++	for (i = 0; i < 3; i++) {
++		v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
++		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
++	}
++	for (i = 0; i < 3; i++) {
++		v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
++		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
++	}
++	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
++	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
++	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
++	SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
++	SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
++	SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
++	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
++	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
++	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
++	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
++	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
++	     SSB_SPROM4_ITSSI_BG_SHIFT);
++	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
++	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
++	     SSB_SPROM4_ITSSI_A_SHIFT);
++	SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
++	SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
++	     SSB_SPROM4_GPIOA_P1_SHIFT);
++	SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
++	SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
++	     SSB_SPROM4_GPIOB_P3_SHIFT);
++
++	/* Extract the antenna gain values. */
++	SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
++	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
++	SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
++	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
++	SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
++	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
++	SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
++	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
++	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
++	       sizeof(out->antenna_gain.ghz5));
++
++	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+-static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
+-{
+-	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
+-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
+-	out->ofdmapo <<= 16;
+-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
+-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
+-
+-	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
+-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
+-	out->ofdmalpo <<= 16;
+-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
+-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
+-
+-	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
+-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
+-	out->ofdmahpo <<= 16;
+-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
+-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
+-
+-	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
+-	     SSB_SPROM3_GPIOLDC_ON_SHIFT);
+-	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
+-	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);
+-	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
+-	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
+-	     SSB_SPROM3_CCKPO_2M_SHIFT);
+-	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
+-	     SSB_SPROM3_CCKPO_55M_SHIFT);
+-	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
+-	     SSB_SPROM3_CCKPO_11M_SHIFT);
+-
+-	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
+-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
+-	out->ofdmgpo <<= 16;
+-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
+-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
+-}
+-
+-static int sprom_extract(struct ssb_bus *bus,
+-			 struct ssb_sprom *out, const u16 *in)
++static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
++			 const u16 *in, u16 size)
+ {
+ 	memset(out, 0, sizeof(*out));
+ 
+-	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
+-	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
+-	     SSB_SPROM_REVISION_CRC_SHIFT);
+-
++	out->revision = in[size - 1] & 0x00FF;
++	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+-		sprom_extract_r1(&out->r1, in);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
++	} else if (bus->chip_id == 0x4321) {
++		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
++		out->revision = 4;
++		sprom_extract_r4(out, in);
+ 	} else {
+ 		if (out->revision == 0)
+ 			goto unsupported;
+-		if (out->revision >= 1 && out->revision <= 3)
+-			sprom_extract_r1(&out->r1, in);
+-		if (out->revision >= 2 && out->revision <= 3)
+-			sprom_extract_r2(&out->r2, in);
+-		if (out->revision == 3)
+-			sprom_extract_r3(&out->r3, in);
+-		if (out->revision >= 4)
++		if (out->revision >= 1 && out->revision <= 3) {
++			sprom_extract_r123(out, in);
++		}
++		if (out->revision == 4)
++			sprom_extract_r4(out, in);
++		if (out->revision >= 5)
+ 			goto unsupported;
+ 	}
+ 
+@@ -448,7 +486,7 @@ static int sprom_extract(struct ssb_bus *bus,
+ unsupported:
+ 	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
+ 		   "detected. Will extract v1\n", out->revision);
+-	sprom_extract_r1(&out->r1, in);
++	sprom_extract_r123(out, in);
+ 	return 0;
+ }
+ 
+@@ -458,16 +496,29 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
+ 	int err = -ENOMEM;
+ 	u16 *buf;
+ 
+-	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
++	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+ 		goto out;
++	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+-	err = sprom_check_crc(buf);
++	err = sprom_check_crc(buf, bus->sprom_size);
+ 	if (err) {
+-		ssb_printk(KERN_WARNING PFX
+-			   "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
++		/* check for rev 4 sprom - has special signature */
++		if (buf[32] == 0x5372) {
++			kfree(buf);
++			buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
++				      GFP_KERNEL);
++			if (!buf)
++				goto out;
++			bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
++			sprom_do_read(bus, buf);
++			err = sprom_check_crc(buf, bus->sprom_size);
++		}
++		if (err)
++			ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
++				   " SPROM CRC (corrupt SPROM)\n");
+ 	}
+-	err = sprom_extract(bus, sprom, buf);
++	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
+ 
+ 	kfree(buf);
+ out:
+@@ -581,29 +632,28 @@ const struct ssb_bus_ops ssb_pci_ops = {
+ 	.write32	= ssb_pci_write32,
+ };
+ 
+-static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
++static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
+ {
+ 	int i, pos = 0;
+ 
+-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
++	for (i = 0; i < size; i++)
+ 		pos += snprintf(buf + pos, buf_len - pos - 1,
+ 				"%04X", swab16(sprom[i]) & 0xFFFF);
+-	}
+ 	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+ 
+ 	return pos + 1;
+ }
+ 
+-static int hex2sprom(u16 *sprom, const char *dump, size_t len)
++static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
+ {
+ 	char tmp[5] = { 0 };
+ 	int cnt = 0;
+ 	unsigned long parsed;
+ 
+-	if (len < SSB_SPROMSIZE_BYTES * 2)
++	if (len < size * 2)
+ 		return -EINVAL;
+ 
+-	while (cnt < SSB_SPROMSIZE_WORDS) {
++	while (cnt < size) {
+ 		memcpy(tmp, dump, 4);
+ 		dump += 4;
+ 		parsed = simple_strtoul(tmp, NULL, 16);
+@@ -627,7 +677,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
+ 	if (!bus)
+ 		goto out;
+ 	err = -ENOMEM;
+-	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
++	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
+ 	if (!sprom)
+ 		goto out;
+ 
+@@ -640,7 +690,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
+ 	sprom_do_read(bus, sprom);
+ 	mutex_unlock(&bus->pci_sprom_mutex);
+ 
+-	count = sprom2hex(sprom, buf, PAGE_SIZE);
++	count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
+ 	err = 0;
+ 
+ out_kfree:
+@@ -662,15 +712,15 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
+ 	if (!bus)
+ 		goto out;
+ 	err = -ENOMEM;
+-	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
++	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
+ 	if (!sprom)
+ 		goto out;
+-	err = hex2sprom(sprom, buf, count);
++	err = hex2sprom(sprom, buf, count, bus->sprom_size);
+ 	if (err) {
+ 		err = -EINVAL;
+ 		goto out_kfree;
+ 	}
+-	err = sprom_check_crc(sprom);
++	err = sprom_check_crc(sprom, bus->sprom_size);
+ 	if (err) {
+ 		err = -EINVAL;
+ 		goto out_kfree;
+diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
+index bb44a76..46816cd 100644
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ 			   struct ssb_device *dev)
+ {
+ 	int err;
+-	unsigned long flags;
+ 
+ #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
+ 	ssb_printk(KERN_INFO PFX
+@@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ 		   dev->core_index);
+ #endif
+ 
+-	spin_lock_irqsave(&bus->bar_lock, flags);
+ 	err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
+ 	if (!err)
+ 		bus->mapped_device = dev;
+-	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ 
+ 	return err;
+ }
+@@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
+ {
+ 	int attempts = 0;
+-	unsigned long flags;
+ 	conf_reg_t reg;
+-	int res, err = 0;
++	int res;
+ 
+ 	SSB_WARN_ON((seg != 0) && (seg != 1));
+ 	reg.Offset = 0x34;
+ 	reg.Function = 0;
+-	spin_lock_irqsave(&bus->bar_lock, flags);
+ 	while (1) {
+ 		reg.Action = CS_WRITE;
+ 		reg.Value = seg;
+@@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
+ 		udelay(10);
+ 	}
+ 	bus->mapped_pcmcia_seg = seg;
+-out_unlock:
+-	spin_unlock_irqrestore(&bus->bar_lock, flags);
+-	return err;
++
++	return 0;
+ error:
+ 	ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+-	err = -ENODEV;
+-	goto out_unlock;
++	return -ENODEV;
+ }
+ 
+ static int select_core_and_segment(struct ssb_device *dev,
+@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev,
+ static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
+ {
+ 	struct ssb_bus *bus = dev->bus;
++	unsigned long flags;
++	int err;
++	u16 value = 0xFFFF;
+ 
+-	if (unlikely(select_core_and_segment(dev, &offset)))
+-		return 0xFFFF;
++	spin_lock_irqsave(&bus->bar_lock, flags);
++	err = select_core_and_segment(dev, &offset);
++	if (likely(!err))
++		value = readw(bus->mmio + offset);
++	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ 
+-	return readw(bus->mmio + offset);
++	return value;
+ }
+ 
+ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
+ {
+ 	struct ssb_bus *bus = dev->bus;
+-	u32 lo, hi;
++	unsigned long flags;
++	int err;
++	u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
+ 
+-	if (unlikely(select_core_and_segment(dev, &offset)))
+-		return 0xFFFFFFFF;
+-	lo = readw(bus->mmio + offset);
+-	hi = readw(bus->mmio + offset + 2);
++	spin_lock_irqsave(&bus->bar_lock, flags);
++	err = select_core_and_segment(dev, &offset);
++	if (likely(!err)) {
++		lo = readw(bus->mmio + offset);
++		hi = readw(bus->mmio + offset + 2);
++	}
++	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ 
+ 	return (lo | (hi << 16));
+ }
+@@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
+ static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
+ {
+ 	struct ssb_bus *bus = dev->bus;
++	unsigned long flags;
++	int err;
+ 
+-	if (unlikely(select_core_and_segment(dev, &offset)))
+-		return;
+-	writew(value, bus->mmio + offset);
++	spin_lock_irqsave(&bus->bar_lock, flags);
++	err = select_core_and_segment(dev, &offset);
++	if (likely(!err))
++		writew(value, bus->mmio + offset);
++	mmiowb();
++	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ }
+ 
+ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
+ {
+ 	struct ssb_bus *bus = dev->bus;
++	unsigned long flags;
++	int err;
+ 
+-	if (unlikely(select_core_and_segment(dev, &offset)))
+-		return;
+-	writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
+-	writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
+-	writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
+-	writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
++	spin_lock_irqsave(&bus->bar_lock, flags);
++	err = select_core_and_segment(dev, &offset);
++	if (likely(!err)) {
++		writew((value & 0x0000FFFF), bus->mmio + offset);
++		writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
++	}
++	mmiowb();
++	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ }
+ 
+ /* Not "static", as it's used in main.c */
+@@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = {
+ 	.write32	= ssb_pcmcia_write32,
+ };
+ 
++#include <linux/etherdevice.h>
+ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ 			      struct ssb_init_invariants *iv)
+ {
+ 	//TODO
++	random_ether_addr(iv->sprom.il0mac);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
+index 865f32b..cc246fa 100644
+--- a/drivers/uio/uio.c
++++ b/drivers/uio/uio.c
+@@ -34,12 +34,12 @@ struct uio_device {
+ 	wait_queue_head_t	wait;
+ 	int			vma_count;
+ 	struct uio_info		*info;
+-	struct kset 		map_attr_kset;
++	struct kobject		*map_dir;
+ };
+ 
+ static int uio_major;
+ static DEFINE_IDR(uio_idr);
+-static struct file_operations uio_fops;
++static const struct file_operations uio_fops;
+ 
+ /* UIO class infrastructure */
+ static struct uio_class {
+@@ -51,47 +51,48 @@ static struct uio_class {
+  * attributes
+  */
+ 
+-static struct attribute attr_addr = {
+-	.name  = "addr",
+-	.mode  = S_IRUGO,
++struct uio_map {
++	struct kobject kobj;
++	struct uio_mem *mem;
+ };
++#define to_map(map) container_of(map, struct uio_map, kobj)
+ 
+-static struct attribute attr_size = {
+-	.name  = "size",
+-	.mode  = S_IRUGO,
+-};
+ 
+-static struct attribute* map_attrs[] = {
+-	&attr_addr, &attr_size, NULL
+-};
+-
+-static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
++static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+ 			     char *buf)
+ {
+-	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
++	struct uio_map *map = to_map(kobj);
++	struct uio_mem *mem = map->mem;
+ 
+-	if (strncmp(attr->name,"addr",4) == 0)
++	if (strncmp(attr->attr.name, "addr", 4) == 0)
+ 		return sprintf(buf, "0x%lx\n", mem->addr);
+ 
+-	if (strncmp(attr->name,"size",4) == 0)
++	if (strncmp(attr->attr.name, "size", 4) == 0)
+ 		return sprintf(buf, "0x%lx\n", mem->size);
+ 
+ 	return -ENODEV;
+ }
+ 
+-static void map_attr_release(struct kobject *kobj)
+-{
+-	/* TODO ??? */
+-}
++static struct kobj_attribute attr_attribute =
++	__ATTR(addr, S_IRUGO, map_attr_show, NULL);
++static struct kobj_attribute size_attribute =
++	__ATTR(size, S_IRUGO, map_attr_show, NULL);
+ 
+-static struct sysfs_ops map_attr_ops = {
+-	.show  = map_attr_show,
++static struct attribute *attrs[] = {
++	&attr_attribute.attr,
++	&size_attribute.attr,
++	NULL,	/* need to NULL terminate the list of attributes */
+ };
+ 
++static void map_release(struct kobject *kobj)
++{
++	struct uio_map *map = to_map(kobj);
++	kfree(map);
++}
++
+ static struct kobj_type map_attr_type = {
+-	.release	= map_attr_release,
+-	.sysfs_ops	= &map_attr_ops,
+-	.default_attrs	= map_attrs,
++	.release	= map_release,
++	.default_attrs	= attrs,
+ };
+ 
+ static ssize_t show_name(struct device *dev,
+@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
+ 	int mi;
+ 	int map_found = 0;
+ 	struct uio_mem *mem;
++	struct uio_map *map;
+ 
+ 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+ 	if (ret)
+@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
+ 			break;
+ 		if (!map_found) {
+ 			map_found = 1;
+-			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+-			idev->map_attr_kset.ktype = &map_attr_type;
+-			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+-			ret = kset_register(&idev->map_attr_kset);
+-			if (ret)
+-				goto err_remove_group;
++			idev->map_dir = kobject_create_and_add("maps",
++							&idev->dev->kobj);
++			if (!idev->map_dir)
++				goto err;
+ 		}
+-		kobject_init(&mem->kobj);
+-		kobject_set_name(&mem->kobj,"map%d",mi);
+-		mem->kobj.parent = &idev->map_attr_kset.kobj;
+-		mem->kobj.kset = &idev->map_attr_kset;
+-		ret = kobject_add(&mem->kobj);
++		map = kzalloc(sizeof(*map), GFP_KERNEL);
++		if (!map)
++			goto err;
++		kobject_init(&map->kobj, &map_attr_type);
++		map->mem = mem;
++		mem->map = map;
++		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
++		if (ret)
++			goto err;
++		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
+ 		if (ret)
+-			goto err_remove_maps;
++			goto err;
+ 	}
+ 
+ 	return 0;
+ 
+-err_remove_maps:
++err:
+ 	for (mi--; mi>=0; mi--) {
+ 		mem = &idev->info->mem[mi];
+-		kobject_unregister(&mem->kobj);
++		map = mem->map;
++		kobject_put(&map->kobj);
+ 	}
+-	kset_unregister(&idev->map_attr_kset); /* Needed ? */
+-err_remove_group:
++	kobject_put(idev->map_dir);
+ 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+ err_group:
+ 	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
+ 		mem = &idev->info->mem[mi];
+ 		if (mem->size == 0)
+ 			break;
+-		kobject_unregister(&mem->kobj);
++		kobject_put(&mem->map->kobj);
+ 	}
+-	kset_unregister(&idev->map_attr_kset);
++	kobject_put(idev->map_dir);
+ 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+ }
+ 
+@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+ 	}
+ }
+ 
+-static struct file_operations uio_fops = {
++static const struct file_operations uio_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= uio_open,
+ 	.release	= uio_release,
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 7580aa5..755823c 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -33,6 +33,7 @@ config USB_ARCH_HAS_OHCI
+ 	default y if ARCH_LH7A404
+ 	default y if ARCH_S3C2410
+ 	default y if PXA27x
++	default y if PXA3xx
+ 	default y if ARCH_EP93XX
+ 	default y if ARCH_AT91
+ 	default y if ARCH_PNX4008
+@@ -41,6 +42,10 @@ config USB_ARCH_HAS_OHCI
+ 	default y if PPC_MPC52xx
+ 	# MIPS:
+ 	default y if SOC_AU1X00
++	# SH:
++	default y if CPU_SUBTYPE_SH7720
++	default y if CPU_SUBTYPE_SH7721
++	default y if CPU_SUBTYPE_SH7763
+ 	# more:
+ 	default PCI
+ 
+@@ -49,6 +54,7 @@ config USB_ARCH_HAS_EHCI
+ 	boolean
+ 	default y if PPC_83xx
+ 	default y if SOC_AU1200
++	default y if ARCH_IXP4XX
+ 	default PCI
+ 
+ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
+index b450cba..86e6403 100644
+--- a/drivers/usb/atm/Kconfig
++++ b/drivers/usb/atm/Kconfig
+@@ -2,10 +2,7 @@
+ # USB/ATM DSL configuration
+ #
+ 
+-menu "USB DSL modem support"
+-	depends on USB
+-
+-config USB_ATM
++menuconfig USB_ATM
+ 	tristate "USB DSL modem support"
+ 	depends on USB && ATM
+ 	select CRC32
+@@ -18,6 +15,8 @@ config USB_ATM
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called usbatm.
+ 
++if USB_ATM
++
+ config USB_SPEEDTOUCH
+ 	tristate "Speedtouch USB support"
+ 	depends on USB_ATM
+@@ -70,4 +69,4 @@ config USB_XUSBATM
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called xusbatm.
+ 
+-endmenu
++endif # USB_ATM
+diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
+index 389c5b1..c5ec1a5 100644
+--- a/drivers/usb/atm/ueagle-atm.c
++++ b/drivers/usb/atm/ueagle-atm.c
+@@ -999,7 +999,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+ 		bi.dwAddress = swab32(blockidx->PageAddress);
+ 
+ 		uea_dbg(INS_TO_USBDEV(sc),
+-		       "sending block %u for DSP page %u size %u adress %x\n",
++		       "sending block %u for DSP page %u size %u address %x\n",
+ 		       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+ 
+ 		/* send block info through the IDMA pipe */
+@@ -1990,7 +1990,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
+ 	return;
+ 
+ bad2:
+-	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
++	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
+ 			"Function : %d, Subfunction : %d\n",
+ 			E1_FUNCTION_TYPE(cmv->bFunction),
+ 			E1_FUNCTION_SUBTYPE(cmv->bFunction));
+@@ -2038,7 +2038,7 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+ 	return;
+ 
+ bad2:
+-	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
++	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
+ 			"Function : %d, Subfunction : %d\n",
+ 			E4_FUNCTION_TYPE(cmv->wFunction),
+ 			E4_FUNCTION_SUBTYPE(cmv->wFunction));
+diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
+index 912d97a..bcc4213 100644
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+ 	   otherwise it is scheduled, and with high data rates data can get lost. */
+ 	tty->low_latency = 1;
+ 
++	if (usb_autopm_get_interface(acm->control)) {
++		mutex_unlock(&open_mutex);
++		return -EIO;
++	}
++
++	mutex_lock(&acm->mutex);
++	mutex_unlock(&open_mutex);
+ 	if (acm->used++) {
++		usb_autopm_put_interface(acm->control);
+ 		goto done;
+         }
+ 
++
+ 	acm->ctrlurb->dev = acm->dev;
+ 	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
+ 		dbg("usb_submit_urb(ctrl irq) failed");
+@@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+ 
+ done:
+ err_out:
+-	mutex_unlock(&open_mutex);
++	mutex_unlock(&acm->mutex);
+ 	return rv;
+ 
+ full_bailout:
+ 	usb_kill_urb(acm->ctrlurb);
+ bail_out:
++	usb_autopm_put_interface(acm->control);
+ 	acm->used--;
+-	mutex_unlock(&open_mutex);
++	mutex_unlock(&acm->mutex);
+ 	return -EIO;
+ }
+ 
+@@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
+ 			usb_kill_urb(acm->writeurb);
+ 			for (i = 0; i < nr; i++)
+ 				usb_kill_urb(acm->ru[i].urb);
++			usb_autopm_put_interface(acm->control);
+ 		} else
+ 			acm_tty_unregister(acm);
+ 	}
+@@ -904,7 +915,7 @@ next_desc:
+ 	}
+ 	
+ 	if (data_interface_num != call_interface_num)
+-		dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
++		dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
+ 
+ skip_normal_probe:
+ 
+@@ -980,6 +991,7 @@ skip_normal_probe:
+ 	spin_lock_init(&acm->throttle_lock);
+ 	spin_lock_init(&acm->write_lock);
+ 	spin_lock_init(&acm->read_lock);
++	mutex_init(&acm->mutex);
+ 	acm->write_ready = 1;
+ 	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
+ 
+@@ -1096,6 +1108,25 @@ alloc_fail:
+ 	return -ENOMEM;
+ }
+ 
++static void stop_data_traffic(struct acm *acm)
++{
++	int i;
++
++	tasklet_disable(&acm->urb_task);
++
++	usb_kill_urb(acm->ctrlurb);
++	usb_kill_urb(acm->writeurb);
++	for (i = 0; i < acm->rx_buflimit; i++)
++		usb_kill_urb(acm->ru[i].urb);
++
++	INIT_LIST_HEAD(&acm->filled_read_bufs);
++	INIT_LIST_HEAD(&acm->spare_read_bufs);
++
++	tasklet_enable(&acm->urb_task);
++
++	cancel_work_sync(&acm->work);
++}
++
+ static void acm_disconnect(struct usb_interface *intf)
+ {
+ 	struct acm *acm = usb_get_intfdata(intf);
+@@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf)
+ 	usb_set_intfdata(acm->control, NULL);
+ 	usb_set_intfdata(acm->data, NULL);
+ 
+-	tasklet_disable(&acm->urb_task);
+-
+-	usb_kill_urb(acm->ctrlurb);
+-	usb_kill_urb(acm->writeurb);
+-	for (i = 0; i < acm->rx_buflimit; i++)
+-		usb_kill_urb(acm->ru[i].urb);
+-
+-	INIT_LIST_HEAD(&acm->filled_read_bufs);
+-	INIT_LIST_HEAD(&acm->spare_read_bufs);
+-
+-	tasklet_enable(&acm->urb_task);
+-
+-	flush_scheduled_work(); /* wait for acm_softint */
++	stop_data_traffic(acm);
+ 
+ 	acm_write_buffers_free(acm);
+ 	usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
+@@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf)
+ 		tty_hangup(acm->tty);
+ }
+ 
++static int acm_suspend(struct usb_interface *intf, pm_message_t message)
++{
++	struct acm *acm = usb_get_intfdata(intf);
++
++	if (acm->susp_count++)
++		return 0;
++	/*
++	we treat opened interfaces differently,
++	we must guard against open
++	*/
++	mutex_lock(&acm->mutex);
++
++	if (acm->used)
++		stop_data_traffic(acm);
++
++	mutex_unlock(&acm->mutex);
++	return 0;
++}
++
++static int acm_resume(struct usb_interface *intf)
++{
++	struct acm *acm = usb_get_intfdata(intf);
++	int rv = 0;
++
++	if (--acm->susp_count)
++		return 0;
++
++	mutex_lock(&acm->mutex);
++	if (acm->used) {
++		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
++		if (rv < 0)
++		goto err_out;
++
++		tasklet_schedule(&acm->urb_task);
++	}
++
++err_out:
++	mutex_unlock(&acm->mutex);
++	return rv;
++}
+ /*
+  * USB driver structure.
+  */
+@@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = {
+ 	.name =		"cdc_acm",
+ 	.probe =	acm_probe,
+ 	.disconnect =	acm_disconnect,
++	.suspend =	acm_suspend,
++	.resume =	acm_resume,
+ 	.id_table =	acm_ids,
++	.supports_autosuspend = 1,
+ };
+ 
+ /*
+diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
+index 09f7765..8df6a57 100644
+--- a/drivers/usb/class/cdc-acm.h
++++ b/drivers/usb/class/cdc-acm.h
+@@ -107,6 +107,7 @@ struct acm {
+ 	int write_used;					/* number of non-empty write buffers */
+ 	int write_ready;				/* write urb is not running */
+ 	spinlock_t write_lock;
++	struct mutex mutex;
+ 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
+ 	struct work_struct work;			/* work queue entry for line discipline waking up */
+ 	struct tasklet_struct urb_task;                 /* rx processing */
+@@ -120,6 +121,7 @@ struct acm {
+ 	unsigned char throttle;				/* throttled by tty layer */
+ 	unsigned char clocal;				/* termios CLOCAL */
+ 	unsigned int ctrl_caps;				/* control capabilities from the class specific header */
++	unsigned int susp_count;			/* number of suspended interfaces */
+ };
+ 
+ #define CDC_DATA_INTERFACE_TYPE	0x0a
+diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
+index 97b09f2..5c33cdb 100644
+--- a/drivers/usb/core/Kconfig
++++ b/drivers/usb/core/Kconfig
+@@ -9,6 +9,21 @@ config USB_DEBUG
+ 	  of debug messages to the system log. Select this if you are having a
+ 	  problem with USB support and want to see more of what is going on.
+ 
++config USB_ANNOUNCE_NEW_DEVICES
++	bool "USB announce new devices"
++	depends on USB
++	default N
++	help
++	  Say Y here if you want the USB core to always announce the
++	  idVendor, idProduct, Manufacturer, Product, and SerialNumber
++	  strings for every new USB device to the syslog.  This option is
++	  usually used by distro vendors to help with debugging and to
++	  let users know what specific device was added to the machine
++	  in what location.
++
++	  If you do not want this kind of information sent to the system
++	  log, or have any doubts about this, say N here.
++
+ comment "Miscellaneous USB options"
+ 	depends on USB
+ 
+diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
+index 28d4972..cadb2dc 100644
+--- a/drivers/usb/core/buffer.c
++++ b/drivers/usb/core/buffer.c
+@@ -53,11 +53,13 @@ int hcd_buffer_create(struct usb_hcd *hcd)
+ 	char		name[16];
+ 	int 		i, size;
+ 
+-	if (!hcd->self.controller->dma_mask)
++	if (!hcd->self.controller->dma_mask &&
++	    !(hcd->driver->flags & HCD_LOCAL_MEM))
+ 		return 0;
+ 
+-	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
+-		if (!(size = pool_max [i]))
++	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
++		size = pool_max[i];
++		if (!size)
+ 			continue;
+ 		snprintf(name, sizeof name, "buffer-%d", size);
+ 		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
+@@ -80,10 +82,10 @@ int hcd_buffer_create(struct usb_hcd *hcd)
+  */
+ void hcd_buffer_destroy(struct usb_hcd *hcd)
+ {
+-	int		i;
++	int i;
+ 
+-	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
+-		struct dma_pool		*pool = hcd->pool[i];
++	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
++		struct dma_pool *pool = hcd->pool[i];
+ 		if (pool) {
+ 			dma_pool_destroy(pool);
+ 			hcd->pool[i] = NULL;
+@@ -107,7 +109,8 @@ void *hcd_buffer_alloc(
+ 	int 			i;
+ 
+ 	/* some USB hosts just use PIO */
+-	if (!bus->controller->dma_mask) {
++	if (!bus->controller->dma_mask &&
++	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ 		*dma = ~(dma_addr_t) 0;
+ 		return kmalloc(size, mem_flags);
+ 	}
+@@ -132,7 +135,8 @@ void hcd_buffer_free(
+ 	if (!addr)
+ 		return;
+ 
+-	if (!bus->controller->dma_mask) {
++	if (!bus->controller->dma_mask &&
++	    !(hcd->driver->flags & HCD_LOCAL_MEM)) {
+ 		kfree(addr);
+ 		return;
+ 	}
+diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
+index 1a8edce..a92122a 100644
+--- a/drivers/usb/core/config.c
++++ b/drivers/usb/core/config.c
+@@ -238,7 +238,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
+ 
+ 	/* Allocate space for the right(?) number of endpoints */
+ 	num_ep = num_ep_orig = alt->desc.bNumEndpoints;
+-	alt->desc.bNumEndpoints = 0;		// Use as a counter
++	alt->desc.bNumEndpoints = 0;		/* Use as a counter */
+ 	if (num_ep > USB_MAXENDPOINTS) {
+ 		dev_warn(ddev, "too many endpoints for config %d interface %d "
+ 		    "altsetting %d: %d, using maximum allowed: %d\n",
+@@ -246,7 +246,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
+ 		num_ep = USB_MAXENDPOINTS;
+ 	}
+ 
+-	if (num_ep > 0) {	/* Can't allocate 0 bytes */
++	if (num_ep > 0) {
++		/* Can't allocate 0 bytes */
+ 		len = sizeof(struct usb_host_endpoint) * num_ep;
+ 		alt->endpoint = kzalloc(len, GFP_KERNEL);
+ 		if (!alt->endpoint)
+@@ -475,8 +476,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
+ 	return 0;
+ }
+ 
+-// hub-only!! ... and only exported for reset/reinit path.
+-// otherwise used internally on disconnect/destroy path
++/* hub-only!! ... and only exported for reset/reinit path.
++ * otherwise used internally on disconnect/destroy path
++ */
+ void usb_destroy_configuration(struct usb_device *dev)
+ {
+ 	int c, i;
+@@ -498,7 +500,7 @@ void usb_destroy_configuration(struct usb_device *dev)
+ 		kfree(cf->string);
+ 		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
+ 			if (cf->intf_cache[i])
+-				kref_put(&cf->intf_cache[i]->ref, 
++				kref_put(&cf->intf_cache[i]->ref,
+ 					  usb_release_interface_cache);
+ 		}
+ 	}
+@@ -525,7 +527,7 @@ int usb_get_configuration(struct usb_device *dev)
+ 	unsigned int cfgno, length;
+ 	unsigned char *buffer;
+ 	unsigned char *bigbuffer;
+- 	struct usb_config_descriptor *desc;
++	struct usb_config_descriptor *desc;
+ 
+ 	cfgno = 0;
+ 	if (dev->authorized == 0)	/* Not really an error */
+diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
+index 87c794d..83d9dc3 100644
+--- a/drivers/usb/core/devices.c
++++ b/drivers/usb/core/devices.c
+@@ -89,7 +89,7 @@ static const char *format_string_serialnumber =
+ static const char *format_bandwidth =
+ /* B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
+   "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
+-  
++
+ static const char *format_device1 =
+ /* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+   "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+@@ -101,7 +101,7 @@ static const char *format_device2 =
+ static const char *format_config =
+ /* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+   "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+-  
++
+ static const char *format_iad =
+ /* A:  FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
+   "A:  FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+@@ -122,7 +122,7 @@ static const char *format_endpt =
+  */
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+-static unsigned int conndiscevcnt = 0;
++static unsigned int conndiscevcnt;
+ 
+ /* this struct stores the poll state for <mountpoint>/devices pollers */
+ struct usb_device_status {
+@@ -172,12 +172,8 @@ static const char *class_decode(const int class)
+ 	return clas_info[ix].class_name;
+ }
+ 
+-static char *usb_dump_endpoint_descriptor(
+-	int speed,
+-	char *start,
+-	char *end,
+-	const struct usb_endpoint_descriptor *desc
+-)
++static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
++				const struct usb_endpoint_descriptor *desc)
+ {
+ 	char dir, unit, *type;
+ 	unsigned interval, bandwidth = 1;
+@@ -235,22 +231,24 @@ static char *usb_dump_endpoint_descriptor(
+ 
+ 	start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
+ 			 desc->bmAttributes, type,
+-			 (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * bandwidth,
++			 (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
++			 bandwidth,
+ 			 interval, unit);
+ 	return start;
+ }
+ 
+ static char *usb_dump_interface_descriptor(char *start, char *end,
+-	const struct usb_interface_cache *intfc,
+-	const struct usb_interface *iface,
+-	int setno)
++					const struct usb_interface_cache *intfc,
++					const struct usb_interface *iface,
++					int setno)
+ {
+-	const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
++	const struct usb_interface_descriptor *desc;
+ 	const char *driver_name = "";
+ 	int active = 0;
+ 
+ 	if (start > end)
+ 		return start;
++	desc = &intfc->altsetting[setno].desc;
+ 	if (iface) {
+ 		driver_name = (iface->dev.driver
+ 				? iface->dev.driver->name
+@@ -270,14 +268,10 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
+ 	return start;
+ }
+ 
+-static char *usb_dump_interface(
+-	int speed,
+-	char *start,
+-	char *end,
+-	const struct usb_interface_cache *intfc,
+-	const struct usb_interface *iface,
+-	int setno
+-) {
++static char *usb_dump_interface(int speed, char *start, char *end,
++				const struct usb_interface_cache *intfc,
++				const struct usb_interface *iface, int setno)
++{
+ 	const struct usb_host_interface *desc = &intfc->altsetting[setno];
+ 	int i;
+ 
+@@ -292,7 +286,7 @@ static char *usb_dump_interface(
+ }
+ 
+ static char *usb_dump_iad_descriptor(char *start, char *end,
+-	const struct usb_interface_assoc_descriptor *iad)
++			const struct usb_interface_assoc_descriptor *iad)
+ {
+ 	if (start > end)
+ 		return start;
+@@ -311,13 +305,15 @@ static char *usb_dump_iad_descriptor(char *start, char *end,
+  * 1. marking active interface altsettings (code lists all, but should mark
+  *    which ones are active, if any)
+  */
+-
+-static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
++static char *usb_dump_config_descriptor(char *start, char *end,
++				const struct usb_config_descriptor *desc,
++				int active)
+ {
+ 	if (start > end)
+ 		return start;
+ 	start += sprintf(start, format_config,
+-			 active ? '*' : ' ',	/* mark active/actual/current cfg. */
++			 /* mark active/actual/current cfg. */
++			 active ? '*' : ' ',
+ 			 desc->bNumInterfaces,
+ 			 desc->bConfigurationValue,
+ 			 desc->bmAttributes,
+@@ -325,13 +321,8 @@ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb
+ 	return start;
+ }
+ 
+-static char *usb_dump_config (
+-	int speed,
+-	char *start,
+-	char *end,
+-	const struct usb_host_config *config,
+-	int active
+-)
++static char *usb_dump_config(int speed, char *start, char *end,
++			     const struct usb_host_config *config, int active)
+ {
+ 	int i, j;
+ 	struct usb_interface_cache *intfc;
+@@ -339,7 +330,8 @@ static char *usb_dump_config (
+ 
+ 	if (start > end)
+ 		return start;
+-	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
++	if (!config)
++		/* getting these some in 2.3.7; none in 2.3.6 */
+ 		return start + sprintf(start, "(null Cfg. desc.)\n");
+ 	start = usb_dump_config_descriptor(start, end, &config->desc, active);
+ 	for (i = 0; i < USB_MAXIADS; i++) {
+@@ -364,7 +356,8 @@ static char *usb_dump_config (
+ /*
+  * Dump the different USB descriptors.
+  */
+-static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
++static char *usb_dump_device_descriptor(char *start, char *end,
++				const struct usb_device_descriptor *desc)
+ {
+ 	u16 bcdUSB = le16_to_cpu(desc->bcdUSB);
+ 	u16 bcdDevice = le16_to_cpu(desc->bcdDevice);
+@@ -374,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
+ 	start += sprintf(start, format_device1,
+ 			  bcdUSB >> 8, bcdUSB & 0xff,
+ 			  desc->bDeviceClass,
+-			  class_decode (desc->bDeviceClass),
++			  class_decode(desc->bDeviceClass),
+ 			  desc->bDeviceSubClass,
+ 			  desc->bDeviceProtocol,
+ 			  desc->bMaxPacketSize0,
+@@ -391,12 +384,14 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
+ /*
+  * Dump the different strings that this device holds.
+  */
+-static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
++static char *usb_dump_device_strings(char *start, char *end,
++				     struct usb_device *dev)
+ {
+ 	if (start > end)
+ 		return start;
+ 	if (dev->manufacturer)
+-		start += sprintf(start, format_string_manufacturer, dev->manufacturer);
++		start += sprintf(start, format_string_manufacturer,
++				 dev->manufacturer);
+ 	if (start > end)
+ 		goto out;
+ 	if (dev->product)
+@@ -405,7 +400,8 @@ static char *usb_dump_device_strings(char *start, char *end, struct usb_device *
+ 		goto out;
+ #ifdef ALLOW_SERIAL_NUMBER
+ 	if (dev->serial)
+-		start += sprintf(start, format_string_serialnumber, dev->serial);
++		start += sprintf(start, format_string_serialnumber,
++				 dev->serial);
+ #endif
+  out:
+ 	return start;
+@@ -417,12 +413,12 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
+ 
+ 	if (start > end)
+ 		return start;
+-		
++
+ 	start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+ 
+ 	if (start > end)
+ 		return start;
+-	
++
+ 	start = usb_dump_device_strings(start, end, dev);
+ 
+ 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+@@ -439,7 +435,8 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
+ 
+ #ifdef PROC_EXTRA /* TBD: may want to add this code later */
+ 
+-static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
++static char *usb_dump_hub_descriptor(char *start, char *end,
++				     const struct usb_hub_descriptor *desc)
+ {
+ 	int leng = USB_DT_HUB_NONVAR_SIZE;
+ 	unsigned char *ptr = (unsigned char *)desc;
+@@ -455,13 +452,16 @@ static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hu
+ 	return start;
+ }
+ 
+-static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
++static char *usb_dump_string(char *start, char *end,
++			     const struct usb_device *dev, char *id, int index)
+ {
+ 	if (start > end)
+ 		return start;
+ 	start += sprintf(start, "Interface:");
+-	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+-		start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
++	if (index <= dev->maxstring && dev->stringindex &&
++	    dev->stringindex[index])
++		start += sprintf(start, "%s: %.100s ", id,
++				 dev->stringindex[index]);
+ 	return start;
+ }
+ 
+@@ -476,8 +476,10 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
+  * file_offset - the offset into the devices file on completion
+  * The caller must own the device lock.
+  */
+-static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
+-				struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
++static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
++			       loff_t *skip_bytes, loff_t *file_offset,
++			       struct usb_device *usbdev, struct usb_bus *bus,
++			       int level, int index, int count)
+ {
+ 	int chix;
+ 	int ret, cnt = 0;
+@@ -485,17 +487,19 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
+ 	char *pages_start, *data_end, *speed;
+ 	unsigned int length;
+ 	ssize_t total_written = 0;
+-	
++
+ 	/* don't bother with anything else if we're not writing any data */
+ 	if (*nbytes <= 0)
+ 		return 0;
+-	
++
+ 	if (level > MAX_TOPO_LEVEL)
+ 		return 0;
+-	/* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
+-        if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
+-                return -ENOMEM;
+-		
++	/* allocate 2^1 pages = 8K (on i386);
++	 * should be more than enough for one device */
++	pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
++	if (!pages_start)
++		return -ENOMEM;
++
+ 	if (usbdev->parent && usbdev->parent->devnum != -1)
+ 		parent_devnum = usbdev->parent->devnum;
+ 	/*
+@@ -541,15 +545,16 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
+ 				bus->bandwidth_allocated, max,
+ 				(100 * bus->bandwidth_allocated + max / 2)
+ 					/ max,
+-			         bus->bandwidth_int_reqs,
+-				 bus->bandwidth_isoc_reqs);
+-	
++				bus->bandwidth_int_reqs,
++				bus->bandwidth_isoc_reqs);
++
+ 	}
+-	data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
+-	
++	data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256,
++				 usbdev);
++
+ 	if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
+ 		data_end += sprintf(data_end, "(truncated)\n");
+-	
++
+ 	length = data_end - pages_start;
+ 	/* if we can start copying some data to the user */
+ 	if (length > *skip_bytes) {
+@@ -567,17 +572,18 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
+ 		*skip_bytes = 0;
+ 	} else
+ 		*skip_bytes -= length;
+-	
++
+ 	free_pages((unsigned long)pages_start, 1);
+-	
++
+ 	/* Now look at all of this device's children. */
+ 	for (chix = 0; chix < usbdev->maxchild; chix++) {
+ 		struct usb_device *childdev = usbdev->children[chix];
+ 
+ 		if (childdev) {
+ 			usb_lock_device(childdev);
+-			ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
+-					bus, level + 1, chix, ++cnt);
++			ret = usb_device_dump(buffer, nbytes, skip_bytes,
++					      file_offset, childdev, bus,
++					      level + 1, chix, ++cnt);
+ 			usb_unlock_device(childdev);
+ 			if (ret == -EFAULT)
+ 				return total_written;
+@@ -587,7 +593,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
+ 	return total_written;
+ }
+ 
+-static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
++static ssize_t usb_device_read(struct file *file, char __user *buf,
++			       size_t nbytes, loff_t *ppos)
+ {
+ 	struct usb_bus *bus;
+ 	ssize_t ret, total_written = 0;
+@@ -607,7 +614,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
+ 		if (!bus->root_hub)
+ 			continue;
+ 		usb_lock_device(bus->root_hub);
+-		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
++		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
++				      bus->root_hub, bus, 0, 0, 0);
+ 		usb_unlock_device(bus->root_hub);
+ 		if (ret < 0) {
+ 			mutex_unlock(&usb_bus_list_lock);
+@@ -620,7 +628,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
+ }
+ 
+ /* Kernel lock for "lastev" protection */
+-static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
++static unsigned int usb_device_poll(struct file *file,
++				    struct poll_table_struct *wait)
+ {
+ 	struct usb_device_status *st = file->private_data;
+ 	unsigned int mask = 0;
+@@ -629,7 +638,8 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
+ 	if (!st) {
+ 		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
+ 
+-		/* we may have dropped BKL - need to check for having lost the race */
++		/* we may have dropped BKL -
++		 * need to check for having lost the race */
+ 		if (file->private_data) {
+ 			kfree(st);
+ 			st = file->private_data;
+@@ -652,7 +662,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
+ 	}
+ lost_race:
+ 	if (file->f_mode & FMODE_READ)
+-                poll_wait(file, &deviceconndiscwq, wait);
++		poll_wait(file, &deviceconndiscwq, wait);
+ 	if (st->lastev != conndiscevcnt)
+ 		mask |= POLLIN;
+ 	st->lastev = conndiscevcnt;
+@@ -662,18 +672,18 @@ lost_race:
+ 
+ static int usb_device_open(struct inode *inode, struct file *file)
+ {
+-        file->private_data = NULL;
+-        return 0;
++	file->private_data = NULL;
++	return 0;
+ }
+ 
+ static int usb_device_release(struct inode *inode, struct file *file)
+ {
+ 	kfree(file->private_data);
+ 	file->private_data = NULL;
+-        return 0;
++	return 0;
+ }
+ 
+-static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
++static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
+ {
+ 	loff_t ret;
+ 
+diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
+index 1f4f6d0..ae94176 100644
+--- a/drivers/usb/core/devio.c
++++ b/drivers/usb/core/devio.c
+@@ -75,14 +75,14 @@ struct async {
+ 	u32 secid;
+ };
+ 
+-static int usbfs_snoop = 0;
+-module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);
+-MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
++static int usbfs_snoop;
++module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
+ 
+ #define snoop(dev, format, arg...)				\
+ 	do {							\
+ 		if (usbfs_snoop)				\
+-			dev_info( dev , format , ## arg);	\
++			dev_info(dev , format , ## arg);	\
+ 	} while (0)
+ 
+ #define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
+@@ -90,7 +90,7 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
+ 
+ #define	MAX_USBFS_BUFFER_SIZE	16384
+ 
+-static inline int connected (struct dev_state *ps)
++static inline int connected(struct dev_state *ps)
+ {
+ 	return (!list_empty(&ps->list) &&
+ 			ps->dev->state != USB_STATE_NOTATTACHED);
+@@ -120,7 +120,8 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
+ 	return ret;
+ }
+ 
+-static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
++static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
++			   loff_t *ppos)
+ {
+ 	struct dev_state *ps = file->private_data;
+ 	struct usb_device *dev = ps->dev;
+@@ -140,7 +141,8 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
+ 	}
+ 
+ 	if (pos < sizeof(struct usb_device_descriptor)) {
+-		struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
++		/* 18 bytes - fits on the stack */
++		struct usb_device_descriptor temp_desc;
+ 
+ 		memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
+ 		le16_to_cpus(&temp_desc.bcdUSB);
+@@ -210,17 +212,17 @@ err:
+ 
+ static struct async *alloc_async(unsigned int numisoframes)
+ {
+-        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
+-        struct async *as = kzalloc(assize, GFP_KERNEL);
++	struct async *as;
+ 
+-        if (!as)
+-                return NULL;
++	as = kzalloc(sizeof(struct async), GFP_KERNEL);
++	if (!as)
++		return NULL;
+ 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
+ 	if (!as->urb) {
+ 		kfree(as);
+ 		return NULL;
+ 	}
+-        return as;
++	return as;
+ }
+ 
+ static void free_async(struct async *as)
+@@ -234,52 +236,54 @@ static void free_async(struct async *as)
+ 
+ static inline void async_newpending(struct async *as)
+ {
+-        struct dev_state *ps = as->ps;
+-        unsigned long flags;
+-        
+-        spin_lock_irqsave(&ps->lock, flags);
+-        list_add_tail(&as->asynclist, &ps->async_pending);
+-        spin_unlock_irqrestore(&ps->lock, flags);
++	struct dev_state *ps = as->ps;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ps->lock, flags);
++	list_add_tail(&as->asynclist, &ps->async_pending);
++	spin_unlock_irqrestore(&ps->lock, flags);
+ }
+ 
+ static inline void async_removepending(struct async *as)
+ {
+-        struct dev_state *ps = as->ps;
+-        unsigned long flags;
+-        
+-        spin_lock_irqsave(&ps->lock, flags);
+-        list_del_init(&as->asynclist);
+-        spin_unlock_irqrestore(&ps->lock, flags);
++	struct dev_state *ps = as->ps;
++	unsigned long flags;
++
++	spin_lock_irqsave(&ps->lock, flags);
++	list_del_init(&as->asynclist);
++	spin_unlock_irqrestore(&ps->lock, flags);
+ }
+ 
+ static inline struct async *async_getcompleted(struct dev_state *ps)
+ {
+-        unsigned long flags;
+-        struct async *as = NULL;
+-
+-        spin_lock_irqsave(&ps->lock, flags);
+-        if (!list_empty(&ps->async_completed)) {
+-                as = list_entry(ps->async_completed.next, struct async, asynclist);
+-                list_del_init(&as->asynclist);
+-        }
+-        spin_unlock_irqrestore(&ps->lock, flags);
+-        return as;
++	unsigned long flags;
++	struct async *as = NULL;
++
++	spin_lock_irqsave(&ps->lock, flags);
++	if (!list_empty(&ps->async_completed)) {
++		as = list_entry(ps->async_completed.next, struct async,
++				asynclist);
++		list_del_init(&as->asynclist);
++	}
++	spin_unlock_irqrestore(&ps->lock, flags);
++	return as;
+ }
+ 
+-static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
++static inline struct async *async_getpending(struct dev_state *ps,
++					     void __user *userurb)
+ {
+-        unsigned long flags;
+-        struct async *as;
++	unsigned long flags;
++	struct async *as;
+ 
+-        spin_lock_irqsave(&ps->lock, flags);
++	spin_lock_irqsave(&ps->lock, flags);
+ 	list_for_each_entry(as, &ps->async_pending, asynclist)
+ 		if (as->userurb == userurb) {
+ 			list_del_init(&as->asynclist);
+ 			spin_unlock_irqrestore(&ps->lock, flags);
+ 			return as;
+ 		}
+-        spin_unlock_irqrestore(&ps->lock, flags);
+-        return NULL;
++	spin_unlock_irqrestore(&ps->lock, flags);
++	return NULL;
+ }
+ 
+ static void snoop_urb(struct urb *urb, void __user *userurb)
+@@ -298,19 +302,19 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
+ 	dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
+ 	dev_info(&urb->dev->dev, "data: ");
+ 	for (j = 0; j < urb->transfer_buffer_length; ++j)
+-		printk ("%02x ", data[j]);
++		printk("%02x ", data[j]);
+ 	printk("\n");
+ }
+ 
+ static void async_completed(struct urb *urb)
+ {
+-        struct async *as = urb->context;
+-        struct dev_state *ps = as->ps;
++	struct async *as = urb->context;
++	struct dev_state *ps = as->ps;
+ 	struct siginfo sinfo;
+ 
+-        spin_lock(&ps->lock);
+-        list_move_tail(&as->asynclist, &ps->async_completed);
+-        spin_unlock(&ps->lock);
++	spin_lock(&ps->lock);
++	list_move_tail(&as->asynclist, &ps->async_completed);
++	spin_unlock(&ps->lock);
+ 	as->status = urb->status;
+ 	if (as->signr) {
+ 		sinfo.si_signo = as->signr;
+@@ -325,7 +329,7 @@ static void async_completed(struct urb *urb)
+ 	wake_up(&ps->wait);
+ }
+ 
+-static void destroy_async (struct dev_state *ps, struct list_head *list)
++static void destroy_async(struct dev_state *ps, struct list_head *list)
+ {
+ 	struct async *as;
+ 	unsigned long flags;
+@@ -348,7 +352,8 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
+ 	}
+ }
+ 
+-static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum)
++static void destroy_async_on_interface(struct dev_state *ps,
++				       unsigned int ifnum)
+ {
+ 	struct list_head *p, *q, hitlist;
+ 	unsigned long flags;
+@@ -364,7 +369,7 @@ static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum
+ 
+ static inline void destroy_all_async(struct dev_state *ps)
+ {
+-	        destroy_async(ps, &ps->async_pending);
++	destroy_async(ps, &ps->async_pending);
+ }
+ 
+ /*
+@@ -373,15 +378,15 @@ static inline void destroy_all_async(struct dev_state *ps)
+  * they're also undone when devices disconnect.
+  */
+ 
+-static int driver_probe (struct usb_interface *intf,
+-			 const struct usb_device_id *id)
++static int driver_probe(struct usb_interface *intf,
++			const struct usb_device_id *id)
+ {
+ 	return -ENODEV;
+ }
+ 
+ static void driver_disconnect(struct usb_interface *intf)
+ {
+-	struct dev_state *ps = usb_get_intfdata (intf);
++	struct dev_state *ps = usb_get_intfdata(intf);
+ 	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
+ 
+ 	if (!ps)
+@@ -396,16 +401,31 @@ static void driver_disconnect(struct usb_interface *intf)
+ 	else
+ 		warn("interface number %u out of range", ifnum);
+ 
+-	usb_set_intfdata (intf, NULL);
++	usb_set_intfdata(intf, NULL);
+ 
+ 	/* force async requests to complete */
+ 	destroy_async_on_interface(ps, ifnum);
+ }
+ 
++/* The following routines are merely placeholders.  There is no way
++ * to inform a user task about suspend or resumes.
++ */
++static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
++{
++	return 0;
++}
++
++static int driver_resume(struct usb_interface *intf)
++{
++	return 0;
++}
++
+ struct usb_driver usbfs_driver = {
+ 	.name =		"usbfs",
+ 	.probe =	driver_probe,
+ 	.disconnect =	driver_disconnect,
++	.suspend =	driver_suspend,
++	.resume =	driver_resume,
+ };
+ 
+ static int claimintf(struct dev_state *ps, unsigned int ifnum)
+@@ -459,15 +479,16 @@ static int checkintf(struct dev_state *ps, unsigned int ifnum)
+ 	if (test_bit(ifnum, &ps->ifclaimed))
+ 		return 0;
+ 	/* if not yet claimed, claim it for the driver */
+-	dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",
+-	       task_pid_nr(current), current->comm, ifnum);
++	dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
++		 "interface %u before use\n", task_pid_nr(current),
++		 current->comm, ifnum);
+ 	return claimintf(ps, ifnum);
+ }
+ 
+ static int findintfep(struct usb_device *dev, unsigned int ep)
+ {
+ 	unsigned int i, j, e;
+-        struct usb_interface *intf;
++	struct usb_interface *intf;
+ 	struct usb_host_interface *alts;
+ 	struct usb_endpoint_descriptor *endpt;
+ 
+@@ -478,7 +499,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
+ 	for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ 		intf = dev->actconfig->interface[i];
+ 		for (j = 0; j < intf->num_altsetting; j++) {
+-                        alts = &intf->altsetting[j];
++			alts = &intf->altsetting[j];
+ 			for (e = 0; e < alts->desc.bNumEndpoints; e++) {
+ 				endpt = &alts->endpoint[e].desc;
+ 				if (endpt->bEndpointAddress == ep)
+@@ -486,10 +507,11 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
+ 			}
+ 		}
+ 	}
+-	return -ENOENT; 
++	return -ENOENT;
+ }
+ 
+-static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
++static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
++			   unsigned int index)
+ {
+ 	int ret = 0;
+ 
+@@ -502,7 +524,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
+ 	index &= 0xff;
+ 	switch (requesttype & USB_RECIP_MASK) {
+ 	case USB_RECIP_ENDPOINT:
+-		if ((ret = findintfep(ps->dev, index)) >= 0)
++		ret = findintfep(ps->dev, index);
++		if (ret >= 0)
+ 			ret = checkintf(ps, ret);
+ 		break;
+ 
+@@ -546,7 +569,8 @@ static int usbdev_open(struct inode *inode, struct file *file)
+ 	mutex_lock(&usbfs_mutex);
+ 
+ 	ret = -ENOMEM;
+-	if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
++	ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
++	if (!ps)
+ 		goto out;
+ 
+ 	ret = -ENOENT;
+@@ -627,15 +651,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)
+ 
+ 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+ 		return -EFAULT;
+-	if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
++	ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
++	if (ret)
+ 		return ret;
+ 	if (ctrl.wLength > PAGE_SIZE)
+ 		return -EINVAL;
+-	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
++	tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
++	if (!tbuf)
+ 		return -ENOMEM;
+ 	tmo = ctrl.timeout;
+ 	if (ctrl.bRequestType & 0x80) {
+-		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
++		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
++					       ctrl.wLength)) {
+ 			free_page((unsigned long)tbuf);
+ 			return -EINVAL;
+ 		}
+@@ -646,14 +673,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
+ 				ctrl.wIndex, ctrl.wLength);
+ 
+ 		usb_unlock_device(dev);
+-		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
+-				       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
++		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest,
++				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
++				    tbuf, ctrl.wLength, tmo);
+ 		usb_lock_device(dev);
+ 		if ((i > 0) && ctrl.wLength) {
+ 			if (usbfs_snoop) {
+ 				dev_info(&dev->dev, "control read: data ");
+ 				for (j = 0; j < i; ++j)
+-					printk("%02x ", (unsigned char)(tbuf)[j]);
++					printk("%02x ", (u8)(tbuf)[j]);
+ 				printk("\n");
+ 			}
+ 			if (copy_to_user(ctrl.data, tbuf, i)) {
+@@ -680,12 +708,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
+ 			printk("\n");
+ 		}
+ 		usb_unlock_device(dev);
+-		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
+-				       ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
++		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
++				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
++				    tbuf, ctrl.wLength, tmo);
+ 		usb_lock_device(dev);
+ 	}
+ 	free_page((unsigned long)tbuf);
+-	if (i<0 && i != -EPIPE) {
++	if (i < 0 && i != -EPIPE) {
+ 		dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
+ 			   "failed cmd %s rqt %u rq %u len %u ret %d\n",
+ 			   current->comm, ctrl.bRequestType, ctrl.bRequest,
+@@ -705,9 +734,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
+ 
+ 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
+ 		return -EFAULT;
+-	if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
++	ret = findintfep(ps->dev, bulk.ep);
++	if (ret < 0)
+ 		return ret;
+-	if ((ret = checkintf(ps, ret)))
++	ret = checkintf(ps, ret);
++	if (ret)
+ 		return ret;
+ 	if (bulk.ep & USB_DIR_IN)
+ 		pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
+@@ -735,7 +766,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
+ 			if (usbfs_snoop) {
+ 				dev_info(&dev->dev, "bulk read: data ");
+ 				for (j = 0; j < len2; ++j)
+-					printk("%02x ", (unsigned char)(tbuf)[j]);
++					printk("%02x ", (u8)(tbuf)[j]);
+ 				printk("\n");
+ 			}
+ 			if (copy_to_user(bulk.data, tbuf, len2)) {
+@@ -775,9 +806,11 @@ static int proc_resetep(struct dev_state *ps, void __user *arg)
+ 
+ 	if (get_user(ep, (unsigned int __user *)arg))
+ 		return -EFAULT;
+-	if ((ret = findintfep(ps->dev, ep)) < 0)
++	ret = findintfep(ps->dev, ep);
++	if (ret < 0)
+ 		return ret;
+-	if ((ret = checkintf(ps, ret)))
++	ret = checkintf(ps, ret);
++	if (ret)
+ 		return ret;
+ 	usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
+ 	return 0;
+@@ -791,18 +824,19 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)
+ 
+ 	if (get_user(ep, (unsigned int __user *)arg))
+ 		return -EFAULT;
+-	if ((ret = findintfep(ps->dev, ep)) < 0)
++	ret = findintfep(ps->dev, ep);
++	if (ret < 0)
+ 		return ret;
+-	if ((ret = checkintf(ps, ret)))
++	ret = checkintf(ps, ret);
++	if (ret)
+ 		return ret;
+ 	if (ep & USB_DIR_IN)
+-                pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+-        else
+-                pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
++		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
++	else
++		pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+ 
+ 	return usb_clear_halt(ps->dev, pipe);
+ }
+-		
+ 
+ static int proc_getdriver(struct dev_state *ps, void __user *arg)
+ {
+@@ -856,23 +890,23 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
+ {
+ 	int u;
+ 	int status = 0;
+- 	struct usb_host_config *actconfig;
++	struct usb_host_config *actconfig;
+ 
+ 	if (get_user(u, (int __user *)arg))
+ 		return -EFAULT;
+ 
+- 	actconfig = ps->dev->actconfig;
+- 
+- 	/* Don't touch the device if any interfaces are claimed.
+- 	 * It could interfere with other drivers' operations, and if
++	actconfig = ps->dev->actconfig;
++
++	/* Don't touch the device if any interfaces are claimed.
++	 * It could interfere with other drivers' operations, and if
+ 	 * an interface is claimed by usbfs it could easily deadlock.
+ 	 */
+- 	if (actconfig) {
+- 		int i;
+- 
+- 		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+- 			if (usb_interface_claimed(actconfig->interface[i])) {
+-				dev_warn (&ps->dev->dev,
++	if (actconfig) {
++		int i;
++
++		for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
++			if (usb_interface_claimed(actconfig->interface[i])) {
++				dev_warn(&ps->dev->dev,
+ 					"usbfs: interface %d claimed by %s "
+ 					"while '%s' sets config #%d\n",
+ 					actconfig->interface[i]
+@@ -881,11 +915,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
+ 					actconfig->interface[i]
+ 						->dev.driver->name,
+ 					current->comm, u);
+- 				status = -EBUSY;
++				status = -EBUSY;
+ 				break;
+ 			}
+- 		}
+- 	}
++		}
++	}
+ 
+ 	/* SET_CONFIGURATION is often abused as a "cheap" driver reset,
+ 	 * so avoid usb_set_configuration()'s kick to sysfs
+@@ -901,8 +935,8 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
+ }
+ 
+ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+-			     struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+-			     void __user *arg)
++			struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
++			void __user *arg)
+ {
+ 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
+ 	struct usb_host_endpoint *ep;
+@@ -917,12 +951,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 		return -EINVAL;
+ 	if (!uurb->buffer)
+ 		return -EINVAL;
+-	if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX))
++	if (uurb->signr != 0 && (uurb->signr < SIGRTMIN ||
++				 uurb->signr > SIGRTMAX))
+ 		return -EINVAL;
+-	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+-		if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0)
++	if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
++	    (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
++		ifnum = findintfep(ps->dev, uurb->endpoint);
++		if (ifnum < 0)
+ 			return ifnum;
+-		if ((ret = checkintf(ps, ifnum)))
++		ret = checkintf(ps, ifnum);
++		if (ret)
+ 			return ret;
+ 	}
+ 	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+@@ -938,10 +976,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 	case USBDEVFS_URB_TYPE_CONTROL:
+ 		if (!usb_endpoint_xfer_control(&ep->desc))
+ 			return -EINVAL;
+-		/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
+-		if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
++		/* min 8 byte setup packet,
++		 * max 8 byte setup plus an arbitrary data stage */
++		if (uurb->buffer_length < 8 ||
++		    uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
+ 			return -EINVAL;
+-		if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
++		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
++		if (!dr)
+ 			return -ENOMEM;
+ 		if (copy_from_user(dr, uurb->buffer, 8)) {
+ 			kfree(dr);
+@@ -951,7 +992,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 			kfree(dr);
+ 			return -EINVAL;
+ 		}
+-		if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
++		ret = check_ctrlrecip(ps, dr->bRequestType,
++				      le16_to_cpup(&dr->wIndex));
++		if (ret) {
+ 			kfree(dr);
+ 			return ret;
+ 		}
+@@ -997,11 +1040,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 
+ 	case USBDEVFS_URB_TYPE_ISO:
+ 		/* arbitrary limit */
+-		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
++		if (uurb->number_of_packets < 1 ||
++		    uurb->number_of_packets > 128)
+ 			return -EINVAL;
+ 		if (!usb_endpoint_xfer_isoc(&ep->desc))
+ 			return -EINVAL;
+-		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
++		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
++				   uurb->number_of_packets;
+ 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
+ 			return -ENOMEM;
+ 		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
+@@ -1009,7 +1054,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 			return -EFAULT;
+ 		}
+ 		for (totlen = u = 0; u < uurb->number_of_packets; u++) {
+-			/* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */
++			/* arbitrary limit,
++			 * sufficient for USB 2.0 high-bandwidth iso */
+ 			if (isopkt[u].length > 8192) {
+ 				kfree(isopkt);
+ 				return -EINVAL;
+@@ -1039,25 +1085,27 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 	default:
+ 		return -EINVAL;
+ 	}
+-	if (!(as = alloc_async(uurb->number_of_packets))) {
++	as = alloc_async(uurb->number_of_packets);
++	if (!as) {
+ 		kfree(isopkt);
+ 		kfree(dr);
+ 		return -ENOMEM;
+ 	}
+-	if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
++	as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL);
++	if (!as->urb->transfer_buffer) {
+ 		kfree(isopkt);
+ 		kfree(dr);
+ 		free_async(as);
+ 		return -ENOMEM;
+ 	}
+-        as->urb->dev = ps->dev;
+-        as->urb->pipe = (uurb->type << 30) |
++	as->urb->dev = ps->dev;
++	as->urb->pipe = (uurb->type << 30) |
+ 			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
+ 			(uurb->endpoint & USB_DIR_IN);
+-        as->urb->transfer_flags = uurb->flags |
++	as->urb->transfer_flags = uurb->flags |
+ 			(is_in ? URB_DIR_IN : URB_DIR_OUT);
+ 	as->urb->transfer_buffer_length = uurb->buffer_length;
+-	as->urb->setup_packet = (unsigned char*)dr;
++	as->urb->setup_packet = (unsigned char *)dr;
+ 	as->urb->start_frame = uurb->start_frame;
+ 	as->urb->number_of_packets = uurb->number_of_packets;
+ 	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+@@ -1065,8 +1113,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
+ 	else
+ 		as->urb->interval = ep->desc.bInterval;
+-        as->urb->context = as;
+-        as->urb->complete = async_completed;
++	as->urb->context = as;
++	as->urb->complete = async_completed;
+ 	for (totlen = u = 0; u < uurb->number_of_packets; u++) {
+ 		as->urb->iso_frame_desc[u].offset = totlen;
+ 		as->urb->iso_frame_desc[u].length = isopkt[u].length;
+@@ -1074,7 +1122,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 	}
+ 	kfree(isopkt);
+ 	as->ps = ps;
+-        as->userurb = arg;
++	as->userurb = arg;
+ 	if (uurb->endpoint & USB_DIR_IN)
+ 		as->userbuffer = uurb->buffer;
+ 	else
+@@ -1093,14 +1141,15 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
+ 		}
+ 	}
+ 	snoop_urb(as->urb, as->userurb);
+-        async_newpending(as);
+-        if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
+-		dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
+-                async_removepending(as);
+-                free_async(as);
+-                return ret;
+-        }
+-        return 0;
++	async_newpending(as);
++	if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
++		dev_printk(KERN_DEBUG, &ps->dev->dev,
++			   "usbfs: usb_submit_urb returned %d\n", ret);
++		async_removepending(as);
++		free_async(as);
++		return ret;
++	}
++	return 0;
+ }
+ 
+ static int proc_submiturb(struct dev_state *ps, void __user *arg)
+@@ -1110,7 +1159,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
+ 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
+ 		return -EFAULT;
+ 
+-	return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
++	return proc_do_submiturb(ps, &uurb,
++			(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
++			arg);
+ }
+ 
+ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
+@@ -1132,7 +1183,8 @@ static int processcompl(struct async *as, void __user * __user *arg)
+ 	unsigned int i;
+ 
+ 	if (as->userbuffer)
+-		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
++		if (copy_to_user(as->userbuffer, urb->transfer_buffer,
++				 urb->transfer_buffer_length))
+ 			return -EFAULT;
+ 	if (put_user(as->status, &userurb->status))
+ 		return -EFAULT;
+@@ -1159,16 +1211,17 @@ static int processcompl(struct async *as, void __user * __user *arg)
+ 	return 0;
+ }
+ 
+-static struct async* reap_as(struct dev_state *ps)
++static struct async *reap_as(struct dev_state *ps)
+ {
+-        DECLARE_WAITQUEUE(wait, current);
++	DECLARE_WAITQUEUE(wait, current);
+ 	struct async *as = NULL;
+ 	struct usb_device *dev = ps->dev;
+ 
+ 	add_wait_queue(&ps->wait, &wait);
+ 	for (;;) {
+ 		__set_current_state(TASK_INTERRUPTIBLE);
+-		if ((as = async_getcompleted(ps)))
++		as = async_getcompleted(ps);
++		if (as)
+ 			break;
+ 		if (signal_pending(current))
+ 			break;
+@@ -1232,10 +1285,12 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
+ {
+ 	struct usbdevfs_urb uurb;
+ 
+-	if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg))
++	if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
+ 		return -EFAULT;
+ 
+-	return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
++	return proc_do_submiturb(ps, &uurb,
++			((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
++			arg);
+ }
+ 
+ static int processcompl_compat(struct async *as, void __user * __user *arg)
+@@ -1246,7 +1301,8 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
+ 	unsigned int i;
+ 
+ 	if (as->userbuffer)
+-		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
++		if (copy_to_user(as->userbuffer, urb->transfer_buffer,
++				 urb->transfer_buffer_length))
+ 			return -EFAULT;
+ 	if (put_user(as->status, &userurb->status))
+ 		return -EFAULT;
+@@ -1337,16 +1393,16 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+ 	struct usb_driver       *driver = NULL;
+ 
+ 	/* alloc buffer */
+-	if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) {
+-		if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
++	if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
++		if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
+ 			return -ENOMEM;
+ 		if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
+-			if (copy_from_user (buf, ctl->data, size)) {
++			if (copy_from_user(buf, ctl->data, size)) {
+ 				kfree(buf);
+ 				return -EFAULT;
+ 			}
+ 		} else {
+-			memset (buf, 0, size);
++			memset(buf, 0, size);
+ 		}
+ 	}
+ 
+@@ -1357,15 +1413,15 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+ 
+ 	if (ps->dev->state != USB_STATE_CONFIGURED)
+ 		retval = -EHOSTUNREACH;
+-	else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno)))
+-               retval = -EINVAL;
++	else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
++		retval = -EINVAL;
+ 	else switch (ctl->ioctl_code) {
+ 
+ 	/* disconnect kernel driver from interface */
+ 	case USBDEVFS_DISCONNECT:
+ 		if (intf->dev.driver) {
+ 			driver = to_usb_driver(intf->dev.driver);
+-			dev_dbg (&intf->dev, "disconnect by usbfs\n");
++			dev_dbg(&intf->dev, "disconnect by usbfs\n");
+ 			usb_driver_release_interface(driver, intf);
+ 		} else
+ 			retval = -ENODATA;
+@@ -1373,9 +1429,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+ 
+ 	/* let kernel drivers try to (re)bind to the interface */
+ 	case USBDEVFS_CONNECT:
+-		usb_unlock_device(ps->dev);
+-		retval = bus_rescan_devices(intf->dev.bus);
+-		usb_lock_device(ps->dev);
++		if (!intf->dev.driver)
++			retval = device_attach(&intf->dev);
++		else
++			retval = -EBUSY;
+ 		break;
+ 
+ 	/* talk directly to the interface's driver */
+@@ -1385,7 +1442,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+ 		if (driver == NULL || driver->ioctl == NULL) {
+ 			retval = -ENOTTY;
+ 		} else {
+-			retval = driver->ioctl (intf, ctl->ioctl_code, buf);
++			retval = driver->ioctl(intf, ctl->ioctl_code, buf);
+ 			if (retval == -ENOIOCTLCMD)
+ 				retval = -ENOTTY;
+ 		}
+@@ -1393,9 +1450,9 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
+ 
+ 	/* cleanup and return */
+ 	if (retval >= 0
+-			&& (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
++			&& (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
+ 			&& size > 0
+-			&& copy_to_user (ctl->data, buf, size) != 0)
++			&& copy_to_user(ctl->data, buf, size) != 0)
+ 		retval = -EFAULT;
+ 
+ 	kfree(buf);
+@@ -1406,7 +1463,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
+ {
+ 	struct usbdevfs_ioctl	ctrl;
+ 
+-	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
++	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+ 		return -EFAULT;
+ 	return proc_ioctl(ps, &ctrl);
+ }
+@@ -1434,7 +1491,8 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
+  * are assuming that somehow the configuration has been prevented from
+  * changing.  But there's no mechanism to ensure that...
+  */
+-static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static int usbdev_ioctl(struct inode *inode, struct file *file,
++			unsigned int cmd, unsigned long arg)
+ {
+ 	struct dev_state *ps = file->private_data;
+ 	struct usb_device *dev = ps->dev;
+@@ -1577,7 +1635,8 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
+ }
+ 
+ /* No kernel lock - fine */
+-static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
++static unsigned int usbdev_poll(struct file *file,
++				struct poll_table_struct *wait)
+ {
+ 	struct dev_state *ps = file->private_data;
+ 	unsigned int mask = 0;
+@@ -1648,7 +1707,7 @@ int __init usb_devio_init(void)
+ 	int retval;
+ 
+ 	retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
+-			"usb_device");
++					"usb_device");
+ 	if (retval) {
+ 		err("unable to register minors for usb_device");
+ 		goto out;
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index c51f8e9..801b6f1 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
+ 		goto exit;
+ 
+ 	if (usb_drv->probe != NULL)
+-		error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
+-					  &driver_attr_new_id.attr);
++		error = driver_create_file(&usb_drv->drvwrap.driver,
++					   &driver_attr_new_id);
+ exit:
+ 	return error;
+ }
+@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
+ 		return;
+ 
+ 	if (usb_drv->probe != NULL)
+-		sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
+-				  &driver_attr_new_id.attr);
++		driver_remove_file(&usb_drv->drvwrap.driver,
++				   &driver_attr_new_id);
+ }
+ 
+ static void usb_free_dynids(struct usb_driver *usb_drv)
+@@ -202,10 +202,10 @@ static int usb_probe_interface(struct device *dev)
+ 	intf = to_usb_interface(dev);
+ 	udev = interface_to_usbdev(intf);
+ 
+- 	if (udev->authorized == 0) {
+- 		dev_err(&intf->dev, "Device is not authorized for usage\n");
+- 		return -ENODEV;
+- 	}
++	if (udev->authorized == 0) {
++		dev_err(&intf->dev, "Device is not authorized for usage\n");
++		return -ENODEV;
++	}
+ 
+ 	id = usb_match_id(intf, driver->id_table);
+ 	if (!id)
+@@ -299,7 +299,7 @@ static int usb_unbind_interface(struct device *dev)
+  * lock.
+  */
+ int usb_driver_claim_interface(struct usb_driver *driver,
+-				struct usb_interface *iface, void* priv)
++				struct usb_interface *iface, void *priv)
+ {
+ 	struct device *dev = &iface->dev;
+ 	struct usb_device *udev = interface_to_usbdev(iface);
+@@ -325,7 +325,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
+ 
+ 	return retval;
+ }
+-EXPORT_SYMBOL(usb_driver_claim_interface);
++EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
+ 
+ /**
+  * usb_driver_release_interface - unbind a driver from an interface
+@@ -370,7 +370,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
+ 	iface->needs_remote_wakeup = 0;
+ 	usb_pm_unlock(udev);
+ }
+-EXPORT_SYMBOL(usb_driver_release_interface);
++EXPORT_SYMBOL_GPL(usb_driver_release_interface);
+ 
+ /* returns 0 if no match, 1 if match */
+ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
+@@ -398,7 +398,7 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
+ 		return 0;
+ 
+ 	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+-	    (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
++	    (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
+ 		return 0;
+ 
+ 	if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+@@ -534,15 +534,15 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
+ 	   id->driver_info is the way to create an entry that
+ 	   indicates that the driver want to examine every
+ 	   device and interface. */
+-	for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+-	       id->driver_info; id++) {
++	for (; id->idVendor || id->idProduct || id->bDeviceClass ||
++	       id->bInterfaceClass || id->driver_info; id++) {
+ 		if (usb_match_one_id(interface, id))
+ 			return id;
+ 	}
+ 
+ 	return NULL;
+ }
+-EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
++EXPORT_SYMBOL_GPL(usb_match_id);
+ 
+ static int usb_device_match(struct device *dev, struct device_driver *drv)
+ {
+@@ -586,7 +586,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
+ 	struct usb_device *usb_dev;
+ 
+ 	/* driver is often null here; dev_dbg() would oops */
+-	pr_debug ("usb %s: uevent\n", dev->bus_id);
++	pr_debug("usb %s: uevent\n", dev->bus_id);
+ 
+ 	if (is_usb_device(dev))
+ 		usb_dev = to_usb_device(dev);
+@@ -596,11 +596,11 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
+ 	}
+ 
+ 	if (usb_dev->devnum < 0) {
+-		pr_debug ("usb %s: already deleted?\n", dev->bus_id);
++		pr_debug("usb %s: already deleted?\n", dev->bus_id);
+ 		return -ENODEV;
+ 	}
+ 	if (!usb_dev->bus) {
+-		pr_debug ("usb %s: bus removed?\n", dev->bus_id);
++		pr_debug("usb %s: bus removed?\n", dev->bus_id);
+ 		return -ENODEV;
+ 	}
+ 
+@@ -745,7 +745,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ 
+ 	return retval;
+ }
+-EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
++EXPORT_SYMBOL_GPL(usb_register_driver);
+ 
+ /**
+  * usb_deregister - unregister a USB interface driver
+@@ -769,7 +769,7 @@ void usb_deregister(struct usb_driver *driver)
+ 
+ 	usbfs_update_special();
+ }
+-EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
++EXPORT_SYMBOL_GPL(usb_deregister);
+ 
+ #ifdef CONFIG_PM
+ 
+@@ -854,8 +854,10 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
+ 			dev_err(&intf->dev, "%s error %d\n",
+ 					"suspend", status);
+ 	} else {
+-		// FIXME else if there's no suspend method, disconnect...
+-		// Not possible if auto_pm is set...
++		/*
++		 * FIXME else if there's no suspend method, disconnect...
++		 * Not possible if auto_pm is set...
++		 */
+ 		dev_warn(&intf->dev, "no suspend for driver %s?\n",
+ 				driver->name);
+ 		mark_quiesced(intf);
+@@ -894,7 +896,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
+ 				dev_err(&intf->dev, "%s error %d\n",
+ 						"reset_resume", status);
+ 		} else {
+-			// status = -EOPNOTSUPP;
++			/* status = -EOPNOTSUPP; */
+ 			dev_warn(&intf->dev, "no %s for driver %s?\n",
+ 					"reset_resume", driver->name);
+ 		}
+@@ -905,7 +907,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
+ 				dev_err(&intf->dev, "%s error %d\n",
+ 						"resume", status);
+ 		} else {
+-			// status = -EOPNOTSUPP;
++			/* status = -EOPNOTSUPP; */
+ 			dev_warn(&intf->dev, "no %s for driver %s?\n",
+ 					"resume", driver->name);
+ 		}
+@@ -1175,7 +1177,7 @@ static int usb_resume_both(struct usb_device *udev)
+ 			 * so if a root hub's controller is suspended
+ 			 * then we're stuck. */
+ 			status = usb_resume_device(udev);
+- 		}
++		}
+ 	} else {
+ 
+ 		/* Needed for setting udev->dev.power.power_state.event,
+diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
+index 5d860bc..8133c99 100644
+--- a/drivers/usb/core/file.c
++++ b/drivers/usb/core/file.c
+@@ -204,7 +204,7 @@ int usb_register_dev(struct usb_interface *intf,
+ exit:
+ 	return retval;
+ }
+-EXPORT_SYMBOL(usb_register_dev);
++EXPORT_SYMBOL_GPL(usb_register_dev);
+ 
+ /**
+  * usb_deregister_dev - deregister a USB device's dynamic minor.
+@@ -245,4 +245,4 @@ void usb_deregister_dev(struct usb_interface *intf,
+ 	intf->minor = -1;
+ 	destroy_usb_class();
+ }
+-EXPORT_SYMBOL(usb_deregister_dev);
++EXPORT_SYMBOL_GPL(usb_deregister_dev);
+diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
+index 3fb9af8..84760dd 100644
+--- a/drivers/usb/core/hcd-pci.c
++++ b/drivers/usb/core/hcd-pci.c
+@@ -1,6 +1,6 @@
+ /*
+  * (C) Copyright David Brownell 2000-2002
+- * 
++ *
+  * 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
+@@ -55,7 +55,7 @@
+  *
+  * Store this function in the HCD's struct pci_driver as probe().
+  */
+-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
++int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ {
+ 	struct hc_driver	*driver;
+ 	struct usb_hcd		*hcd;
+@@ -64,66 +64,71 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+ 	if (usb_disabled())
+ 		return -ENODEV;
+ 
+-	if (!id || !(driver = (struct hc_driver *) id->driver_data))
++	if (!id)
++		return -EINVAL;
++	driver = (struct hc_driver *)id->driver_data;
++	if (!driver)
+ 		return -EINVAL;
+ 
+-	if (pci_enable_device (dev) < 0)
++	if (pci_enable_device(dev) < 0)
+ 		return -ENODEV;
+ 	dev->current_state = PCI_D0;
+ 	dev->dev.power.power_state = PMSG_ON;
+-	
+-        if (!dev->irq) {
+-        	dev_err (&dev->dev,
++
++	if (!dev->irq) {
++		dev_err(&dev->dev,
+ 			"Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",
+ 			pci_name(dev));
+-   	        retval = -ENODEV;
++		retval = -ENODEV;
+ 		goto err1;
+-        }
++	}
+ 
+-	hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
++	hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
+ 	if (!hcd) {
+ 		retval = -ENOMEM;
+ 		goto err1;
+ 	}
+ 
+-	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
+-		hcd->rsrc_start = pci_resource_start (dev, 0);
+-		hcd->rsrc_len = pci_resource_len (dev, 0);
+-		if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
++	if (driver->flags & HCD_MEMORY) {
++		/* EHCI, OHCI */
++		hcd->rsrc_start = pci_resource_start(dev, 0);
++		hcd->rsrc_len = pci_resource_len(dev, 0);
++		if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ 				driver->description)) {
+-			dev_dbg (&dev->dev, "controller already in use\n");
++			dev_dbg(&dev->dev, "controller already in use\n");
+ 			retval = -EBUSY;
+ 			goto err2;
+ 		}
+-		hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
++		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ 		if (hcd->regs == NULL) {
+-			dev_dbg (&dev->dev, "error mapping memory\n");
++			dev_dbg(&dev->dev, "error mapping memory\n");
+ 			retval = -EFAULT;
+ 			goto err3;
+ 		}
+ 
+-	} else { 				// UHCI
++	} else {
++		/* UHCI */
+ 		int	region;
+ 
+ 		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+-			if (!(pci_resource_flags (dev, region) &
++			if (!(pci_resource_flags(dev, region) &
+ 					IORESOURCE_IO))
+ 				continue;
+ 
+-			hcd->rsrc_start = pci_resource_start (dev, region);
+-			hcd->rsrc_len = pci_resource_len (dev, region);
+-			if (request_region (hcd->rsrc_start, hcd->rsrc_len,
++			hcd->rsrc_start = pci_resource_start(dev, region);
++			hcd->rsrc_len = pci_resource_len(dev, region);
++			if (request_region(hcd->rsrc_start, hcd->rsrc_len,
+ 					driver->description))
+ 				break;
+ 		}
+ 		if (region == PCI_ROM_RESOURCE) {
+-			dev_dbg (&dev->dev, "no i/o regions available\n");
++			dev_dbg(&dev->dev, "no i/o regions available\n");
+ 			retval = -EBUSY;
+ 			goto err1;
+ 		}
+ 	}
+ 
+-	pci_set_master (dev);
++	pci_set_master(dev);
+ 
+ 	retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
+ 	if (retval != 0)
+@@ -132,19 +137,19 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+ 
+  err4:
+ 	if (driver->flags & HCD_MEMORY) {
+-		iounmap (hcd->regs);
++		iounmap(hcd->regs);
+  err3:
+-		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	} else
+-		release_region (hcd->rsrc_start, hcd->rsrc_len);
++		release_region(hcd->rsrc_start, hcd->rsrc_len);
+  err2:
+-	usb_put_hcd (hcd);
++	usb_put_hcd(hcd);
+  err1:
+-	pci_disable_device (dev);
+-	dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
++	pci_disable_device(dev);
++	dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
+ 	return retval;
+-} 
+-EXPORT_SYMBOL (usb_hcd_pci_probe);
++}
++EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
+ 
+ 
+ /* may be called without controller electrically present */
+@@ -161,7 +166,7 @@ EXPORT_SYMBOL (usb_hcd_pci_probe);
+  *
+  * Store this function in the HCD's struct pci_driver as remove().
+  */
+-void usb_hcd_pci_remove (struct pci_dev *dev)
++void usb_hcd_pci_remove(struct pci_dev *dev)
+ {
+ 	struct usb_hcd		*hcd;
+ 
+@@ -169,17 +174,17 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
+ 	if (!hcd)
+ 		return;
+ 
+-	usb_remove_hcd (hcd);
++	usb_remove_hcd(hcd);
+ 	if (hcd->driver->flags & HCD_MEMORY) {
+-		iounmap (hcd->regs);
+-		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++		iounmap(hcd->regs);
++		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	} else {
+-		release_region (hcd->rsrc_start, hcd->rsrc_len);
++		release_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	}
+-	usb_put_hcd (hcd);
++	usb_put_hcd(hcd);
+ 	pci_disable_device(dev);
+ }
+-EXPORT_SYMBOL (usb_hcd_pci_remove);
++EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
+ 
+ 
+ #ifdef	CONFIG_PM
+@@ -191,7 +196,7 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
+  *
+  * Store this function in the HCD's struct pci_driver as suspend().
+  */
+-int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
++int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
+ {
+ 	struct usb_hcd		*hcd;
+ 	int			retval = 0;
+@@ -246,12 +251,18 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
+ 
+ 		/* no DMA or IRQs except when HC is active */
+ 		if (dev->current_state == PCI_D0) {
+-			pci_save_state (dev);
+-			pci_disable_device (dev);
++			pci_save_state(dev);
++			pci_disable_device(dev);
++		}
++
++		if (message.event == PM_EVENT_FREEZE ||
++				message.event == PM_EVENT_PRETHAW) {
++			dev_dbg(hcd->self.controller, "--> no state change\n");
++			goto done;
+ 		}
+ 
+ 		if (!has_pci_pm) {
+-			dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
++			dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n");
+ 			goto done;
+ 		}
+ 
+@@ -260,30 +271,30 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
+ 		 * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
+ 		 * some device state (e.g. as part of clock reinit).
+ 		 */
+-		retval = pci_set_power_state (dev, PCI_D3hot);
++		retval = pci_set_power_state(dev, PCI_D3hot);
+ 		suspend_report_result(pci_set_power_state, retval);
+ 		if (retval == 0) {
+ 			int wake = device_can_wakeup(&hcd->self.root_hub->dev);
+ 
+ 			wake = wake && device_may_wakeup(hcd->self.controller);
+ 
+-			dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
++			dev_dbg(hcd->self.controller, "--> PCI D3%s\n",
+ 					wake ? "/wakeup" : "");
+ 
+ 			/* Ignore these return values.  We rely on pci code to
+ 			 * reject requests the hardware can't implement, rather
+ 			 * than coding the same thing.
+ 			 */
+-			(void) pci_enable_wake (dev, PCI_D3hot, wake);
+-			(void) pci_enable_wake (dev, PCI_D3cold, wake);
++			(void) pci_enable_wake(dev, PCI_D3hot, wake);
++			(void) pci_enable_wake(dev, PCI_D3cold, wake);
+ 		} else {
+-			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
++			dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
+ 					retval);
+-			(void) usb_hcd_pci_resume (dev);
++			(void) usb_hcd_pci_resume(dev);
+ 		}
+ 
+ 	} else if (hcd->state != HC_STATE_HALT) {
+-		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
++		dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n",
+ 			hcd->state);
+ 		WARN_ON(1);
+ 		retval = -EINVAL;
+@@ -298,7 +309,7 @@ done:
+ 		if (machine_is(powermac)) {
+ 			struct device_node	*of_node;
+ 
+-			of_node = pci_device_to_OF_node (dev);
++			of_node = pci_device_to_OF_node(dev);
+ 			if (of_node)
+ 				pmac_call_feature(PMAC_FTR_USB_ENABLE,
+ 							of_node, 0, 0);
+@@ -308,7 +319,7 @@ done:
+ 
+ 	return retval;
+ }
+-EXPORT_SYMBOL (usb_hcd_pci_suspend);
++EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
+ 
+ /**
+  * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+@@ -316,14 +327,14 @@ EXPORT_SYMBOL (usb_hcd_pci_suspend);
+  *
+  * Store this function in the HCD's struct pci_driver as resume().
+  */
+-int usb_hcd_pci_resume (struct pci_dev *dev)
++int usb_hcd_pci_resume(struct pci_dev *dev)
+ {
+ 	struct usb_hcd		*hcd;
+ 	int			retval;
+ 
+ 	hcd = pci_get_drvdata(dev);
+ 	if (hcd->state != HC_STATE_SUSPENDED) {
+-		dev_dbg (hcd->self.controller, 
++		dev_dbg(hcd->self.controller,
+ 				"can't resume, not suspended!\n");
+ 		return 0;
+ 	}
+@@ -333,9 +344,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
+ 	if (machine_is(powermac)) {
+ 		struct device_node *of_node;
+ 
+-		of_node = pci_device_to_OF_node (dev);
++		of_node = pci_device_to_OF_node(dev);
+ 		if (of_node)
+-			pmac_call_feature (PMAC_FTR_USB_ENABLE,
++			pmac_call_feature(PMAC_FTR_USB_ENABLE,
+ 						of_node, 0, 1);
+ 	}
+ #endif
+@@ -374,8 +385,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
+ 		}
+ #endif
+ 		/* yes, ignore these results too... */
+-		(void) pci_enable_wake (dev, dev->current_state, 0);
+-		(void) pci_enable_wake (dev, PCI_D3cold, 0);
++		(void) pci_enable_wake(dev, dev->current_state, 0);
++		(void) pci_enable_wake(dev, PCI_D3cold, 0);
+ 	} else {
+ 		/* Same basic cases: clean (powered/not), dirty */
+ 		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
+@@ -386,14 +397,14 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
+ 	 * but that won't re-enable bus mastering.  Yet pci_disable_device()
+ 	 * explicitly disables bus mastering...
+ 	 */
+-	retval = pci_enable_device (dev);
++	retval = pci_enable_device(dev);
+ 	if (retval < 0) {
+-		dev_err (hcd->self.controller,
++		dev_err(hcd->self.controller,
+ 			"can't re-enable after resume, %d!\n", retval);
+ 		return retval;
+ 	}
+-	pci_set_master (dev);
+-	pci_restore_state (dev);
++	pci_set_master(dev);
++	pci_restore_state(dev);
+ 
+ 	dev->dev.power.power_state = PMSG_ON;
+ 
+@@ -402,15 +413,15 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
+ 	if (hcd->driver->resume) {
+ 		retval = hcd->driver->resume(hcd);
+ 		if (retval) {
+-			dev_err (hcd->self.controller,
++			dev_err(hcd->self.controller,
+ 				"PCI post-resume error %d!\n", retval);
+-			usb_hc_died (hcd);
++			usb_hc_died(hcd);
+ 		}
+ 	}
+ 
+ 	return retval;
+ }
+-EXPORT_SYMBOL (usb_hcd_pci_resume);
++EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
+ 
+ #endif	/* CONFIG_PM */
+ 
+@@ -418,7 +429,7 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
+  * usb_hcd_pci_shutdown - shutdown host controller
+  * @dev: USB Host Controller being shutdown
+  */
+-void usb_hcd_pci_shutdown (struct pci_dev *dev)
++void usb_hcd_pci_shutdown(struct pci_dev *dev)
+ {
+ 	struct usb_hcd		*hcd;
+ 
+@@ -429,5 +440,5 @@ void usb_hcd_pci_shutdown (struct pci_dev *dev)
+ 	if (hcd->driver->shutdown)
+ 		hcd->driver->shutdown(hcd);
+ }
+-EXPORT_SYMBOL (usb_hcd_pci_shutdown);
++EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
+ 
+diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
+index d5ed3fa..e52ed16 100644
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -35,6 +35,7 @@
+ #include <linux/mutex.h>
+ #include <asm/irq.h>
+ #include <asm/byteorder.h>
++#include <asm/unaligned.h>
+ #include <linux/platform_device.h>
+ #include <linux/workqueue.h>
+ 
+@@ -131,8 +132,8 @@ static const u8 usb2_rh_dev_descriptor [18] = {
+ 	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
+ 	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
+ 
+-	0x00, 0x00, /*  __le16 idVendor; */
+- 	0x00, 0x00, /*  __le16 idProduct; */
++	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
++	0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
+ 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
+ 
+ 	0x03,       /*  __u8  iManufacturer; */
+@@ -154,8 +155,8 @@ static const u8 usb11_rh_dev_descriptor [18] = {
+ 	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
+ 	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
+ 
+-	0x00, 0x00, /*  __le16 idVendor; */
+- 	0x00, 0x00, /*  __le16 idProduct; */
++	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
++	0x01, 0x00, /*  __le16 idProduct; device 0x0001 */
+ 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
+ 
+ 	0x03,       /*  __u8  iManufacturer; */
+@@ -807,13 +808,13 @@ static int usb_register_bus(struct usb_bus *bus)
+ 	}
+ 	set_bit (busnum, busmap.busmap);
+ 	bus->busnum = busnum;
+-	bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
+-					     bus->controller, "usb_host%d",
+-					     busnum);
+-	result = PTR_ERR(bus->class_dev);
+-	if (IS_ERR(bus->class_dev))
++
++	bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
++				 "usb_host%d", busnum);
++	result = PTR_ERR(bus->dev);
++	if (IS_ERR(bus->dev))
+ 		goto error_create_class_dev;
+-	class_set_devdata(bus->class_dev, bus);
++	dev_set_drvdata(bus->dev, bus);
+ 
+ 	/* Add it to the local list of buses */
+ 	list_add (&bus->bus_list, &usb_bus_list);
+@@ -857,7 +858,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
+ 
+ 	clear_bit (bus->busnum, busmap.busmap);
+ 
+-	class_device_unregister(bus->class_dev);
++	device_unregister(bus->dev);
+ }
+ 
+ /**
+@@ -970,7 +971,7 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+ 		return -1;
+ 	}
+ }
+-EXPORT_SYMBOL (usb_calc_bus_time);
++EXPORT_SYMBOL_GPL(usb_calc_bus_time);
+ 
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -1112,48 +1113,177 @@ void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+ }
+ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+ 
+-static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
++/*
++ * Some usb host controllers can only perform dma using a small SRAM area.
++ * The usb core itself is however optimized for host controllers that can dma
++ * using regular system memory - like pci devices doing bus mastering.
++ *
++ * To support host controllers with limited dma capabilites we provide dma
++ * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
++ * For this to work properly the host controller code must first use the
++ * function dma_declare_coherent_memory() to point out which memory area
++ * that should be used for dma allocations.
++ *
++ * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
++ * dma using dma_alloc_coherent() which in turn allocates from the memory
++ * area pointed out with dma_declare_coherent_memory().
++ *
++ * So, to summarize...
++ *
++ * - We need "local" memory, canonical example being
++ *   a small SRAM on a discrete controller being the
++ *   only memory that the controller can read ...
++ *   (a) "normal" kernel memory is no good, and
++ *   (b) there's not enough to share
++ *
++ * - The only *portable* hook for such stuff in the
++ *   DMA framework is dma_declare_coherent_memory()
++ *
++ * - So we use that, even though the primary requirement
++ *   is that the memory be "local" (hence addressible
++ *   by that device), not "coherent".
++ *
++ */
++
++static int hcd_alloc_coherent(struct usb_bus *bus,
++			      gfp_t mem_flags, dma_addr_t *dma_handle,
++			      void **vaddr_handle, size_t size,
++			      enum dma_data_direction dir)
++{
++	unsigned char *vaddr;
++
++	vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
++				 mem_flags, dma_handle);
++	if (!vaddr)
++		return -ENOMEM;
++
++	/*
++	 * Store the virtual address of the buffer at the end
++	 * of the allocated dma buffer. The size of the buffer
++	 * may be uneven so use unaligned functions instead
++	 * of just rounding up. It makes sense to optimize for
++	 * memory footprint over access speed since the amount
++	 * of memory available for dma may be limited.
++	 */
++	put_unaligned((unsigned long)*vaddr_handle,
++		      (unsigned long *)(vaddr + size));
++
++	if (dir == DMA_TO_DEVICE)
++		memcpy(vaddr, *vaddr_handle, size);
++
++	*vaddr_handle = vaddr;
++	return 0;
++}
++
++static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
++			      void **vaddr_handle, size_t size,
++			      enum dma_data_direction dir)
++{
++	unsigned char *vaddr = *vaddr_handle;
++
++	vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size));
++
++	if (dir == DMA_FROM_DEVICE)
++		memcpy(vaddr, *vaddr_handle, size);
++
++	hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle);
++
++	*vaddr_handle = vaddr;
++	*dma_handle = 0;
++}
++
++static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
++			   gfp_t mem_flags)
+ {
++	enum dma_data_direction dir;
++	int ret = 0;
++
+ 	/* Map the URB's buffers for DMA access.
+ 	 * Lower level HCD code should use *_dma exclusively,
+ 	 * unless it uses pio or talks to another transport.
+ 	 */
+-	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+-		if (usb_endpoint_xfer_control(&urb->ep->desc)
+-			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+-			urb->setup_dma = dma_map_single (
++	if (is_root_hub(urb->dev))
++		return 0;
++
++	if (usb_endpoint_xfer_control(&urb->ep->desc)
++	    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
++		if (hcd->self.uses_dma)
++			urb->setup_dma = dma_map_single(
+ 					hcd->self.controller,
+ 					urb->setup_packet,
+-					sizeof (struct usb_ctrlrequest),
++					sizeof(struct usb_ctrlrequest),
++					DMA_TO_DEVICE);
++		else if (hcd->driver->flags & HCD_LOCAL_MEM)
++			ret = hcd_alloc_coherent(
++					urb->dev->bus, mem_flags,
++					&urb->setup_dma,
++					(void **)&urb->setup_packet,
++					sizeof(struct usb_ctrlrequest),
+ 					DMA_TO_DEVICE);
+-		if (urb->transfer_buffer_length != 0
+-			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
++	}
++
++	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++	if (ret == 0 && urb->transfer_buffer_length != 0
++	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
++		if (hcd->self.uses_dma)
+ 			urb->transfer_dma = dma_map_single (
+ 					hcd->self.controller,
+ 					urb->transfer_buffer,
+ 					urb->transfer_buffer_length,
+-					usb_urb_dir_in(urb)
+-					    ? DMA_FROM_DEVICE
+-					    : DMA_TO_DEVICE);
++					dir);
++		else if (hcd->driver->flags & HCD_LOCAL_MEM) {
++			ret = hcd_alloc_coherent(
++					urb->dev->bus, mem_flags,
++					&urb->transfer_dma,
++					&urb->transfer_buffer,
++					urb->transfer_buffer_length,
++					dir);
++
++			if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
++			    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
++				hcd_free_coherent(urb->dev->bus,
++					&urb->setup_dma,
++					(void **)&urb->setup_packet,
++					sizeof(struct usb_ctrlrequest),
++					DMA_TO_DEVICE);
++		}
+ 	}
++	return ret;
+ }
+ 
+ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+ {
+-	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+-		if (usb_endpoint_xfer_control(&urb->ep->desc)
+-			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
++	enum dma_data_direction dir;
++
++	if (is_root_hub(urb->dev))
++		return;
++
++	if (usb_endpoint_xfer_control(&urb->ep->desc)
++	    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
++		if (hcd->self.uses_dma)
+ 			dma_unmap_single(hcd->self.controller, urb->setup_dma,
+ 					sizeof(struct usb_ctrlrequest),
+ 					DMA_TO_DEVICE);
+-		if (urb->transfer_buffer_length != 0
+-			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
++		else if (hcd->driver->flags & HCD_LOCAL_MEM)
++			hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
++					(void **)&urb->setup_packet,
++					sizeof(struct usb_ctrlrequest),
++					DMA_TO_DEVICE);
++	}
++
++	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++	if (urb->transfer_buffer_length != 0
++	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
++		if (hcd->self.uses_dma)
+ 			dma_unmap_single(hcd->self.controller,
+ 					urb->transfer_dma,
+ 					urb->transfer_buffer_length,
+-					usb_urb_dir_in(urb)
+-					    ? DMA_FROM_DEVICE
+-					    : DMA_TO_DEVICE);
++					dir);
++		else if (hcd->driver->flags & HCD_LOCAL_MEM)
++			hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
++					&urb->transfer_buffer,
++					urb->transfer_buffer_length,
++					dir);
+ 	}
+ }
+ 
+@@ -1185,7 +1315,12 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+ 	 * URBs must be submitted in process context with interrupts
+ 	 * enabled.
+ 	 */
+-	map_urb_for_dma(hcd, urb);
++	status = map_urb_for_dma(hcd, urb, mem_flags);
++	if (unlikely(status)) {
++		usbmon_urb_submit_error(&hcd->self, urb, status);
++		goto error;
++	}
++
+ 	if (is_root_hub(urb->dev))
+ 		status = rh_urb_enqueue(hcd, urb);
+ 	else
+@@ -1194,6 +1329,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+ 	if (unlikely(status)) {
+ 		usbmon_urb_submit_error(&hcd->self, urb, status);
+ 		unmap_urb_for_dma(hcd, urb);
++ error:
+ 		urb->hcpriv = NULL;
+ 		INIT_LIST_HEAD(&urb->urb_list);
+ 		atomic_dec(&urb->use_count);
+@@ -1291,7 +1427,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+ 		wake_up (&usb_kill_urb_queue);
+ 	usb_put_urb (urb);
+ }
+-EXPORT_SYMBOL (usb_hcd_giveback_urb);
++EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -1531,7 +1667,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
+ 		mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));
+ 	return status;
+ }
+-EXPORT_SYMBOL (usb_bus_start_enum);
++EXPORT_SYMBOL_GPL(usb_bus_start_enum);
+ 
+ #endif
+ 
+@@ -1638,7 +1774,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+ 			"USB Host Controller";
+ 	return hcd;
+ }
+-EXPORT_SYMBOL (usb_create_hcd);
++EXPORT_SYMBOL_GPL(usb_create_hcd);
+ 
+ static void hcd_release (struct kref *kref)
+ {
+@@ -1653,14 +1789,14 @@ struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
+ 		kref_get (&hcd->kref);
+ 	return hcd;
+ }
+-EXPORT_SYMBOL (usb_get_hcd);
++EXPORT_SYMBOL_GPL(usb_get_hcd);
+ 
+ void usb_put_hcd (struct usb_hcd *hcd)
+ {
+ 	if (hcd)
+ 		kref_put (&hcd->kref, hcd_release);
+ }
+-EXPORT_SYMBOL (usb_put_hcd);
++EXPORT_SYMBOL_GPL(usb_put_hcd);
+ 
+ /**
+  * usb_add_hcd - finish generic HCD structure initialization and register
+@@ -1786,7 +1922,7 @@ err_register_bus:
+ 	hcd_buffer_destroy(hcd);
+ 	return retval;
+ } 
+-EXPORT_SYMBOL (usb_add_hcd);
++EXPORT_SYMBOL_GPL(usb_add_hcd);
+ 
+ /**
+  * usb_remove_hcd - shutdown processing for generic HCDs
+@@ -1828,7 +1964,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
+ 	usb_deregister_bus(&hcd->self);
+ 	hcd_buffer_destroy(hcd);
+ }
+-EXPORT_SYMBOL (usb_remove_hcd);
++EXPORT_SYMBOL_GPL(usb_remove_hcd);
+ 
+ void
+ usb_hcd_platform_shutdown(struct platform_device* dev)
+@@ -1838,7 +1974,7 @@ usb_hcd_platform_shutdown(struct platform_device* dev)
+ 	if (hcd->driver->shutdown)
+ 		hcd->driver->shutdown(hcd);
+ }
+-EXPORT_SYMBOL (usb_hcd_platform_shutdown);
++EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
+index 98e2419..2d1c3d5 100644
+--- a/drivers/usb/core/hcd.h
++++ b/drivers/usb/core/hcd.h
+@@ -125,7 +125,7 @@ struct usb_hcd {
+ 
+ 	/* more shared queuing code would be good; it should support
+ 	 * smarter scheduling, handle transaction translators, etc;
+-	 * input size of periodic table to an interrupt scheduler. 
++	 * input size of periodic table to an interrupt scheduler.
+ 	 * (ohci 32, uhci 1024, ehci 256/512/1024).
+ 	 */
+ 
+@@ -133,16 +133,16 @@ struct usb_hcd {
+ 	 * this structure.
+ 	 */
+ 	unsigned long hcd_priv[0]
+-			__attribute__ ((aligned (sizeof(unsigned long))));
++			__attribute__ ((aligned(sizeof(unsigned long))));
+ };
+ 
+ /* 2.4 does this a bit differently ... */
+-static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
++static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
+ {
+ 	return &hcd->self;
+ }
+ 
+-static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
++static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
+ {
+ 	return container_of(bus, struct usb_hcd, self);
+ }
+@@ -165,6 +165,7 @@ struct hc_driver {
+ 
+ 	int	flags;
+ #define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
++#define	HCD_LOCAL_MEM	0x0002		/* HC needs local memory */
+ #define	HCD_USB11	0x0010		/* USB 1.1 */
+ #define	HCD_USB2	0x0020		/* USB 2.0 */
+ 
+@@ -201,15 +202,18 @@ struct hc_driver {
+ 			struct usb_host_endpoint *ep);
+ 
+ 	/* root hub support */
+-	int		(*hub_status_data) (struct usb_hcd *hcd, char *buf);
+-	int		(*hub_control) (struct usb_hcd *hcd,
++	int	(*hub_status_data) (struct usb_hcd *hcd, char *buf);
++	int	(*hub_control) (struct usb_hcd *hcd,
+ 				u16 typeReq, u16 wValue, u16 wIndex,
+ 				char *buf, u16 wLength);
+-	int		(*bus_suspend)(struct usb_hcd *);
+-	int		(*bus_resume)(struct usb_hcd *);
+-	int		(*start_port_reset)(struct usb_hcd *, unsigned port_num);
+-	void		(*hub_irq_enable)(struct usb_hcd *);
++	int	(*bus_suspend)(struct usb_hcd *);
++	int	(*bus_resume)(struct usb_hcd *);
++	int	(*start_port_reset)(struct usb_hcd *, unsigned port_num);
++	void	(*hub_irq_enable)(struct usb_hcd *);
+ 		/* Needed only if port-change IRQs are level-triggered */
++
++		/* force handover of high-speed port to full-speed companion */
++	void	(*relinquish_port)(struct usb_hcd *, int);
+ };
+ 
+ extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+@@ -217,56 +221,56 @@ extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ 		int status);
+ extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+ 
+-extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
+-extern int usb_hcd_unlink_urb (struct urb *urb, int status);
++extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
++extern int usb_hcd_unlink_urb(struct urb *urb, int status);
+ extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+ 		int status);
+ extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ 		struct usb_host_endpoint *ep);
+ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
+ 		struct usb_host_endpoint *ep);
+-extern int usb_hcd_get_frame_number (struct usb_device *udev);
++extern int usb_hcd_get_frame_number(struct usb_device *udev);
+ 
+-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
++extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
+ 		struct device *dev, char *bus_name);
+-extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
+-extern void usb_put_hcd (struct usb_hcd *hcd);
++extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
++extern void usb_put_hcd(struct usb_hcd *hcd);
+ extern int usb_add_hcd(struct usb_hcd *hcd,
+ 		unsigned int irqnum, unsigned long irqflags);
+ extern void usb_remove_hcd(struct usb_hcd *hcd);
+ 
+ struct platform_device;
+-extern void usb_hcd_platform_shutdown(struct platform_device* dev);
++extern void usb_hcd_platform_shutdown(struct platform_device *dev);
+ 
+ #ifdef CONFIG_PCI
+ struct pci_dev;
+ struct pci_device_id;
+-extern int usb_hcd_pci_probe (struct pci_dev *dev,
++extern int usb_hcd_pci_probe(struct pci_dev *dev,
+ 				const struct pci_device_id *id);
+-extern void usb_hcd_pci_remove (struct pci_dev *dev);
++extern void usb_hcd_pci_remove(struct pci_dev *dev);
+ 
+ #ifdef CONFIG_PM
+-extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
+-extern int usb_hcd_pci_resume (struct pci_dev *dev);
++extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state);
++extern int usb_hcd_pci_resume(struct pci_dev *dev);
+ #endif /* CONFIG_PM */
+ 
+-extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
++extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
+ 
+ #endif /* CONFIG_PCI */
+ 
+ /* pci-ish (pdev null is ok) buffer alloc/mapping support */
+-int hcd_buffer_create (struct usb_hcd *hcd);
+-void hcd_buffer_destroy (struct usb_hcd *hcd);
++int hcd_buffer_create(struct usb_hcd *hcd);
++void hcd_buffer_destroy(struct usb_hcd *hcd);
+ 
+-void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
++void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
+ 	gfp_t mem_flags, dma_addr_t *dma);
+-void hcd_buffer_free (struct usb_bus *bus, size_t size,
++void hcd_buffer_free(struct usb_bus *bus, size_t size,
+ 	void *addr, dma_addr_t dma);
+ 
+ /* generic bus glue, needed for host controllers that don't use PCI */
+-extern irqreturn_t usb_hcd_irq (int irq, void *__hcd);
++extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
+ 
+-extern void usb_hc_died (struct usb_hcd *hcd);
++extern void usb_hc_died(struct usb_hcd *hcd);
+ extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
+ 
+ /* -------------------------------------------------------------------------- */
+@@ -319,9 +323,9 @@ extern void usb_destroy_configuration(struct usb_device *dev);
+  * Generic bandwidth allocation constants/support
+  */
+ #define FRAME_TIME_USECS	1000L
+-#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
++#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
+ 		/* Trying not to use worst-case bit-stuffing
+-                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
++		 * of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+ 		/* bytecount = data payload byte count */
+ 
+ #define NS_TO_US(ns)	((ns + 500L) / 1000L)
+@@ -333,9 +337,9 @@ extern void usb_destroy_configuration(struct usb_device *dev);
+  */
+ #define BW_HOST_DELAY	1000L		/* nanoseconds */
+ #define BW_HUB_LS_SETUP	333L		/* nanoseconds */
+-                        /* 4 full-speed bit times (est.) */
++			/* 4 full-speed bit times (est.) */
+ 
+-#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
++#define FRAME_TIME_BITS			12000L	/* frame = 1 millisecond */
+ #define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
+ #define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
+ 
+@@ -345,16 +349,16 @@ extern void usb_destroy_configuration(struct usb_device *dev);
+  * to preallocate bandwidth)
+  */
+ #define USB2_HOST_DELAY	5	/* nsec, guess */
+-#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \
++#define HS_NSECS(bytes) (((55 * 8 * 2083) \
+ 	+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ 	+ USB2_HOST_DELAY)
+-#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \
++#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
+ 	+ (2083UL * (3 + BitTime(bytes))))/1000 \
+ 	+ USB2_HOST_DELAY)
+ #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
+ #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
+ 
+-extern long usb_calc_bus_time (int speed, int is_input,
++extern long usb_calc_bus_time(int speed, int is_input,
+ 			int isoc, int bytecount);
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -370,16 +374,16 @@ extern struct list_head usb_bus_list;
+ extern struct mutex usb_bus_list_lock;
+ extern wait_queue_head_t usb_kill_urb_queue;
+ 
+-extern void usb_enable_root_hub_irq (struct usb_bus *bus);
++extern void usb_enable_root_hub_irq(struct usb_bus *bus);
+ 
+-extern int usb_find_interface_driver (struct usb_device *dev,
++extern int usb_find_interface_driver(struct usb_device *dev,
+ 	struct usb_interface *interface);
+ 
+ #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
+ 
+ #ifdef CONFIG_PM
+-extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
+-extern void usb_root_hub_lost_power (struct usb_device *rhdev);
++extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
++extern void usb_root_hub_lost_power(struct usb_device *rhdev);
+ extern int hcd_bus_suspend(struct usb_device *rhdev);
+ extern int hcd_bus_resume(struct usb_device *rhdev);
+ #else
+@@ -399,13 +403,13 @@ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
+  * these are expected to be called from the USB core/hub thread
+  * with the kernel lock held
+  */
+-extern void usbfs_update_special (void);
++extern void usbfs_update_special(void);
+ extern int usbfs_init(void);
+ extern void usbfs_cleanup(void);
+ 
+ #else /* CONFIG_USB_DEVICEFS */
+ 
+-static inline void usbfs_update_special (void) {}
++static inline void usbfs_update_special(void) {}
+ static inline int usbfs_init(void) { return 0; }
+ static inline void usbfs_cleanup(void) { }
+ 
+@@ -460,7 +464,7 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ /*-------------------------------------------------------------------------*/
+ 
+ /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
+-// bleech -- resurfaced in 2.4.11 or 2.4.12
++/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
+ #define bitmap 	DeviceRemovable
+ 
+ 
+@@ -468,8 +472,8 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ 
+ /* random stuff */
+ 
+-#define	RUN_CONTEXT (in_irq () ? "in_irq" \
+-		: (in_interrupt () ? "in_interrupt" : "can sleep"))
++#define	RUN_CONTEXT (in_irq() ? "in_irq" \
++		: (in_interrupt() ? "in_interrupt" : "can sleep"))
+ 
+ 
+ /* This rwsem is for use only by the hub driver and ehci-hcd.
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index b04d232..68fc521 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -37,6 +37,13 @@
+ #define	USB_PERSIST	0
+ #endif
+ 
++/* if we are in debug mode, always announce new devices */
++#ifdef DEBUG
++#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
++#define CONFIG_USB_ANNOUNCE_NEW_DEVICES
++#endif
++#endif
++
+ struct usb_hub {
+ 	struct device		*intfdev;	/* the "interface" device */
+ 	struct usb_device	*hdev;
+@@ -487,6 +494,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
+ 	schedule_work (&tt->kevent);
+ 	spin_unlock_irqrestore (&tt->lock, flags);
+ }
++EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
+ 
+ static void hub_power_on(struct usb_hub *hub)
+ {
+@@ -1027,8 +1035,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
+ 		if (udev->children[i])
+ 			recursively_mark_NOTATTACHED(udev->children[i]);
+ 	}
+-	if (udev->state == USB_STATE_SUSPENDED)
++	if (udev->state == USB_STATE_SUSPENDED) {
+ 		udev->discon_suspended = 1;
++		udev->active_duration -= jiffies;
++	}
+ 	udev->state = USB_STATE_NOTATTACHED;
+ }
+ 
+@@ -1077,6 +1087,12 @@ void usb_set_device_state(struct usb_device *udev,
+ 			else
+ 				device_init_wakeup(&udev->dev, 0);
+ 		}
++		if (udev->state == USB_STATE_SUSPENDED &&
++			new_state != USB_STATE_SUSPENDED)
++			udev->active_duration -= jiffies;
++		else if (new_state == USB_STATE_SUSPENDED &&
++				udev->state != USB_STATE_SUSPENDED)
++			udev->active_duration += jiffies;
+ 		udev->state = new_state;
+ 	} else
+ 		recursively_mark_NOTATTACHED(udev);
+@@ -1207,7 +1223,7 @@ void usb_disconnect(struct usb_device **pdev)
+ 	put_device(&udev->dev);
+ }
+ 
+-#ifdef DEBUG
++#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+ static void show_string(struct usb_device *udev, char *id, char *string)
+ {
+ 	if (!string)
+@@ -1215,12 +1231,24 @@ static void show_string(struct usb_device *udev, char *id, char *string)
+ 	dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
+ }
+ 
++static void announce_device(struct usb_device *udev)
++{
++	dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
++		le16_to_cpu(udev->descriptor.idVendor),
++		le16_to_cpu(udev->descriptor.idProduct));
++	dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, "
++		"SerialNumber=%d\n",
++		udev->descriptor.iManufacturer,
++		udev->descriptor.iProduct,
++		udev->descriptor.iSerialNumber);
++	show_string(udev, "Product", udev->product);
++	show_string(udev, "Manufacturer", udev->manufacturer);
++	show_string(udev, "SerialNumber", udev->serial);
++}
+ #else
+-static inline void show_string(struct usb_device *udev, char *id, char *string)
+-{}
++static inline void announce_device(struct usb_device *udev) { }
+ #endif
+ 
+-
+ #ifdef	CONFIG_USB_OTG
+ #include "otg_whitelist.h"
+ #endif
+@@ -1390,14 +1418,7 @@ int usb_new_device(struct usb_device *udev)
+ 	}
+ 
+ 	/* Tell the world! */
+-	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+-		"SerialNumber=%d\n",
+-		udev->descriptor.iManufacturer,
+-		udev->descriptor.iProduct,
+-		udev->descriptor.iSerialNumber);
+-	show_string(udev, "Product", udev->product);
+-	show_string(udev, "Manufacturer", udev->manufacturer);
+-	show_string(udev, "SerialNumber", udev->serial);
++	announce_device(udev);
+ 	return err;
+ 
+ fail:
+@@ -2482,6 +2503,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
+ {
+ 	struct usb_device *hdev = hub->hdev;
+ 	struct device *hub_dev = hub->intfdev;
++	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+ 	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+ 	int status, i;
+  
+@@ -2645,6 +2667,8 @@ loop:
+  
+ done:
+ 	hub_port_disable(hub, port1, 1);
++	if (hcd->driver->relinquish_port && !hub->hdev->parent)
++		hcd->driver->relinquish_port(hcd, port1);
+ }
+ 
+ static void hub_events(void)
+@@ -2946,7 +2970,7 @@ static int config_descriptors_changed(struct usb_device *udev)
+ 		if (len < le16_to_cpu(udev->config[index].desc.wTotalLength))
+ 			len = le16_to_cpu(udev->config[index].desc.wTotalLength);
+ 	}
+-	buf = kmalloc (len, GFP_KERNEL);
++	buf = kmalloc(len, GFP_NOIO);
+ 	if (buf == NULL) {
+ 		dev_err(&udev->dev, "no mem to re-read configs after reset\n");
+ 		/* assume the worst */
+@@ -3093,7 +3117,7 @@ re_enumerate:
+ 	hub_port_logical_disconnect(parent_hub, port1);
+ 	return -ENODEV;
+ }
+-EXPORT_SYMBOL(usb_reset_device);
++EXPORT_SYMBOL_GPL(usb_reset_device);
+ 
+ /**
+  * usb_reset_composite_device - warn interface drivers and perform a USB port reset
+@@ -3110,16 +3134,12 @@ EXPORT_SYMBOL(usb_reset_device);
+  * this from a driver probe() routine after downloading new firmware.
+  * For calls that might not occur during probe(), drivers should lock
+  * the device using usb_lock_device_for_reset().
+- *
+- * The interface locks are acquired during the pre_reset stage and released
+- * during the post_reset stage.  However if iface is not NULL and is
+- * currently being probed, we assume that the caller already owns its
+- * lock.
+  */
+ int usb_reset_composite_device(struct usb_device *udev,
+ 		struct usb_interface *iface)
+ {
+ 	int ret;
++	int i;
+ 	struct usb_host_config *config = udev->actconfig;
+ 
+ 	if (udev->state == USB_STATE_NOTATTACHED ||
+@@ -3136,16 +3156,11 @@ int usb_reset_composite_device(struct usb_device *udev,
+ 		iface = NULL;
+ 
+ 	if (config) {
+-		int i;
+-		struct usb_interface *cintf;
+-		struct usb_driver *drv;
+-
+ 		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+-			cintf = config->interface[i];
+-			if (cintf != iface)
+-				down(&cintf->dev.sem);
+-			if (device_is_registered(&cintf->dev) &&
+-					cintf->dev.driver) {
++			struct usb_interface *cintf = config->interface[i];
++			struct usb_driver *drv;
++
++			if (cintf->dev.driver) {
+ 				drv = to_usb_driver(cintf->dev.driver);
+ 				if (drv->pre_reset)
+ 					(drv->pre_reset)(cintf);
+@@ -3157,25 +3172,20 @@ int usb_reset_composite_device(struct usb_device *udev,
+ 	ret = usb_reset_device(udev);
+ 
+ 	if (config) {
+-		int i;
+-		struct usb_interface *cintf;
+-		struct usb_driver *drv;
+-
+ 		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
+-			cintf = config->interface[i];
+-			if (device_is_registered(&cintf->dev) &&
+-					cintf->dev.driver) {
++			struct usb_interface *cintf = config->interface[i];
++			struct usb_driver *drv;
++
++			if (cintf->dev.driver) {
+ 				drv = to_usb_driver(cintf->dev.driver);
+ 				if (drv->post_reset)
+ 					(drv->post_reset)(cintf);
+ 	/* FIXME: Unbind if post_reset returns an error or isn't defined */
+ 			}
+-			if (cintf != iface)
+-				up(&cintf->dev.sem);
+ 		}
+ 	}
+ 
+ 	usb_autosuspend_device(udev);
+ 	return ret;
+ }
+-EXPORT_SYMBOL(usb_reset_composite_device);
++EXPORT_SYMBOL_GPL(usb_reset_composite_device);
+diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
+index cf9559c..1551aed 100644
+--- a/drivers/usb/core/hub.h
++++ b/drivers/usb/core/hub.h
+@@ -55,16 +55,16 @@
+ #define USB_PORT_FEAT_TEST              21
+ #define USB_PORT_FEAT_INDICATOR         22
+ 
+-/* 
++/*
+  * Hub Status and Hub Change results
+  * See USB 2.0 spec Table 11-19 and Table 11-20
+  */
+ struct usb_port_status {
+ 	__le16 wPortStatus;
+-	__le16 wPortChange;	
++	__le16 wPortChange;
+ } __attribute__ ((packed));
+ 
+-/* 
++/*
+  * wPortStatus bit field
+  * See USB 2.0 spec Table 11-21
+  */
+@@ -81,7 +81,7 @@ struct usb_port_status {
+ #define USB_PORT_STAT_INDICATOR         0x1000
+ /* bits 13 to 15 are reserved */
+ 
+-/* 
++/*
+  * wPortChange bit field
+  * See USB 2.0 spec Table 11-22
+  * Bits 0 to 4 shown, bits 5 to 15 are reserved
+@@ -93,7 +93,7 @@ struct usb_port_status {
+ #define USB_PORT_STAT_C_RESET		0x0010
+ 
+ /*
+- * wHubCharacteristics (masks) 
++ * wHubCharacteristics (masks)
+  * See USB 2.0 spec Table 11-13, offset 3
+  */
+ #define HUB_CHAR_LPSM		0x0003 /* D1 .. D0 */
+@@ -119,8 +119,8 @@ struct usb_hub_status {
+ #define HUB_CHANGE_OVERCURRENT	0x0002
+ 
+ 
+-/* 
+- * Hub descriptor 
++/*
++ * Hub descriptor
+  * See USB 2.0 spec Table 11-13
+  */
+ 
+@@ -134,7 +134,7 @@ struct usb_hub_descriptor {
+ 	__le16 wHubCharacteristics;
+ 	__u8  bPwrOn2PwrGood;
+ 	__u8  bHubContrCurrent;
+-	    	/* add 1 bit for hub status change; round to bytes */
++		/* add 1 bit for hub status change; round to bytes */
+ 	__u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
+ 	__u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
+ } __attribute__ ((packed));
+@@ -190,6 +190,6 @@ struct usb_tt_clear {
+ 	u16			devinfo;
+ };
+ 
+-extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
++extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
+ 
+ #endif /* __LINUX_HUB_H */
+diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
+index cd4f111..83a373e 100644
+--- a/drivers/usb/core/inode.c
++++ b/drivers/usb/core/inode.c
+@@ -38,10 +38,15 @@
+ #include <linux/usbdevice_fs.h>
+ #include <linux/parser.h>
+ #include <linux/notifier.h>
++#include <linux/seq_file.h>
+ #include <asm/byteorder.h>
+ #include "usb.h"
+ #include "hcd.h"
+ 
++#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
++#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
++#define USBFS_DEFAULT_LISTMODE S_IRUGO
++
+ static struct super_operations usbfs_ops;
+ static const struct file_operations default_file_operations;
+ static struct vfsmount *usbfs_mount;
+@@ -57,9 +62,33 @@ static uid_t listuid;	/* = 0 */
+ static gid_t devgid;	/* = 0 */
+ static gid_t busgid;	/* = 0 */
+ static gid_t listgid;	/* = 0 */
+-static umode_t devmode = S_IWUSR | S_IRUGO;
+-static umode_t busmode = S_IXUGO | S_IRUGO;
+-static umode_t listmode = S_IRUGO;
++static umode_t devmode = USBFS_DEFAULT_DEVMODE;
++static umode_t busmode = USBFS_DEFAULT_BUSMODE;
++static umode_t listmode = USBFS_DEFAULT_LISTMODE;
++
++static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
++{
++	if (devuid != 0)
++		seq_printf(seq, ",devuid=%u", devuid);
++	if (devgid != 0)
++		seq_printf(seq, ",devgid=%u", devgid);
++	if (devmode != USBFS_DEFAULT_DEVMODE)
++		seq_printf(seq, ",devmode=%o", devmode);
++	if (busuid != 0)
++		seq_printf(seq, ",busuid=%u", busuid);
++	if (busgid != 0)
++		seq_printf(seq, ",busgid=%u", busgid);
++	if (busmode != USBFS_DEFAULT_BUSMODE)
++		seq_printf(seq, ",busmode=%o", busmode);
++	if (listuid != 0)
++		seq_printf(seq, ",listuid=%u", listuid);
++	if (listgid != 0)
++		seq_printf(seq, ",listgid=%u", listgid);
++	if (listmode != USBFS_DEFAULT_LISTMODE)
++		seq_printf(seq, ",listmode=%o", listmode);
++
++	return 0;
++}
+ 
+ enum {
+ 	Opt_devuid, Opt_devgid, Opt_devmode,
+@@ -93,9 +122,9 @@ static int parse_options(struct super_block *s, char *data)
+ 	devgid = 0;
+ 	busgid = 0;
+ 	listgid = 0;
+-	devmode = S_IWUSR | S_IRUGO;
+-	busmode = S_IXUGO | S_IRUGO;
+-	listmode = S_IRUGO;
++	devmode = USBFS_DEFAULT_DEVMODE;
++	busmode = USBFS_DEFAULT_BUSMODE;
++	listmode = USBFS_DEFAULT_LISTMODE;
+ 
+ 	while ((p = strsep(&data, ",")) != NULL) {
+ 		substring_t args[MAX_OPT_ARGS];
+@@ -418,6 +447,7 @@ static struct super_operations usbfs_ops = {
+ 	.statfs =	simple_statfs,
+ 	.drop_inode =	generic_delete_inode,
+ 	.remount_fs =	remount,
++	.show_options = usbfs_show_options,
+ };
+ 
+ static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
+diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
+index fcd40ec..fefb922 100644
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -39,7 +39,7 @@ static void usb_api_blocking_completion(struct urb *urb)
+  * own interruptible routines.
+  */
+ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+-{ 
++{
+ 	struct api_context ctx;
+ 	unsigned long expire;
+ 	int retval;
+@@ -74,9 +74,9 @@ out:
+ }
+ 
+ /*-------------------------------------------------------------------*/
+-// returns status (negative) or length (positive)
++/* returns status (negative) or length (positive) */
+ static int usb_internal_control_msg(struct usb_device *usb_dev,
+-				    unsigned int pipe, 
++				    unsigned int pipe,
+ 				    struct usb_ctrlrequest *cmd,
+ 				    void *data, int len, int timeout)
+ {
+@@ -87,7 +87,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
+ 	urb = usb_alloc_urb(0, GFP_NOIO);
+ 	if (!urb)
+ 		return -ENOMEM;
+-  
++
+ 	usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
+ 			     len, usb_api_blocking_completion, NULL);
+ 
+@@ -99,47 +99,51 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
+ }
+ 
+ /**
+- *	usb_control_msg - Builds a control urb, sends it off and waits for completion
+- *	@dev: pointer to the usb device to send the message to
+- *	@pipe: endpoint "pipe" to send the message to
+- *	@request: USB message request value
+- *	@requesttype: USB message request type value
+- *	@value: USB message value
+- *	@index: USB message index value
+- *	@data: pointer to the data to send
+- *	@size: length in bytes of the data to send
+- *	@timeout: time in msecs to wait for the message to complete before
+- *		timing out (if 0 the wait is forever)
+- *	Context: !in_interrupt ()
+- *
+- *	This function sends a simple control message to a specified endpoint
+- *	and waits for the message to complete, or timeout.
+- *	
+- *	If successful, it returns the number of bytes transferred, otherwise a negative error number.
+- *
+- *	Don't use this function from within an interrupt context, like a
+- *	bottom half handler.  If you need an asynchronous message, or need to send
+- *	a message from within interrupt context, use usb_submit_urb()
+- *      If a thread in your driver uses this call, make sure your disconnect()
+- *      method can wait for it to complete.  Since you don't have a handle on
+- *      the URB used, you can't cancel the request.
++ * usb_control_msg - Builds a control urb, sends it off and waits for completion
++ * @dev: pointer to the usb device to send the message to
++ * @pipe: endpoint "pipe" to send the message to
++ * @request: USB message request value
++ * @requesttype: USB message request type value
++ * @value: USB message value
++ * @index: USB message index value
++ * @data: pointer to the data to send
++ * @size: length in bytes of the data to send
++ * @timeout: time in msecs to wait for the message to complete before timing
++ *	out (if 0 the wait is forever)
++ *
++ * Context: !in_interrupt ()
++ *
++ * This function sends a simple control message to a specified endpoint and
++ * waits for the message to complete, or timeout.
++ *
++ * If successful, it returns the number of bytes transferred, otherwise a
++ * negative error number.
++ *
++ * Don't use this function from within an interrupt context, like a bottom half
++ * handler.  If you need an asynchronous message, or need to send a message
++ * from within interrupt context, use usb_submit_urb().
++ * If a thread in your driver uses this call, make sure your disconnect()
++ * method can wait for it to complete.  Since you don't have a handle on the
++ * URB used, you can't cancel the request.
+  */
+-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+-			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
++int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
++		    __u8 requesttype, __u16 value, __u16 index, void *data,
++		    __u16 size, int timeout)
+ {
+-	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
++	struct usb_ctrlrequest *dr;
+ 	int ret;
+-	
++
++	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+ 	if (!dr)
+ 		return -ENOMEM;
+ 
+-	dr->bRequestType= requesttype;
++	dr->bRequestType = requesttype;
+ 	dr->bRequest = request;
+ 	dr->wValue = cpu_to_le16p(&value);
+ 	dr->wIndex = cpu_to_le16p(&index);
+ 	dr->wLength = cpu_to_le16p(&size);
+ 
+-	//dbg("usb_control_msg");	
++	/* dbg("usb_control_msg"); */
+ 
+ 	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+ 
+@@ -147,7 +151,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
+ 
+ 	return ret;
+ }
+-
++EXPORT_SYMBOL_GPL(usb_control_msg);
+ 
+ /**
+  * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
+@@ -155,9 +159,11 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
+  * @pipe: endpoint "pipe" to send the message to
+  * @data: pointer to the data to send
+  * @len: length in bytes of the data to send
+- * @actual_length: pointer to a location to put the actual length transferred in bytes
++ * @actual_length: pointer to a location to put the actual length transferred
++ *	in bytes
+  * @timeout: time in msecs to wait for the message to complete before
+  *	timing out (if 0 the wait is forever)
++ *
+  * Context: !in_interrupt ()
+  *
+  * This function sends a simple interrupt message to a specified endpoint and
+@@ -181,38 +187,38 @@ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
+ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
+ 
+ /**
+- *	usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
+- *	@usb_dev: pointer to the usb device to send the message to
+- *	@pipe: endpoint "pipe" to send the message to
+- *	@data: pointer to the data to send
+- *	@len: length in bytes of the data to send
+- *	@actual_length: pointer to a location to put the actual length transferred in bytes
+- *	@timeout: time in msecs to wait for the message to complete before
+- *		timing out (if 0 the wait is forever)
+- *	Context: !in_interrupt ()
+- *
+- *	This function sends a simple bulk message to a specified endpoint
+- *	and waits for the message to complete, or timeout.
+- *	
+- *	If successful, it returns 0, otherwise a negative error number.
+- *	The number of actual bytes transferred will be stored in the 
+- *	actual_length paramater.
+- *
+- *	Don't use this function from within an interrupt context, like a
+- *	bottom half handler.  If you need an asynchronous message, or need to
+- *	send a message from within interrupt context, use usb_submit_urb()
+- *      If a thread in your driver uses this call, make sure your disconnect()
+- *      method can wait for it to complete.  Since you don't have a handle on
+- *      the URB used, you can't cancel the request.
+- *
+- *	Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
+- *	ioctl, users are forced to abuse this routine by using it to submit
+- *	URBs for interrupt endpoints.  We will take the liberty of creating
+- *	an interrupt URB (with the default interval) if the target is an
+- *	interrupt endpoint.
++ * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
++ * @usb_dev: pointer to the usb device to send the message to
++ * @pipe: endpoint "pipe" to send the message to
++ * @data: pointer to the data to send
++ * @len: length in bytes of the data to send
++ * @actual_length: pointer to a location to put the actual length transferred
++ *	in bytes
++ * @timeout: time in msecs to wait for the message to complete before
++ *	timing out (if 0 the wait is forever)
++ *
++ * Context: !in_interrupt ()
++ *
++ * This function sends a simple bulk message to a specified endpoint
++ * and waits for the message to complete, or timeout.
++ *
++ * If successful, it returns 0, otherwise a negative error number.  The number
++ * of actual bytes transferred will be stored in the actual_length paramater.
++ *
++ * Don't use this function from within an interrupt context, like a bottom half
++ * handler.  If you need an asynchronous message, or need to send a message
++ * from within interrupt context, use usb_submit_urb() If a thread in your
++ * driver uses this call, make sure your disconnect() method can wait for it to
++ * complete.  Since you don't have a handle on the URB used, you can't cancel
++ * the request.
++ *
++ * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl,
++ * users are forced to abuse this routine by using it to submit URBs for
++ * interrupt endpoints.  We will take the liberty of creating an interrupt URB
++ * (with the default interval) if the target is an interrupt endpoint.
+  */
+-int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
+-			void *data, int len, int *actual_length, int timeout)
++int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
++		 void *data, int len, int *actual_length, int timeout)
+ {
+ 	struct urb *urb;
+ 	struct usb_host_endpoint *ep;
+@@ -238,29 +244,30 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
+ 
+ 	return usb_start_wait_urb(urb, timeout, actual_length);
+ }
++EXPORT_SYMBOL_GPL(usb_bulk_msg);
+ 
+ /*-------------------------------------------------------------------*/
+ 
+-static void sg_clean (struct usb_sg_request *io)
++static void sg_clean(struct usb_sg_request *io)
+ {
+ 	if (io->urbs) {
+ 		while (io->entries--)
+-			usb_free_urb (io->urbs [io->entries]);
+-		kfree (io->urbs);
++			usb_free_urb(io->urbs [io->entries]);
++		kfree(io->urbs);
+ 		io->urbs = NULL;
+ 	}
+ 	if (io->dev->dev.dma_mask != NULL)
+-		usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+-				io->sg, io->nents);
++		usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
++				    io->sg, io->nents);
+ 	io->dev = NULL;
+ }
+ 
+-static void sg_complete (struct urb *urb)
++static void sg_complete(struct urb *urb)
+ {
+-	struct usb_sg_request	*io = urb->context;
++	struct usb_sg_request *io = urb->context;
+ 	int status = urb->status;
+ 
+-	spin_lock (&io->lock);
++	spin_lock(&io->lock);
+ 
+ 	/* In 2.5 we require hcds' endpoint queues not to progress after fault
+ 	 * reports, until the completion callback (this!) returns.  That lets
+@@ -276,13 +283,13 @@ static void sg_complete (struct urb *urb)
+ 			&& (io->status != -ECONNRESET
+ 				|| status != -ECONNRESET)
+ 			&& urb->actual_length) {
+-		dev_err (io->dev->bus->controller,
++		dev_err(io->dev->bus->controller,
+ 			"dev %s ep%d%s scatterlist error %d/%d\n",
+ 			io->dev->devpath,
+ 			usb_endpoint_num(&urb->ep->desc),
+ 			usb_urb_dir_in(urb) ? "in" : "out",
+ 			status, io->status);
+-		// BUG ();
++		/* BUG (); */
+ 	}
+ 
+ 	if (io->status == 0 && status && status != -ECONNRESET) {
+@@ -294,22 +301,22 @@ static void sg_complete (struct urb *urb)
+ 		 * unlink pending urbs so they won't rx/tx bad data.
+ 		 * careful: unlink can sometimes be synchronous...
+ 		 */
+-		spin_unlock (&io->lock);
++		spin_unlock(&io->lock);
+ 		for (i = 0, found = 0; i < io->entries; i++) {
+ 			if (!io->urbs [i] || !io->urbs [i]->dev)
+ 				continue;
+ 			if (found) {
+-				retval = usb_unlink_urb (io->urbs [i]);
++				retval = usb_unlink_urb(io->urbs [i]);
+ 				if (retval != -EINPROGRESS &&
+ 				    retval != -ENODEV &&
+ 				    retval != -EBUSY)
+-					dev_err (&io->dev->dev,
++					dev_err(&io->dev->dev,
+ 						"%s, unlink --> %d\n",
+ 						__FUNCTION__, retval);
+ 			} else if (urb == io->urbs [i])
+ 				found = 1;
+ 		}
+-		spin_lock (&io->lock);
++		spin_lock(&io->lock);
+ 	}
+ 	urb->dev = NULL;
+ 
+@@ -317,9 +324,9 @@ static void sg_complete (struct urb *urb)
+ 	io->bytes += urb->actual_length;
+ 	io->count--;
+ 	if (!io->count)
+-		complete (&io->complete);
++		complete(&io->complete);
+ 
+-	spin_unlock (&io->lock);
++	spin_unlock(&io->lock);
+ }
+ 
+ 
+@@ -348,28 +355,21 @@ static void sg_complete (struct urb *urb)
+  * The request may be canceled with usb_sg_cancel(), either before or after
+  * usb_sg_wait() is called.
+  */
+-int usb_sg_init (
+-	struct usb_sg_request	*io,
+-	struct usb_device	*dev,
+-	unsigned		pipe, 
+-	unsigned		period,
+-	struct scatterlist	*sg,
+-	int			nents,
+-	size_t			length,
+-	gfp_t			mem_flags
+-)
++int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
++		unsigned pipe, unsigned	period, struct scatterlist *sg,
++		int nents, size_t length, gfp_t mem_flags)
+ {
+-	int			i;
+-	int			urb_flags;
+-	int			dma;
++	int i;
++	int urb_flags;
++	int dma;
+ 
+ 	if (!io || !dev || !sg
+-			|| usb_pipecontrol (pipe)
+-			|| usb_pipeisoc (pipe)
++			|| usb_pipecontrol(pipe)
++			|| usb_pipeisoc(pipe)
+ 			|| nents <= 0)
+ 		return -EINVAL;
+ 
+-	spin_lock_init (&io->lock);
++	spin_lock_init(&io->lock);
+ 	io->dev = dev;
+ 	io->pipe = pipe;
+ 	io->sg = sg;
+@@ -381,7 +381,7 @@ int usb_sg_init (
+ 	dma = (dev->dev.dma_mask != NULL);
+ 	if (dma)
+ 		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+-				sg, nents);
++						sg, nents);
+ 	else
+ 		io->entries = nents;
+ 
+@@ -390,30 +390,30 @@ int usb_sg_init (
+ 		return io->entries;
+ 
+ 	io->count = io->entries;
+-	io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
++	io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
+ 	if (!io->urbs)
+ 		goto nomem;
+ 
+ 	urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
+-	if (usb_pipein (pipe))
++	if (usb_pipein(pipe))
+ 		urb_flags |= URB_SHORT_NOT_OK;
+ 
+ 	for (i = 0; i < io->entries; i++) {
+-		unsigned		len;
++		unsigned len;
+ 
+-		io->urbs [i] = usb_alloc_urb (0, mem_flags);
+-		if (!io->urbs [i]) {
++		io->urbs[i] = usb_alloc_urb(0, mem_flags);
++		if (!io->urbs[i]) {
+ 			io->entries = i;
+ 			goto nomem;
+ 		}
+ 
+-		io->urbs [i]->dev = NULL;
+-		io->urbs [i]->pipe = pipe;
+-		io->urbs [i]->interval = period;
+-		io->urbs [i]->transfer_flags = urb_flags;
++		io->urbs[i]->dev = NULL;
++		io->urbs[i]->pipe = pipe;
++		io->urbs[i]->interval = period;
++		io->urbs[i]->transfer_flags = urb_flags;
+ 
+-		io->urbs [i]->complete = sg_complete;
+-		io->urbs [i]->context = io;
++		io->urbs[i]->complete = sg_complete;
++		io->urbs[i]->context = io;
+ 
+ 		/*
+ 		 * Some systems need to revert to PIO when DMA is temporarily
+@@ -432,8 +432,8 @@ int usb_sg_init (
+ 		 * to prevent stale pointers and to help spot bugs.
+ 		 */
+ 		if (dma) {
+-			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
+-			len = sg_dma_len (sg + i);
++			io->urbs[i]->transfer_dma = sg_dma_address(sg + i);
++			len = sg_dma_len(sg + i);
+ #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
+ 			io->urbs[i]->transfer_buffer = NULL;
+ #else
+@@ -441,31 +441,31 @@ int usb_sg_init (
+ #endif
+ 		} else {
+ 			/* hc may use _only_ transfer_buffer */
+-			io->urbs [i]->transfer_buffer = sg_virt(&sg[i]);
+-			len = sg [i].length;
++			io->urbs[i]->transfer_buffer = sg_virt(&sg[i]);
++			len = sg[i].length;
+ 		}
+ 
+ 		if (length) {
+-			len = min_t (unsigned, len, length);
++			len = min_t(unsigned, len, length);
+ 			length -= len;
+ 			if (length == 0)
+ 				io->entries = i + 1;
+ 		}
+-		io->urbs [i]->transfer_buffer_length = len;
++		io->urbs[i]->transfer_buffer_length = len;
+ 	}
+-	io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
++	io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+ 
+ 	/* transaction state */
+ 	io->status = 0;
+ 	io->bytes = 0;
+-	init_completion (&io->complete);
++	init_completion(&io->complete);
+ 	return 0;
+ 
+ nomem:
+-	sg_clean (io);
++	sg_clean(io);
+ 	return -ENOMEM;
+ }
+-
++EXPORT_SYMBOL_GPL(usb_sg_init);
+ 
+ /**
+  * usb_sg_wait - synchronously execute scatter/gather request
+@@ -506,31 +506,32 @@ nomem:
+  * speed interrupt endpoints, which allow at most one packet per millisecond,
+  * of at most 8 or 64 bytes (respectively).
+  */
+-void usb_sg_wait (struct usb_sg_request *io)
++void usb_sg_wait(struct usb_sg_request *io)
+ {
+-	int		i, entries = io->entries;
++	int i;
++	int entries = io->entries;
+ 
+ 	/* queue the urbs.  */
+-	spin_lock_irq (&io->lock);
++	spin_lock_irq(&io->lock);
+ 	i = 0;
+ 	while (i < entries && !io->status) {
+-		int	retval;
++		int retval;
+ 
+-		io->urbs [i]->dev = io->dev;
+-		retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC);
++		io->urbs[i]->dev = io->dev;
++		retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
+ 
+ 		/* after we submit, let completions or cancelations fire;
+ 		 * we handshake using io->status.
+ 		 */
+-		spin_unlock_irq (&io->lock);
++		spin_unlock_irq(&io->lock);
+ 		switch (retval) {
+ 			/* maybe we retrying will recover */
+-		case -ENXIO:	// hc didn't queue this one
++		case -ENXIO:	/* hc didn't queue this one */
+ 		case -EAGAIN:
+ 		case -ENOMEM:
+ 			io->urbs[i]->dev = NULL;
+ 			retval = 0;
+-			yield ();
++			yield();
+ 			break;
+ 
+ 			/* no error? continue immediately.
+@@ -541,34 +542,35 @@ void usb_sg_wait (struct usb_sg_request *io)
+ 			 */
+ 		case 0:
+ 			++i;
+-			cpu_relax ();
++			cpu_relax();
+ 			break;
+ 
+ 			/* fail any uncompleted urbs */
+ 		default:
+-			io->urbs [i]->dev = NULL;
+-			io->urbs [i]->status = retval;
+-			dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
++			io->urbs[i]->dev = NULL;
++			io->urbs[i]->status = retval;
++			dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
+ 				__FUNCTION__, retval);
+-			usb_sg_cancel (io);
++			usb_sg_cancel(io);
+ 		}
+-		spin_lock_irq (&io->lock);
++		spin_lock_irq(&io->lock);
+ 		if (retval && (io->status == 0 || io->status == -ECONNRESET))
+ 			io->status = retval;
+ 	}
+ 	io->count -= entries - i;
+ 	if (io->count == 0)
+-		complete (&io->complete);
+-	spin_unlock_irq (&io->lock);
++		complete(&io->complete);
++	spin_unlock_irq(&io->lock);
+ 
+ 	/* OK, yes, this could be packaged as non-blocking.
+ 	 * So could the submit loop above ... but it's easier to
+ 	 * solve neither problem than to solve both!
+ 	 */
+-	wait_for_completion (&io->complete);
++	wait_for_completion(&io->complete);
+ 
+-	sg_clean (io);
++	sg_clean(io);
+ }
++EXPORT_SYMBOL_GPL(usb_sg_wait);
+ 
+ /**
+  * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
+@@ -578,32 +580,33 @@ void usb_sg_wait (struct usb_sg_request *io)
+  * It can also prevents one initialized by usb_sg_init() from starting,
+  * so that call just frees resources allocated to the request.
+  */
+-void usb_sg_cancel (struct usb_sg_request *io)
++void usb_sg_cancel(struct usb_sg_request *io)
+ {
+-	unsigned long	flags;
++	unsigned long flags;
+ 
+-	spin_lock_irqsave (&io->lock, flags);
++	spin_lock_irqsave(&io->lock, flags);
+ 
+ 	/* shut everything down, if it didn't already */
+ 	if (!io->status) {
+-		int	i;
++		int i;
+ 
+ 		io->status = -ECONNRESET;
+-		spin_unlock (&io->lock);
++		spin_unlock(&io->lock);
+ 		for (i = 0; i < io->entries; i++) {
+-			int	retval;
++			int retval;
+ 
+ 			if (!io->urbs [i]->dev)
+ 				continue;
+-			retval = usb_unlink_urb (io->urbs [i]);
++			retval = usb_unlink_urb(io->urbs [i]);
+ 			if (retval != -EINPROGRESS && retval != -EBUSY)
+-				dev_warn (&io->dev->dev, "%s, unlink --> %d\n",
++				dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
+ 					__FUNCTION__, retval);
+ 		}
+-		spin_lock (&io->lock);
++		spin_lock(&io->lock);
+ 	}
+-	spin_unlock_irqrestore (&io->lock, flags);
++	spin_unlock_irqrestore(&io->lock, flags);
+ }
++EXPORT_SYMBOL_GPL(usb_sg_cancel);
+ 
+ /*-------------------------------------------------------------------*/
+ 
+@@ -629,12 +632,13 @@ void usb_sg_cancel (struct usb_sg_request *io)
+  * Returns the number of bytes received on success, or else the status code
+  * returned by the underlying usb_control_msg() call.
+  */
+-int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
++int usb_get_descriptor(struct usb_device *dev, unsigned char type,
++		       unsigned char index, void *buf, int size)
+ {
+ 	int i;
+ 	int result;
+-	
+-	memset(buf,0,size);	// Make sure we parse really received data
++
++	memset(buf, 0, size);	/* Make sure we parse really received data */
+ 
+ 	for (i = 0; i < 3; ++i) {
+ 		/* retry on length 0 or error; some devices are flakey */
+@@ -652,6 +656,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
+ 	}
+ 	return result;
+ }
++EXPORT_SYMBOL_GPL(usb_get_descriptor);
+ 
+ /**
+  * usb_get_string - gets a string descriptor
+@@ -708,7 +713,7 @@ static void usb_try_string_workarounds(unsigned char *buf, int *length)
+ }
+ 
+ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+-		unsigned int index, unsigned char *buf)
++			  unsigned int index, unsigned char *buf)
+ {
+ 	int rc;
+ 
+@@ -751,7 +756,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+  * @buf: where to put the string
+  * @size: how big is "buf"?
+  * Context: !in_interrupt ()
+- * 
++ *
+  * This converts the UTF-16LE encoded strings returned by devices, from
+  * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
+  * that are more usable in most kernel contexts.  Note that all characters
+@@ -787,23 +792,23 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+ 	if (!dev->have_langid) {
+ 		err = usb_string_sub(dev, 0, 0, tbuf);
+ 		if (err < 0) {
+-			dev_err (&dev->dev,
++			dev_err(&dev->dev,
+ 				"string descriptor 0 read error: %d\n",
+ 				err);
+ 			goto errout;
+ 		} else if (err < 4) {
+-			dev_err (&dev->dev, "string descriptor 0 too short\n");
++			dev_err(&dev->dev, "string descriptor 0 too short\n");
+ 			err = -EINVAL;
+ 			goto errout;
+ 		} else {
+ 			dev->have_langid = 1;
+-			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+-				/* always use the first langid listed */
+-			dev_dbg (&dev->dev, "default language 0x%04x\n",
++			dev->string_langid = tbuf[2] | (tbuf[3] << 8);
++			/* always use the first langid listed */
++			dev_dbg(&dev->dev, "default language 0x%04x\n",
+ 				dev->string_langid);
+ 		}
+ 	}
+-	
++
+ 	err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+ 	if (err < 0)
+ 		goto errout;
+@@ -821,12 +826,15 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+ 	err = idx;
+ 
+ 	if (tbuf[1] != USB_DT_STRING)
+-		dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf);
++		dev_dbg(&dev->dev,
++			"wrong descriptor type %02x for string %d (\"%s\")\n",
++			tbuf[1], index, buf);
+ 
+  errout:
+ 	kfree(tbuf);
+ 	return err;
+ }
++EXPORT_SYMBOL_GPL(usb_string);
+ 
+ /**
+  * usb_cache_string - read a string descriptor and cache it for later use
+@@ -842,9 +850,15 @@ char *usb_cache_string(struct usb_device *udev, int index)
+ 	char *smallbuf = NULL;
+ 	int len;
+ 
+-	if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
+-		if ((len = usb_string(udev, index, buf, 256)) > 0) {
+-			if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
++	if (index <= 0)
++		return NULL;
++
++	buf = kmalloc(256, GFP_KERNEL);
++	if (buf) {
++		len = usb_string(udev, index, buf, 256);
++		if (len > 0) {
++			smallbuf = kmalloc(++len, GFP_KERNEL);
++			if (!smallbuf)
+ 				return buf;
+ 			memcpy(smallbuf, buf, len);
+ 		}
+@@ -883,7 +897,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
+ 		return -ENOMEM;
+ 
+ 	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
+-	if (ret >= 0) 
++	if (ret >= 0)
+ 		memcpy(&dev->descriptor, desc, size);
+ 	kfree(desc);
+ 	return ret;
+@@ -927,6 +941,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data)
+ 	kfree(status);
+ 	return ret;
+ }
++EXPORT_SYMBOL_GPL(usb_get_status);
+ 
+ /**
+  * usb_clear_halt - tells device to clear endpoint halt/stall condition
+@@ -955,8 +970,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
+ {
+ 	int result;
+ 	int endp = usb_pipeendpoint(pipe);
+-	
+-	if (usb_pipein (pipe))
++
++	if (usb_pipein(pipe))
+ 		endp |= USB_DIR_IN;
+ 
+ 	/* we don't care if it wasn't halted first. in fact some devices
+@@ -985,6 +1000,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(usb_clear_halt);
+ 
+ /**
+  * usb_disable_endpoint -- Disable an endpoint by address
+@@ -1038,7 +1054,7 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
+ 	}
+ }
+ 
+-/*
++/**
+  * usb_disable_device - Disable all the endpoints for a USB device
+  * @dev: the device whose endpoints are being disabled
+  * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
+@@ -1053,7 +1069,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
+ 	int i;
+ 
+ 	dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__,
+-			skip_ep0 ? "non-ep0" : "all");
++		skip_ep0 ? "non-ep0" : "all");
+ 	for (i = skip_ep0; i < 16; ++i) {
+ 		usb_disable_endpoint(dev, i);
+ 		usb_disable_endpoint(dev, i + USB_DIR_IN);
+@@ -1071,17 +1087,17 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
+ 			interface = dev->actconfig->interface[i];
+ 			if (!device_is_registered(&interface->dev))
+ 				continue;
+-			dev_dbg (&dev->dev, "unregistering interface %s\n",
++			dev_dbg(&dev->dev, "unregistering interface %s\n",
+ 				interface->dev.bus_id);
+ 			usb_remove_sysfs_intf_files(interface);
+-			device_del (&interface->dev);
++			device_del(&interface->dev);
+ 		}
+ 
+ 		/* Now that the interfaces are unbound, nobody should
+ 		 * try to access them.
+ 		 */
+ 		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+-			put_device (&dev->actconfig->interface[i]->dev);
++			put_device(&dev->actconfig->interface[i]->dev);
+ 			dev->actconfig->interface[i] = NULL;
+ 		}
+ 		dev->actconfig = NULL;
+@@ -1090,8 +1106,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
+ 	}
+ }
+ 
+-
+-/*
++/**
+  * usb_enable_endpoint - Enable an endpoint for USB communications
+  * @dev: the device whose interface is being enabled
+  * @ep: the endpoint
+@@ -1116,7 +1131,7 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+ 	ep->enabled = 1;
+ }
+ 
+-/*
++/**
+  * usb_enable_interface - Enable all the endpoints for an interface
+  * @dev: the device whose interface is being enabled
+  * @intf: pointer to the interface descriptor
+@@ -1172,6 +1187,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+ 	struct usb_host_interface *alt;
+ 	int ret;
+ 	int manual = 0;
++	unsigned int epaddr;
++	unsigned int pipe;
+ 
+ 	if (dev->state == USB_STATE_SUSPENDED)
+ 		return -EHOSTUNREACH;
+@@ -1226,11 +1243,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+ 		int i;
+ 
+ 		for (i = 0; i < alt->desc.bNumEndpoints; i++) {
+-			unsigned int epaddr =
+-				alt->endpoint[i].desc.bEndpointAddress;
+-			unsigned int pipe =
+-	__create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr)
+-	| (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN);
++			epaddr = alt->endpoint[i].desc.bEndpointAddress;
++			pipe = __create_pipe(dev,
++					USB_ENDPOINT_NUMBER_MASK & epaddr) |
++					(usb_endpoint_out(epaddr) ?
++					USB_DIR_OUT : USB_DIR_IN);
+ 
+ 			usb_clear_halt(dev, pipe);
+ 		}
+@@ -1253,6 +1270,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(usb_set_interface);
+ 
+ /**
+  * usb_reset_configuration - lightweight device reset
+@@ -1328,6 +1346,7 @@ int usb_reset_configuration(struct usb_device *dev)
+ 	}
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(usb_reset_configuration);
+ 
+ static void usb_release_interface(struct device *dev)
+ {
+@@ -1357,7 +1376,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
+ 		return -ENOMEM;
+ 
+ 	if (add_uevent_var(env,
+-		   "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
++		   "MODALIAS=usb:"
++		   "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ 		   le16_to_cpu(usb_dev->descriptor.idVendor),
+ 		   le16_to_cpu(usb_dev->descriptor.idProduct),
+ 		   le16_to_cpu(usb_dev->descriptor.bcdDevice),
+@@ -1387,8 +1407,8 @@ struct device_type usb_if_device_type = {
+ };
+ 
+ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
+-						       struct usb_host_config *config,
+-						       u8 inum)
++						struct usb_host_config *config,
++						u8 inum)
+ {
+ 	struct usb_interface_assoc_descriptor *retval = NULL;
+ 	struct usb_interface_assoc_descriptor *intf_assoc;
+@@ -1415,7 +1435,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
+ 	return retval;
+ }
+ 
+-
+ /*
+  * usb_set_configuration - Makes a particular device setting be current
+  * @dev: the device whose configuration is being updated
+@@ -1533,12 +1552,12 @@ free_interfaces:
+ 	 * getting rid of old interfaces means unbinding their drivers.
+ 	 */
+ 	if (dev->state != USB_STATE_ADDRESS)
+-		usb_disable_device (dev, 1);	// Skip ep0
+-
+-	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+-			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+-			NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
++		usb_disable_device(dev, 1);	/* Skip ep0 */
+ 
++	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
++			      USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
++			      NULL, 0, USB_CTRL_SET_TIMEOUT);
++	if (ret < 0) {
+ 		/* All the old state is gone, so what else can we do?
+ 		 * The device is probably useless now anyway.
+ 		 */
+@@ -1585,11 +1604,11 @@ free_interfaces:
+ 		intf->dev.bus = &usb_bus_type;
+ 		intf->dev.type = &usb_if_device_type;
+ 		intf->dev.dma_mask = dev->dev.dma_mask;
+-		device_initialize (&intf->dev);
++		device_initialize(&intf->dev);
+ 		mark_quiesced(intf);
+-		sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
+-			 dev->bus->busnum, dev->devpath,
+-			 configuration, alt->desc.bInterfaceNumber);
++		sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",
++			dev->bus->busnum, dev->devpath,
++			configuration, alt->desc.bInterfaceNumber);
+ 	}
+ 	kfree(new_interfaces);
+ 
+@@ -1605,11 +1624,11 @@ free_interfaces:
+ 	for (i = 0; i < nintf; ++i) {
+ 		struct usb_interface *intf = cp->interface[i];
+ 
+-		dev_dbg (&dev->dev,
++		dev_dbg(&dev->dev,
+ 			"adding %s (config #%d, interface %d)\n",
+ 			intf->dev.bus_id, configuration,
+ 			intf->cur_altsetting->desc.bInterfaceNumber);
+-		ret = device_add (&intf->dev);
++		ret = device_add(&intf->dev);
+ 		if (ret != 0) {
+ 			dev_err(&dev->dev, "device_add(%s) --> %d\n",
+ 				intf->dev.bus_id, ret);
+@@ -1677,22 +1696,3 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
+-
+-// synchronous request completion model
+-EXPORT_SYMBOL(usb_control_msg);
+-EXPORT_SYMBOL(usb_bulk_msg);
+-
+-EXPORT_SYMBOL(usb_sg_init);
+-EXPORT_SYMBOL(usb_sg_cancel);
+-EXPORT_SYMBOL(usb_sg_wait);
+-
+-// synchronous control message convenience routines
+-EXPORT_SYMBOL(usb_get_descriptor);
+-EXPORT_SYMBOL(usb_get_status);
+-EXPORT_SYMBOL(usb_string);
+-
+-// synchronous calls that also maintain usbcore state
+-EXPORT_SYMBOL(usb_clear_halt);
+-EXPORT_SYMBOL(usb_reset_configuration);
+-EXPORT_SYMBOL(usb_set_interface);
+-
+diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
+index 6b36897..7542dce 100644
+--- a/drivers/usb/core/notify.c
++++ b/drivers/usb/core/notify.c
+@@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(usb_register_notify);
+  * usb_unregister_notify - unregister a notifier callback
+  * @nb: pointer to the notifier block for the callback events.
+  *
+- * usb_register_notifier() must have been previously called for this function
++ * usb_register_notify() must have been previously called for this function
+  * to work properly.
+  */
+ void usb_unregister_notify(struct notifier_block *nb)
+diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
+index 7f31a49..e8cdce5 100644
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -14,7 +14,7 @@
+  * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
+  *
+  * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
+- */ 
++ */
+ 
+ static struct usb_device_id whitelist_table [] = {
+ 
+@@ -55,7 +55,7 @@ static int is_targeted(struct usb_device *dev)
+ 		return 1;
+ 
+ 	/* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
+-	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && 
++	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ 	     le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
+ 		return 0;
+ 
+@@ -86,7 +86,7 @@ static int is_targeted(struct usb_device *dev)
+ 			continue;
+ 
+ 		if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+-		    (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
++		    (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
+ 			continue;
+ 
+ 		if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
+index 32bd130..a37ccbd 100644
+--- a/drivers/usb/core/sysfs.c
++++ b/drivers/usb/core/sysfs.c
+@@ -72,7 +72,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
+ 	return (value < 0) ? value : count;
+ }
+ 
+-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, 
++static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+ 		show_bConfigurationValue, set_bConfigurationValue);
+ 
+ /* String fields */
+@@ -249,6 +249,41 @@ static void remove_persist_attributes(struct device *dev)
+ #ifdef	CONFIG_USB_SUSPEND
+ 
+ static ssize_t
++show_connected_duration(struct device *dev, struct device_attribute *attr,
++		char *buf)
++{
++	struct usb_device *udev = to_usb_device(dev);
++
++	return sprintf(buf, "%u\n",
++			jiffies_to_msecs(jiffies - udev->connect_time));
++}
++
++static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
++
++/*
++ * If the device is resumed, the last time the device was suspended has
++ * been pre-subtracted from active_duration.  We add the current time to
++ * get the duration that the device was actually active.
++ *
++ * If the device is suspended, the active_duration is up-to-date.
++ */
++static ssize_t
++show_active_duration(struct device *dev, struct device_attribute *attr,
++		char *buf)
++{
++	struct usb_device *udev = to_usb_device(dev);
++	int duration;
++
++	if (udev->state != USB_STATE_SUSPENDED)
++		duration = jiffies_to_msecs(jiffies + udev->active_duration);
++	else
++		duration = jiffies_to_msecs(udev->active_duration);
++	return sprintf(buf, "%u\n", duration);
++}
++
++static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
++
++static ssize_t
+ show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ 	struct usb_device *udev = to_usb_device(dev);
+@@ -365,6 +400,14 @@ static int add_power_attributes(struct device *dev)
+ 			rc = sysfs_add_file_to_group(&dev->kobj,
+ 					&dev_attr_level.attr,
+ 					power_group);
++		if (rc == 0)
++			rc = sysfs_add_file_to_group(&dev->kobj,
++					&dev_attr_connected_duration.attr,
++					power_group);
++		if (rc == 0)
++			rc = sysfs_add_file_to_group(&dev->kobj,
++					&dev_attr_active_duration.attr,
++					power_group);
+ 	}
+ 	return rc;
+ }
+@@ -372,6 +415,12 @@ static int add_power_attributes(struct device *dev)
+ static void remove_power_attributes(struct device *dev)
+ {
+ 	sysfs_remove_file_from_group(&dev->kobj,
++			&dev_attr_active_duration.attr,
++			power_group);
++	sysfs_remove_file_from_group(&dev->kobj,
++			&dev_attr_connected_duration.attr,
++			power_group);
++	sysfs_remove_file_from_group(&dev->kobj,
+ 			&dev_attr_level.attr,
+ 			power_group);
+ 	sysfs_remove_file_from_group(&dev->kobj,
+@@ -601,21 +650,21 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
+ /* Interface Accociation Descriptor fields */
+ #define usb_intf_assoc_attr(field, format_string)			\
+ static ssize_t								\
+-show_iad_##field (struct device *dev, struct device_attribute *attr,	\
++show_iad_##field(struct device *dev, struct device_attribute *attr,	\
+ 		char *buf)						\
+ {									\
+-	struct usb_interface *intf = to_usb_interface (dev);		\
++	struct usb_interface *intf = to_usb_interface(dev);		\
+ 									\
+-	return sprintf (buf, format_string,				\
+-			intf->intf_assoc->field); 		\
++	return sprintf(buf, format_string,				\
++			intf->intf_assoc->field); 			\
+ }									\
+ static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+ 
+-usb_intf_assoc_attr (bFirstInterface, "%02x\n")
+-usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
+-usb_intf_assoc_attr (bFunctionClass, "%02x\n")
+-usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
+-usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
++usb_intf_assoc_attr(bFirstInterface, "%02x\n")
++usb_intf_assoc_attr(bInterfaceCount, "%02d\n")
++usb_intf_assoc_attr(bFunctionClass, "%02x\n")
++usb_intf_assoc_attr(bFunctionSubClass, "%02x\n")
++usb_intf_assoc_attr(bFunctionProtocol, "%02x\n")
+ 
+ /* Interface fields */
+ #define usb_intf_attr(field, format_string)				\
+diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
+index d05ead2..9d7e632 100644
+--- a/drivers/usb/core/urb.c
++++ b/drivers/usb/core/urb.c
+@@ -42,6 +42,7 @@ void usb_init_urb(struct urb *urb)
+ 		INIT_LIST_HEAD(&urb->anchor_list);
+ 	}
+ }
++EXPORT_SYMBOL_GPL(usb_init_urb);
+ 
+ /**
+  * usb_alloc_urb - creates a new urb for a USB driver to use
+@@ -73,6 +74,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
+ 	usb_init_urb(urb);
+ 	return urb;
+ }
++EXPORT_SYMBOL_GPL(usb_alloc_urb);
+ 
+ /**
+  * usb_free_urb - frees the memory used by a urb when all users of it are finished
+@@ -89,6 +91,7 @@ void usb_free_urb(struct urb *urb)
+ 	if (urb)
+ 		kref_put(&urb->kref, urb_destroy);
+ }
++EXPORT_SYMBOL_GPL(usb_free_urb);
+ 
+ /**
+  * usb_get_urb - increments the reference count of the urb
+@@ -100,12 +103,13 @@ void usb_free_urb(struct urb *urb)
+  *
+  * A pointer to the urb with the incremented reference counter is returned.
+  */
+-struct urb * usb_get_urb(struct urb *urb)
++struct urb *usb_get_urb(struct urb *urb)
+ {
+ 	if (urb)
+ 		kref_get(&urb->kref);
+ 	return urb;
+ }
++EXPORT_SYMBOL_GPL(usb_get_urb);
+ 
+ /**
+  * usb_anchor_urb - anchors an URB while it is processed
+@@ -172,7 +176,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
+  * describing that request to the USB subsystem.  Request completion will
+  * be indicated later, asynchronously, by calling the completion handler.
+  * The three types of completion are success, error, and unlink
+- * (a software-induced fault, also called "request cancellation").  
++ * (a software-induced fault, also called "request cancellation").
+  *
+  * URBs may be submitted in interrupt context.
+  *
+@@ -255,7 +259,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
+  *       semaphores), or
+  *   (c) current->state != TASK_RUNNING, this is the case only after
+  *       you've changed it.
+- * 
++ *
+  * GFP_NOIO is used in the block io path and error handling of storage
+  * devices.
+  *
+@@ -284,7 +288,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ 
+ 	if (!urb || urb->hcpriv || !urb->complete)
+ 		return -EINVAL;
+-	if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
++	dev = urb->dev;
++	if ((!dev) || (dev->state < USB_STATE_DEFAULT))
+ 		return -ENODEV;
+ 
+ 	/* For now, get the endpoint from the pipe.  Eventually drivers
+@@ -347,11 +352,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ 			max *= mult;
+ 		}
+ 
+-		if (urb->number_of_packets <= 0)		    
++		if (urb->number_of_packets <= 0)
+ 			return -EINVAL;
+ 		for (n = 0; n < urb->number_of_packets; n++) {
+ 			len = urb->iso_frame_desc[n].length;
+-			if (len < 0 || len > max) 
++			if (len < 0 || len > max)
+ 				return -EMSGSIZE;
+ 			urb->iso_frame_desc[n].status = -EXDEV;
+ 			urb->iso_frame_desc[n].actual_length = 0;
+@@ -416,7 +421,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ 		/* too big? */
+ 		switch (dev->speed) {
+ 		case USB_SPEED_HIGH:	/* units are microframes */
+-			// NOTE usb handles 2^15
++			/* NOTE usb handles 2^15 */
+ 			if (urb->interval > (1024 * 8))
+ 				urb->interval = 1024 * 8;
+ 			max = 1024 * 8;
+@@ -426,12 +431,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ 			if (xfertype == USB_ENDPOINT_XFER_INT) {
+ 				if (urb->interval > 255)
+ 					return -EINVAL;
+-				// NOTE ohci only handles up to 32
++				/* NOTE ohci only handles up to 32 */
+ 				max = 128;
+ 			} else {
+ 				if (urb->interval > 1024)
+ 					urb->interval = 1024;
+-				// NOTE usb and ohci handle up to 2^15
++				/* NOTE usb and ohci handle up to 2^15 */
+ 				max = 1024;
+ 			}
+ 			break;
+@@ -444,6 +449,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
+ 
+ 	return usb_hcd_submit_urb(urb, mem_flags);
+ }
++EXPORT_SYMBOL_GPL(usb_submit_urb);
+ 
+ /*-------------------------------------------------------------------*/
+ 
+@@ -514,6 +520,7 @@ int usb_unlink_urb(struct urb *urb)
+ 		return -EIDRM;
+ 	return usb_hcd_unlink_urb(urb, -ECONNRESET);
+ }
++EXPORT_SYMBOL_GPL(usb_unlink_urb);
+ 
+ /**
+  * usb_kill_urb - cancel a transfer request and wait for it to finish
+@@ -553,6 +560,7 @@ void usb_kill_urb(struct urb *urb)
+ 	--urb->reject;
+ 	mutex_unlock(&reject_mutex);
+ }
++EXPORT_SYMBOL_GPL(usb_kill_urb);
+ 
+ /**
+  * usb_kill_anchored_urbs - cancel transfer requests en masse
+@@ -567,7 +575,8 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor)
+ 
+ 	spin_lock_irq(&anchor->lock);
+ 	while (!list_empty(&anchor->urb_list)) {
+-		victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
++		victim = list_entry(anchor->urb_list.prev, struct urb,
++				    anchor_list);
+ 		/* we must make sure the URB isn't freed before we kill it*/
+ 		usb_get_urb(victim);
+ 		spin_unlock_irq(&anchor->lock);
+@@ -595,11 +604,3 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+ 				  msecs_to_jiffies(timeout));
+ }
+ EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
+-
+-EXPORT_SYMBOL(usb_init_urb);
+-EXPORT_SYMBOL(usb_alloc_urb);
+-EXPORT_SYMBOL(usb_free_urb);
+-EXPORT_SYMBOL(usb_get_urb);
+-EXPORT_SYMBOL(usb_submit_urb);
+-EXPORT_SYMBOL(usb_unlink_urb);
+-EXPORT_SYMBOL(usb_kill_urb);
+diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
+index 8f14237..4e98406 100644
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -96,6 +96,7 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+ 
+ 	return NULL;
+ }
++EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
+ 
+ /**
+  * usb_altnum_to_altsetting - get the altsetting structure with a given
+@@ -115,8 +116,9 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+  * Don't call this function unless you are bound to the intf interface
+  * or you have locked the device!
+  */
+-struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
+-						    unsigned int altnum)
++struct usb_host_interface *usb_altnum_to_altsetting(
++					const struct usb_interface *intf,
++					unsigned int altnum)
+ {
+ 	int i;
+ 
+@@ -126,13 +128,14 @@ struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *
+ 	}
+ 	return NULL;
+ }
++EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);
+ 
+ struct find_interface_arg {
+ 	int minor;
+ 	struct usb_interface *interface;
+ };
+ 
+-static int __find_interface(struct device * dev, void * data)
++static int __find_interface(struct device *dev, void *data)
+ {
+ 	struct find_interface_arg *arg = data;
+ 	struct usb_interface *intf;
+@@ -154,7 +157,7 @@ static int __find_interface(struct device * dev, void * data)
+  * @drv: the driver whose current configuration is considered
+  * @minor: the minor number of the desired device
+  *
+- * This walks the driver device list and returns a pointer to the interface 
++ * This walks the driver device list and returns a pointer to the interface
+  * with the matching minor.  Note, this only works for devices that share the
+  * USB major number.
+  */
+@@ -170,6 +173,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
+ 					__find_interface);
+ 	return argb.interface;
+ }
++EXPORT_SYMBOL_GPL(usb_find_interface);
+ 
+ /**
+  * usb_release_dev - free a usb device structure when all users of it are finished.
+@@ -230,7 +234,7 @@ static int ksuspend_usb_init(void)
+ 	 * singlethreaded.  Its job doesn't justify running on more
+ 	 * than one CPU.
+ 	 */
+-	ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
++	ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
+ 	if (!ksuspend_usb_wq)
+ 		return -ENOMEM;
+ 	return 0;
+@@ -269,8 +273,8 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+  *
+  * This call may not be used in a non-sleeping context.
+  */
+-struct usb_device *
+-usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
++struct usb_device *usb_alloc_dev(struct usb_device *parent,
++				 struct usb_bus *bus, unsigned port1)
+ {
+ 	struct usb_device *dev;
+ 	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+@@ -339,6 +343,8 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
+ 	mutex_init(&dev->pm_mutex);
+ 	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
+ 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
++	dev->connect_time = jiffies;
++	dev->active_duration = -jiffies;
+ #endif
+ 	if (root_hub)	/* Root hub always ok [and always wired] */
+ 		dev->authorized = 1;
+@@ -367,6 +373,7 @@ struct usb_device *usb_get_dev(struct usb_device *dev)
+ 		get_device(&dev->dev);
+ 	return dev;
+ }
++EXPORT_SYMBOL_GPL(usb_get_dev);
+ 
+ /**
+  * usb_put_dev - release a use of the usb device structure
+@@ -380,6 +387,7 @@ void usb_put_dev(struct usb_device *dev)
+ 	if (dev)
+ 		put_device(&dev->dev);
+ }
++EXPORT_SYMBOL_GPL(usb_put_dev);
+ 
+ /**
+  * usb_get_intf - increments the reference count of the usb interface structure
+@@ -400,6 +408,7 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf)
+ 		get_device(&intf->dev);
+ 	return intf;
+ }
++EXPORT_SYMBOL_GPL(usb_get_intf);
+ 
+ /**
+  * usb_put_intf - release a use of the usb interface structure
+@@ -414,7 +423,7 @@ void usb_put_intf(struct usb_interface *intf)
+ 	if (intf)
+ 		put_device(&intf->dev);
+ }
+-
++EXPORT_SYMBOL_GPL(usb_put_intf);
+ 
+ /*			USB device locking
+  *
+@@ -461,11 +470,11 @@ int usb_lock_device_for_reset(struct usb_device *udev,
+ 		return -EHOSTUNREACH;
+ 	if (iface) {
+ 		switch (iface->condition) {
+-		  case USB_INTERFACE_BINDING:
++		case USB_INTERFACE_BINDING:
+ 			return 0;
+-		  case USB_INTERFACE_BOUND:
++		case USB_INTERFACE_BOUND:
+ 			break;
+-		  default:
++		default:
+ 			return -EINTR;
+ 		}
+ 	}
+@@ -487,7 +496,7 @@ int usb_lock_device_for_reset(struct usb_device *udev,
+ 	}
+ 	return 1;
+ }
+-
++EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
+ 
+ static struct usb_device *match_device(struct usb_device *dev,
+ 				       u16 vendor_id, u16 product_id)
+@@ -540,10 +549,10 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
+ 	struct list_head *buslist;
+ 	struct usb_bus *bus;
+ 	struct usb_device *dev = NULL;
+-	
++
+ 	mutex_lock(&usb_bus_list_lock);
+ 	for (buslist = usb_bus_list.next;
+-	     buslist != &usb_bus_list; 
++	     buslist != &usb_bus_list;
+ 	     buslist = buslist->next) {
+ 		bus = container_of(buslist, struct usb_bus, bus_list);
+ 		if (!bus->root_hub)
+@@ -576,6 +585,7 @@ int usb_get_current_frame_number(struct usb_device *dev)
+ {
+ 	return usb_hcd_get_frame_number(dev);
+ }
++EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
+ 
+ /*-------------------------------------------------------------------*/
+ /*
+@@ -584,7 +594,7 @@ int usb_get_current_frame_number(struct usb_device *dev)
+  */
+ 
+ int __usb_get_extra_descriptor(char *buffer, unsigned size,
+-	unsigned char type, void **ptr)
++			       unsigned char type, void **ptr)
+ {
+ 	struct usb_descriptor_header *header;
+ 
+@@ -595,7 +605,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
+ 			printk(KERN_ERR
+ 				"%s: bogus descriptor, type %d length %d\n",
+ 				usbcore_name,
+-				header->bDescriptorType, 
++				header->bDescriptorType,
+ 				header->bLength);
+ 			return -1;
+ 		}
+@@ -610,6 +620,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
+ 	}
+ 	return -1;
+ }
++EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
+ 
+ /**
+  * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
+@@ -633,17 +644,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
+  *
+  * When the buffer is no longer used, free it with usb_buffer_free().
+  */
+-void *usb_buffer_alloc(
+-	struct usb_device *dev,
+-	size_t size,
+-	gfp_t mem_flags,
+-	dma_addr_t *dma
+-)
++void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags,
++		       dma_addr_t *dma)
+ {
+ 	if (!dev || !dev->bus)
+ 		return NULL;
+ 	return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_alloc);
+ 
+ /**
+  * usb_buffer_free - free memory allocated with usb_buffer_alloc()
+@@ -656,12 +664,8 @@ void *usb_buffer_alloc(
+  * been allocated using usb_buffer_alloc(), and the parameters must match
+  * those provided in that allocation request.
+  */
+-void usb_buffer_free(
+-	struct usb_device *dev,
+-	size_t size,
+-	void *addr,
+-	dma_addr_t dma
+-)
++void usb_buffer_free(struct usb_device *dev, size_t size, void *addr,
++		     dma_addr_t dma)
+ {
+ 	if (!dev || !dev->bus)
+ 		return;
+@@ -669,6 +673,7 @@ void usb_buffer_free(
+ 		return;
+ 	hcd_buffer_free(dev->bus, size, addr, dma);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_free);
+ 
+ /**
+  * usb_buffer_map - create DMA mapping(s) for an urb
+@@ -708,14 +713,15 @@ struct urb *usb_buffer_map(struct urb *urb)
+ 					urb->setup_packet,
+ 					sizeof(struct usb_ctrlrequest),
+ 					DMA_TO_DEVICE);
+-	// FIXME generic api broken like pci, can't report errors
+-	// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
++	/* FIXME generic api broken like pci, can't report errors */
++	/* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
+ 	} else
+ 		urb->transfer_dma = ~0;
+ 	urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
+ 				| URB_NO_SETUP_DMA_MAP);
+ 	return urb;
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_map);
+ #endif  /*  0  */
+ 
+ /* XXX DISABLED, no users currently.  If you wish to re-enable this
+@@ -753,6 +759,7 @@ void usb_buffer_dmasync(struct urb *urb)
+ 					DMA_TO_DEVICE);
+ 	}
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_dmasync);
+ #endif
+ 
+ /**
+@@ -788,6 +795,7 @@ void usb_buffer_unmap(struct urb *urb)
+ 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
+ 				| URB_NO_SETUP_DMA_MAP);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_unmap);
+ #endif  /*  0  */
+ 
+ /**
+@@ -828,10 +836,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
+ 			|| !controller->dma_mask)
+ 		return -1;
+ 
+-	// FIXME generic api broken like pci, can't report errors
++	/* FIXME generic api broken like pci, can't report errors */
+ 	return dma_map_sg(controller, sg, nents,
+ 			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
+ 
+ /* XXX DISABLED, no users currently.  If you wish to re-enable this
+  * XXX please determine whether the sync is to transfer ownership of
+@@ -865,6 +874,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
+ 	dma_sync_sg(controller, sg, n_hw_ents,
+ 			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
+ #endif
+ 
+ /**
+@@ -891,6 +901,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
+ 	dma_unmap_sg(controller, sg, n_hw_ents,
+ 			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
++EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
+ 
+ /* format to disable USB on kernel command line is: nousb */
+ __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
+@@ -902,6 +913,7 @@ int usb_disabled(void)
+ {
+ 	return nousb;
+ }
++EXPORT_SYMBOL_GPL(usb_disabled);
+ 
+ /*
+  * Init
+@@ -918,7 +930,7 @@ static int __init usb_init(void)
+ 	if (retval)
+ 		goto out;
+ 	retval = bus_register(&usb_bus_type);
+-	if (retval) 
++	if (retval)
+ 		goto bus_register_failed;
+ 	retval = usb_host_init();
+ 	if (retval)
+@@ -983,45 +995,4 @@ static void __exit usb_exit(void)
+ 
+ subsys_initcall(usb_init);
+ module_exit(usb_exit);
+-
+-/*
+- * USB may be built into the kernel or be built as modules.
+- * These symbols are exported for device (or host controller)
+- * driver modules to use.
+- */
+-
+-EXPORT_SYMBOL(usb_disabled);
+-
+-EXPORT_SYMBOL_GPL(usb_get_intf);
+-EXPORT_SYMBOL_GPL(usb_put_intf);
+-
+-EXPORT_SYMBOL(usb_put_dev);
+-EXPORT_SYMBOL(usb_get_dev);
+-EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
+-
+-EXPORT_SYMBOL(usb_lock_device_for_reset);
+-
+-EXPORT_SYMBOL(usb_find_interface);
+-EXPORT_SYMBOL(usb_ifnum_to_if);
+-EXPORT_SYMBOL(usb_altnum_to_altsetting);
+-
+-EXPORT_SYMBOL(__usb_get_extra_descriptor);
+-
+-EXPORT_SYMBOL(usb_get_current_frame_number);
+-
+-EXPORT_SYMBOL(usb_buffer_alloc);
+-EXPORT_SYMBOL(usb_buffer_free);
+-
+-#if 0
+-EXPORT_SYMBOL(usb_buffer_map);
+-EXPORT_SYMBOL(usb_buffer_dmasync);
+-EXPORT_SYMBOL(usb_buffer_unmap);
+-#endif
+-
+-EXPORT_SYMBOL(usb_buffer_map_sg);
+-#if 0
+-EXPORT_SYMBOL(usb_buffer_dmasync_sg);
+-#endif
+-EXPORT_SYMBOL(usb_buffer_unmap_sg);
+-
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
+index c52626c..2375194 100644
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -1,22 +1,23 @@
+ /* Functions local to drivers/usb/core/ */
+ 
+-extern int usb_create_sysfs_dev_files (struct usb_device *dev);
+-extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
+-extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
+-extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
+-extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
++extern int usb_create_sysfs_dev_files(struct usb_device *dev);
++extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
++extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
++extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
++extern int usb_create_ep_files(struct device *parent,
++				struct usb_host_endpoint *endpoint,
+ 				struct usb_device *udev);
+ extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+ 
+ extern void usb_enable_endpoint(struct usb_device *dev,
+ 		struct usb_host_endpoint *ep);
+-extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
+-extern void usb_disable_interface (struct usb_device *dev,
++extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr);
++extern void usb_disable_interface(struct usb_device *dev,
+ 		struct usb_interface *intf);
+ extern void usb_release_interface_cache(struct kref *ref);
+-extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+-extern int usb_deauthorize_device (struct usb_device *);
+-extern int usb_authorize_device (struct usb_device *);
++extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
++extern int usb_deauthorize_device(struct usb_device *);
++extern int usb_authorize_device(struct usb_device *);
+ extern void usb_detect_quirks(struct usb_device *udev);
+ 
+ extern int usb_get_device_descriptor(struct usb_device *dev,
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index f81d08d..c139551 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -12,10 +12,9 @@
+ # With help from a special transceiver and a "Mini-AB" jack, systems with
+ # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+ #
+-menu "USB Gadget Support"
+ 
+-config USB_GADGET
+-	tristate "Support for USB Gadgets"
++menuconfig USB_GADGET
++	tristate "USB Gadget Support"
+ 	help
+ 	   USB is a master/slave protocol, organized with one master
+ 	   host (such as a PC) controlling up to 127 peripheral devices.
+@@ -42,6 +41,8 @@ config USB_GADGET
+ 	   For more information, see <http://www.linux-usb.org/gadget> and
+ 	   the kernel DocBook documentation for this API.
+ 
++if USB_GADGET
++
+ config USB_GADGET_DEBUG
+ 	boolean "Debugging messages"
+ 	depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
+@@ -220,6 +221,16 @@ config USB_M66592
+ 	default USB_GADGET
+ 	select USB_GADGET_SELECTED
+ 
++config SUPERH_BUILT_IN_M66592
++	boolean "Enable SuperH built-in USB like the M66592"
++	depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
++	help
++	   SH7722 has USB like the M66592.
++
++	   The transfer rate is very slow when use "Ethernet Gadget".
++	   However, this problem is improved if change a value of
++	   NET_IP_ALIGN to 4.
++
+ config USB_GADGET_GOKU
+ 	boolean "Toshiba TC86C001 'Goku-S'"
+ 	depends on PCI
+@@ -308,7 +319,7 @@ config USB_S3C2410_DEBUG
+ 
+ config USB_GADGET_AT91
+ 	boolean "AT91 USB Device Port"
+-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
++	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
+ 	select USB_GADGET_SELECTED
+ 	help
+ 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
+@@ -538,6 +549,20 @@ config USB_MIDI_GADGET
+ 	  Say "y" to link the driver statically, or "m" to build a
+ 	  dynamically linked module called "g_midi".
+ 
++config USB_G_PRINTER
++	tristate "Printer Gadget"
++	help
++	  The Printer Gadget channels data between the USB host and a
++	  userspace program driving the print engine. The user space
++	  program reads and writes the device file /dev/g_printer to
++	  receive or send printer data. It can use ioctl calls to
++	  the device file to get or set printer status.
++
++	  Say "y" to link the driver statically, or "m" to build a
++	  dynamically linked module called "g_printer".
++
++	  For more information, see Documentation/usb/gadget_printer.txt
++	  which includes sample code for accessing the device file.
+ 
+ # put drivers that need isochronous transfer support (for audio
+ # or video class gadget drivers), or specific hardware, here.
+@@ -546,4 +571,4 @@ config USB_MIDI_GADGET
+ 
+ endchoice
+ 
+-endmenu
++endif # USB_GADGET
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index 904e57b..c3aab80 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -28,6 +28,8 @@ g_midi-objs			:= gmidi.o usbstring.o config.o epautoconf.o
+ gadgetfs-objs			:= inode.o
+ g_file_storage-objs		:= file_storage.o usbstring.o config.o \
+ 					epautoconf.o
++g_printer-objs			:= printer.o usbstring.o config.o \
++					epautoconf.o
+ 
+ ifeq ($(CONFIG_USB_ETH_RNDIS),y)
+ 	g_ether-objs		+= rndis.o
+@@ -38,5 +40,6 @@ obj-$(CONFIG_USB_ETH)		+= g_ether.o
+ obj-$(CONFIG_USB_GADGETFS)	+= gadgetfs.o
+ obj-$(CONFIG_USB_FILE_STORAGE)	+= g_file_storage.o
+ obj-$(CONFIG_USB_G_SERIAL)	+= g_serial.o
++obj-$(CONFIG_USB_G_PRINTER)	+= g_printer.o
+ obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
+ 
+diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
+index c72e962..b663f23 100644
+--- a/drivers/usb/gadget/amd5536udc.c
++++ b/drivers/usb/gadget/amd5536udc.c
+@@ -1244,7 +1244,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+ 		/* stop OUT naking */
+ 		if (!ep->in) {
+ 			if (!use_dma && udc_rxfifo_pending) {
+-				DBG(dev, "udc_queue(): pending bytes in"
++				DBG(dev, "udc_queue(): pending bytes in "
+ 					"rxfifo after nyet\n");
+ 				/*
+ 				 * read pending bytes afer nyet:
+@@ -2038,6 +2038,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ 	spin_unlock_irqrestore(&dev->lock, flags);
+ 
+ 	driver->unbind(&dev->gadget);
++	dev->gadget.dev.driver = NULL;
+ 	dev->driver = NULL;
+ 
+ 	/* set SD */
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index cd62b02..a83e8b7 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -21,8 +21,7 @@
+  * Boston, MA  02111-1307, USA.
+  */
+ 
+-#undef	DEBUG
+-#undef	VERBOSE
++#undef	VERBOSE_DEBUG
+ #undef	PACKET_TRACE
+ 
+ #include <linux/kernel.h>
+@@ -46,8 +45,8 @@
+ #include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/mach-types.h>
++#include <asm/gpio.h>
+ 
+-#include <asm/arch/gpio.h>
+ #include <asm/arch/board.h>
+ #include <asm/arch/cpu.h>
+ #include <asm/arch/at91sam9261_matrix.h>
+@@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
+  */
+ 
+ static struct usb_request *
+-at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
++at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+ {
+ 	struct at91_request *req;
+ 
+@@ -881,6 +880,8 @@ static void clk_off(struct at91_udc *udc)
+  */
+ static void pullup(struct at91_udc *udc, int is_on)
+ {
++	int	active = !udc->board.pullup_active_low;
++
+ 	if (!udc->enabled || !udc->vbus)
+ 		is_on = 0;
+ 	DBG("%sactive\n", is_on ? "" : "in");
+@@ -890,7 +891,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+ 		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+ 		at91_udp_write(udc, AT91_UDP_TXVC, 0);
+ 		if (cpu_is_at91rm9200())
+-			at91_set_gpio_value(udc->board.pullup_pin, 1);
++			gpio_set_value(udc->board.pullup_pin, active);
+ 		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
+ 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+ 
+@@ -908,7 +909,7 @@ static void pullup(struct at91_udc *udc, int is_on)
+ 		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+ 		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ 		if (cpu_is_at91rm9200())
+-			at91_set_gpio_value(udc->board.pullup_pin, 0);
++			gpio_set_value(udc->board.pullup_pin, !active);
+ 		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
+ 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+ 
+@@ -1153,7 +1154,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+ 			| USB_REQ_GET_STATUS:
+ 		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ 		ep = &udc->ep[tmp];
+-		if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
++		if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
+ 			goto stall;
+ 
+ 		if (tmp) {
+@@ -1176,7 +1177,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+ 			| USB_REQ_SET_FEATURE:
+ 		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ 		ep = &udc->ep[tmp];
+-		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
++		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+ 			goto stall;
+ 		if (!ep->desc || ep->is_iso)
+ 			goto stall;
+@@ -1195,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+ 			| USB_REQ_CLEAR_FEATURE:
+ 		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ 		ep = &udc->ep[tmp];
+-		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
++		if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+ 			goto stall;
+ 		if (tmp == 0)
+ 			goto succeed;
+@@ -1551,7 +1552,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc)
+ 
+ 	/* vbus needs at least brief debouncing */
+ 	udelay(10);
+-	value = at91_get_gpio_value(udc->board.vbus_pin);
++	value = gpio_get_value(udc->board.vbus_pin);
+ 	if (value != udc->vbus)
+ 		at91_vbus_session(&udc->gadget, value);
+ 
+@@ -1616,6 +1617,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+ 	local_irq_enable();
+ 
+ 	driver->unbind(&udc->gadget);
++	udc->gadget.dev.driver = NULL;
++	udc->gadget.dev.driver_data = NULL;
+ 	udc->driver = NULL;
+ 
+ 	DBG("unbound from %s\n", driver->driver.name);
+@@ -1645,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	if (pdev->num_resources != 2) {
+-		DBG("invalid num_resources");
++		DBG("invalid num_resources\n");
+ 		return -ENODEV;
+ 	}
+ 	if ((pdev->resource[0].flags != IORESOURCE_MEM)
+ 			|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+-		DBG("invalid resource type");
++		DBG("invalid resource type\n");
+ 		return -ENODEV;
+ 	}
+ 
+@@ -1672,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ 	udc->pdev = pdev;
+ 	udc->enabled = 0;
+ 
++	/* rm9200 needs manual D+ pullup; off by default */
++	if (cpu_is_at91rm9200()) {
++		if (udc->board.pullup_pin <= 0) {
++			DBG("no D+ pullup?\n");
++			retval = -ENODEV;
++			goto fail0;
++		}
++		retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
++		if (retval) {
++			DBG("D+ pullup is busy\n");
++			goto fail0;
++		}
++		gpio_direction_output(udc->board.pullup_pin,
++				udc->board.pullup_active_low);
++	}
++
+ 	udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+ 	if (!udc->udp_baseaddr) {
+-		release_mem_region(res->start, res->end - res->start + 1);
+-		return -ENOMEM;
++		retval = -ENOMEM;
++		goto fail0a;
+ 	}
+ 
+ 	udc_reinit(udc);
+@@ -1686,12 +1705,13 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ 	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+ 		DBG("clocks missing\n");
+ 		retval = -ENODEV;
+-		goto fail0;
++		/* NOTE: we "know" here that refcounts on these are NOPs */
++		goto fail0b;
+ 	}
+ 
+ 	retval = device_register(&udc->gadget.dev);
+ 	if (retval < 0)
+-		goto fail0;
++		goto fail0b;
+ 
+ 	/* don't do anything until we have both gadget driver and VBUS */
+ 	clk_enable(udc->iclk);
+@@ -1703,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ 
+ 	/* request UDC and maybe VBUS irqs */
+ 	udc->udp_irq = platform_get_irq(pdev, 0);
+-	if (request_irq(udc->udp_irq, at91_udc_irq,
+-			IRQF_DISABLED, driver_name, udc)) {
++	retval = request_irq(udc->udp_irq, at91_udc_irq,
++			IRQF_DISABLED, driver_name, udc);
++	if (retval < 0) {
+ 		DBG("request irq %d failed\n", udc->udp_irq);
+-		retval = -EBUSY;
+ 		goto fail1;
+ 	}
+ 	if (udc->board.vbus_pin > 0) {
++		retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
++		if (retval < 0) {
++			DBG("request vbus pin failed\n");
++			goto fail2;
++		}
++		gpio_direction_input(udc->board.vbus_pin);
++
+ 		/*
+ 		 * Get the initial state of VBUS - we cannot expect
+ 		 * a pending interrupt.
+ 		 */
+-		udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
++		udc->vbus = gpio_get_value(udc->board.vbus_pin);
+ 		if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
+ 				IRQF_DISABLED, driver_name, udc)) {
+ 			DBG("request vbus irq %d failed\n",
+ 					udc->board.vbus_pin);
+ 			free_irq(udc->udp_irq, udc);
+ 			retval = -EBUSY;
+-			goto fail1;
++			goto fail3;
+ 		}
+ 	} else {
+ 		DBG("no VBUS detection, assuming always-on\n");
+@@ -1734,8 +1761,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
+ 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+ 	return 0;
+ 
++fail3:
++	if (udc->board.vbus_pin > 0)
++		gpio_free(udc->board.vbus_pin);
++fail2:
++	free_irq(udc->udp_irq, udc);
+ fail1:
+ 	device_unregister(&udc->gadget.dev);
++fail0b:
++	iounmap(udc->udp_baseaddr);
++fail0a:
++	if (cpu_is_at91rm9200())
++		gpio_free(udc->board.pullup_pin);
+ fail0:
+ 	release_mem_region(res->start, res->end - res->start + 1);
+ 	DBG("%s probe failed, %d\n", driver_name, retval);
+@@ -1756,12 +1793,18 @@ static int __exit at91udc_remove(struct platform_device *pdev)
+ 
+ 	device_init_wakeup(&pdev->dev, 0);
+ 	remove_debug_file(udc);
+-	if (udc->board.vbus_pin > 0)
++	if (udc->board.vbus_pin > 0) {
+ 		free_irq(udc->board.vbus_pin, udc);
++		gpio_free(udc->board.vbus_pin);
++	}
+ 	free_irq(udc->udp_irq, udc);
+ 	device_unregister(&udc->gadget.dev);
+ 
+ 	iounmap(udc->udp_baseaddr);
++
++	if (cpu_is_at91rm9200())
++		gpio_free(udc->board.pullup_pin);
++
+ 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	release_mem_region(res->start, res->end - res->start + 1);
+ 
+diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
+index 7e34e2f..a973f2a 100644
+--- a/drivers/usb/gadget/at91_udc.h
++++ b/drivers/usb/gadget/at91_udc.h
+@@ -53,7 +53,7 @@
+ #define     AT91_UDP_RXRSM	(1 <<  9)	/* USB Resume Interrupt Status */
+ #define     AT91_UDP_EXTRSM	(1 << 10)	/* External Resume Interrupt Status [AT91RM9200 only] */
+ #define     AT91_UDP_SOFINT	(1 << 11)	/* Start of Frame Interrupt Status */
+-#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrpt Status */
++#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrupt Status */
+ #define     AT91_UDP_WAKEUP	(1 << 13)	/* USB Wakeup Interrupt Status [AT91RM9200 only] */
+ 
+ #define AT91_UDP_ICR		0x20		/* Interrupt Clear Register */
+@@ -158,13 +158,7 @@ struct at91_request {
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-#ifdef DEBUG
+-#define DBG(stuff...)		printk(KERN_DEBUG "udc: " stuff)
+-#else
+-#define DBG(stuff...)		do{}while(0)
+-#endif
+-
+-#ifdef VERBOSE
++#ifdef VERBOSE_DEBUG
+ #    define VDBG		DBG
+ #else
+ #    define VDBG(stuff...)	do{}while(0)
+@@ -176,9 +170,10 @@ struct at91_request {
+ #    define PACKET(stuff...)	do{}while(0)
+ #endif
+ 
+-#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+-#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+-#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
++#define ERR(stuff...)		pr_err("udc: " stuff)
++#define WARN(stuff...)		pr_warning("udc: " stuff)
++#define INFO(stuff...)		pr_info("udc: " stuff)
++#define DBG(stuff...)		pr_debug("udc: " stuff)
+ 
+ #endif
+ 
+diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
+index 4fb5ff4..af8b2a3 100644
+--- a/drivers/usb/gadget/atmel_usba_udc.c
++++ b/drivers/usb/gadget/atmel_usba_udc.c
+@@ -1384,8 +1384,7 @@ delegate:
+ 	return retval;
+ 
+ stall:
+-	printk(KERN_ERR
+-		"udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
++	pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+ 		"halting endpoint...\n",
+ 		ep->ep.name, crq->bRequestType, crq->bRequest,
+ 		le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+@@ -1456,8 +1455,7 @@ restart:
+ 				set_protocol_stall(udc, ep);
+ 			break;
+ 		default:
+-			printk(KERN_ERR
+-				"udc: %s: TXCOMP: Invalid endpoint state %d, "
++			pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, "
+ 				"halting endpoint...\n",
+ 				ep->ep.name, ep->state);
+ 			set_protocol_stall(udc, ep);
+@@ -1486,8 +1484,7 @@ restart:
+ 		default:
+ 			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ 			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+-			printk(KERN_ERR
+-				"udc: %s: RXRDY: Invalid endpoint state %d, "
++			pr_err("udc: %s: RXRDY: Invalid endpoint state %d, "
+ 				"halting endpoint...\n",
+ 				ep->ep.name, ep->state);
+ 			set_protocol_stall(udc, ep);
+@@ -1532,7 +1529,7 @@ restart:
+ 		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+ 		DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+ 		if (pkt_len != sizeof(crq)) {
+-			printk(KERN_WARNING "udc: Invalid packet length %u "
++			pr_warning("udc: Invalid packet length %u "
+ 				"(expected %lu)\n", pkt_len, sizeof(crq));
+ 			set_protocol_stall(udc, ep);
+ 			return;
+diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
+index a68304e..08bf6f9 100644
+--- a/drivers/usb/gadget/atmel_usba_udc.h
++++ b/drivers/usb/gadget/atmel_usba_udc.h
+@@ -216,7 +216,6 @@
+ #define FIFO_IOMEM_ID	0
+ #define CTRL_IOMEM_ID	1
+ 
+-#ifdef DEBUG
+ #define DBG_ERR		0x0001	/* report all error returns */
+ #define DBG_HW		0x0002	/* debug hardware initialization */
+ #define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+@@ -230,14 +229,12 @@
+ #define DBG_NONE	0x0000
+ 
+ #define DEBUG_LEVEL	(DBG_ERR)
++
+ #define DBG(level, fmt, ...)					\
+ 	do {							\
+ 		if ((level) & DEBUG_LEVEL)			\
+-			printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__);	\
++			pr_debug("udc: " fmt, ## __VA_ARGS__);	\
+ 	} while (0)
+-#else
+-#define DBG(level, fmt...)
+-#endif
+ 
+ enum usba_ctrl_state {
+ 	WAIT_FOR_SETUP,
+diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
+index 9db2482..cbe4453 100644
+--- a/drivers/usb/gadget/dummy_hcd.c
++++ b/drivers/usb/gadget/dummy_hcd.c
+@@ -61,6 +61,8 @@
+ #define DRIVER_DESC	"USB Host+Gadget Emulator"
+ #define DRIVER_VERSION	"02 May 2005"
+ 
++#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
++
+ static const char	driver_name [] = "dummy_hcd";
+ static const char	driver_desc [] = "USB Host+Gadget Emulator";
+ 
+@@ -772,18 +774,17 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
+ 	list_del_init (&dum->ep [0].ep.ep_list);
+ 	INIT_LIST_HEAD(&dum->fifo_req.queue);
+ 
++	driver->driver.bus = NULL;
+ 	dum->driver = driver;
+ 	dum->gadget.dev.driver = &driver->driver;
+ 	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
+ 			driver->driver.name);
+-	if ((retval = driver->bind (&dum->gadget)) != 0)
+-		goto err_bind_gadget;
+-
+-	driver->driver.bus = dum->gadget.dev.parent->bus;
+-	if ((retval = driver_register (&driver->driver)) != 0)
+-		goto err_register;
+-	if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
+-		goto err_bind_driver;
++	retval = driver->bind(&dum->gadget);
++	if (retval) {
++		dum->driver = NULL;
++		dum->gadget.dev.driver = NULL;
++		return retval;
++	}
+ 
+ 	/* khubd will enumerate this in a while */
+ 	spin_lock_irq (&dum->lock);
+@@ -793,20 +794,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
+ 
+ 	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+ 	return 0;
+-
+-err_bind_driver:
+-	driver_unregister (&driver->driver);
+-err_register:
+-	if (driver->unbind)
+-		driver->unbind (&dum->gadget);
+-	spin_lock_irq (&dum->lock);
+-	dum->pullup = 0;
+-	set_link_state (dum);
+-	spin_unlock_irq (&dum->lock);
+-err_bind_gadget:
+-	dum->driver = NULL;
+-	dum->gadget.dev.driver = NULL;
+-	return retval;
+ }
+ EXPORT_SYMBOL (usb_gadget_register_driver);
+ 
+@@ -830,11 +817,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+ 	spin_unlock_irqrestore (&dum->lock, flags);
+ 
+ 	driver->unbind (&dum->gadget);
++	dum->gadget.dev.driver = NULL;
+ 	dum->driver = NULL;
+ 
+-	device_release_driver (&dum->gadget.dev);
+-	driver_unregister (&driver->driver);
+-
+ 	spin_lock_irqsave (&dum->lock, flags);
+ 	dum->pullup = 0;
+ 	set_link_state (dum);
+@@ -1827,8 +1812,7 @@ static int dummy_start (struct usb_hcd *hcd)
+ 
+ 	INIT_LIST_HEAD (&dum->urbp_list);
+ 
+-	/* only show a low-power port: just 8mA */
+-	hcd->power_budget = 8;
++	hcd->power_budget = POWER_BUDGET;
+ 	hcd->state = HC_STATE_RUNNING;
+ 	hcd->uses_new_polling = 1;
+ 
+diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
+index 9e732bf..a70e255 100644
+--- a/drivers/usb/gadget/ether.c
++++ b/drivers/usb/gadget/ether.c
+@@ -1067,19 +1067,19 @@ done:
+ 
+ 	/* on error, disable any endpoints  */
+ 	if (result < 0) {
+-		if (!subset_active(dev))
++		if (!subset_active(dev) && dev->status_ep)
+ 			(void) usb_ep_disable (dev->status_ep);
+ 		dev->status = NULL;
+ 		(void) usb_ep_disable (dev->in_ep);
+ 		(void) usb_ep_disable (dev->out_ep);
+ 		dev->in = NULL;
+ 		dev->out = NULL;
+-	} else
++	}
+ 
+ 	/* activate non-CDC configs right away
+ 	 * this isn't strictly according to the RNDIS spec
+ 	 */
+-	if (!cdc_active (dev)) {
++	else if (!cdc_active (dev)) {
+ 		netif_carrier_on (dev->net);
+ 		if (netif_running (dev->net)) {
+ 			spin_unlock (&dev->lock);
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+index 1d174dc..3301167 100644
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -275,19 +275,15 @@ MODULE_LICENSE("Dual BSD/GPL");
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-#ifdef DEBUG
+ #define LDBG(lun,fmt,args...) \
+ 	dev_dbg(&(lun)->dev , fmt , ## args)
+ #define MDBG(fmt,args...) \
+-	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
+-#else
+-#define LDBG(lun,fmt,args...) \
+-	do { } while (0)
+-#define MDBG(fmt,args...) \
+-	do { } while (0)
++	pr_debug(DRIVER_NAME ": " fmt , ## args)
++
++#ifndef DEBUG
+ #undef VERBOSE_DEBUG
+ #undef DUMP_MSGS
+-#endif /* DEBUG */
++#endif /* !DEBUG */
+ 
+ #ifdef VERBOSE_DEBUG
+ #define VLDBG	LDBG
+@@ -304,7 +300,7 @@ MODULE_LICENSE("Dual BSD/GPL");
+ 	dev_info(&(lun)->dev , fmt , ## args)
+ 
+ #define MINFO(fmt,args...) \
+-	printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
++	pr_info(DRIVER_NAME ": " fmt , ## args)
+ 
+ #define DBG(d, fmt, args...) \
+ 	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
+index 038e7d7..63e8fa3 100644
+--- a/drivers/usb/gadget/fsl_usb2_udc.c
++++ b/drivers/usb/gadget/fsl_usb2_udc.c
+@@ -776,7 +776,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+ 		VDBG("%s, bad params\n", __FUNCTION__);
+ 		return -EINVAL;
+ 	}
+-	if (!_ep || (!ep->desc && ep_index(ep))) {
++	if (unlikely(!_ep || !ep->desc)) {
+ 		VDBG("%s, bad ep\n", __FUNCTION__);
+ 		return -EINVAL;
+ 	}
+@@ -1896,7 +1896,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
+ 
+ 	spin_lock_irqsave(&udc->lock, flags);
+ 
+-	/* ------basic driver infomation ---- */
++	/* ------basic driver information ---- */
+ 	t = scnprintf(next, size,
+ 			DRIVER_DESC "\n"
+ 			"%s version: %s\n"
+diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
+index 832ab82..9fb0b1e 100644
+--- a/drivers/usb/gadget/fsl_usb2_udc.h
++++ b/drivers/usb/gadget/fsl_usb2_udc.h
+@@ -551,9 +551,9 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
+ #define VDBG(stuff...)	do{}while(0)
+ #endif
+ 
+-#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+-#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+-#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
++#define ERR(stuff...)		pr_err("udc: " stuff)
++#define WARN(stuff...)		pr_warning("udc: " stuff)
++#define INFO(stuff...)		pr_info("udc: " stuff)
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
+index 0689189..5b42ccd 100644
+--- a/drivers/usb/gadget/gmidi.c
++++ b/drivers/usb/gadget/gmidi.c
+@@ -24,7 +24,6 @@
+ #include <linux/utsname.h>
+ #include <linux/device.h>
+ 
+-#include <sound/driver.h>
+ #include <sound/core.h>
+ #include <sound/initval.h>
+ #include <sound/rawmidi.h>
+@@ -1159,7 +1158,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget)
+ 	/* support optional vendor/distro customization */
+ 	if (idVendor) {
+ 		if (!idProduct) {
+-			printk(KERN_ERR "idVendor needs idProduct!\n");
++			pr_err("idVendor needs idProduct!\n");
+ 			return -ENODEV;
+ 		}
+ 		device_desc.idVendor = cpu_to_le16(idVendor);
+@@ -1191,7 +1190,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget)
+ 	in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
+ 	if (!in_ep) {
+ autoconf_fail:
+-		printk(KERN_ERR "%s: can't autoconfigure on %s\n",
++		pr_err("%s: can't autoconfigure on %s\n",
+ 			shortname, gadget->name);
+ 		return -ENODEV;
+ 	}
+@@ -1213,7 +1212,7 @@ autoconf_fail:
+ 		 * it SHOULD NOT have problems with bulk-capable hardware.
+ 		 * so warn about unrecognized controllers, don't panic.
+ 		 */
+-		printk(KERN_WARNING "%s: controller '%s' not recognized\n",
++		pr_warning("%s: controller '%s' not recognized\n",
+ 			shortname, gadget->name);
+ 		device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ 	}
+diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
+index 2ec9d19..d3e7025 100644
+--- a/drivers/usb/gadget/goku_udc.c
++++ b/drivers/usb/gadget/goku_udc.c
+@@ -1422,6 +1422,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ 	spin_unlock_irqrestore(&dev->lock, flags);
+ 
+ 	driver->unbind(&dev->gadget);
++	dev->gadget.dev.driver = NULL;
+ 
+ 	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
+ 	return 0;
+diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
+index 47ef8bd..805602a 100644
+--- a/drivers/usb/gadget/inode.c
++++ b/drivers/usb/gadget/inode.c
+@@ -1699,7 +1699,7 @@ gadgetfs_bind (struct usb_gadget *gadget)
+ 	if (!dev)
+ 		return -ESRCH;
+ 	if (0 != strcmp (CHIP, gadget->name)) {
+-		printk (KERN_ERR "%s expected %s controller not %s\n",
++		pr_err("%s expected %s controller not %s\n",
+ 			shortname, CHIP, gadget->name);
+ 		return -ENODEV;
+ 	}
+diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
+index 367b75c..37243ef 100644
+--- a/drivers/usb/gadget/lh7a40x_udc.c
++++ b/drivers/usb/gadget/lh7a40x_udc.c
+@@ -474,6 +474,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ 	spin_unlock_irqrestore(&dev->lock, flags);
+ 
+ 	driver->unbind(&dev->gadget);
++	dev->gadget.dev.driver = NULL;
+ 	device_del(&dev->gadget.dev);
+ 
+ 	udc_disable(dev);
+diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
+index ebc5536..835948f 100644
+--- a/drivers/usb/gadget/m66592-udc.c
++++ b/drivers/usb/gadget/m66592-udc.c
+@@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver");
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Yoshihiro Shimoda");
+ 
+-#define DRIVER_VERSION	"29 May 2007"
++#define DRIVER_VERSION	"18 Oct 2007"
+ 
+ /* module parameters */
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++static unsigned short endian = M66592_LITTLE;
++module_param(endian, ushort, 0644);
++MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
++#else
+ static unsigned short clock = M66592_XTAL24;
+ module_param(clock, ushort, 0644);
+ MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+@@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL;
+ module_param(irq_sense, ushort, 0644);
+ MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+ 		"(default=2)");
++#endif
+ 
+ static const char udc_name[] = "m66592_udc";
+ static const char *m66592_ep_name[] = {
+@@ -141,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
+ 		offset = get_pipectr_addr(pipenum);
+ 		pid = m66592_read(m66592, offset) & M66592_PID;
+ 	} else
+-		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
++		pr_err("unexpect pipe num (%d)\n", pipenum);
+ 
+ 	return pid;
+ }
+@@ -157,7 +163,7 @@ static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
+ 		offset = get_pipectr_addr(pipenum);
+ 		m66592_mdfy(m66592, pid, M66592_PID, offset);
+ 	} else
+-		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
++		pr_err("unexpect pipe num (%d)\n", pipenum);
+ }
+ 
+ static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
+@@ -186,7 +192,7 @@ static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum)
+ 		offset = get_pipectr_addr(pipenum);
+ 		ret = m66592_read(m66592, offset);
+ 	} else
+-		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
++		pr_err("unexpect pipe num (%d)\n", pipenum);
+ 
+ 	return ret;
+ }
+@@ -203,7 +209,7 @@ static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum)
+ 		offset = get_pipectr_addr(pipenum);
+ 		m66592_bset(m66592, M66592_SQCLR, offset);
+ 	} else
+-		printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
++		pr_err("unexpect pipe num(%d)\n", pipenum);
+ }
+ 
+ static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
+@@ -285,7 +291,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
+ 		break;
+ 	}
+ 	if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
+-		printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
++		pr_err("m66592 pipe memory is insufficient(%d)\n",
+ 				m66592->bi_bufnum);
+ 		return -ENOMEM;
+ 	}
+@@ -326,7 +332,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
+ 		if (info->type == M66592_BULK)
+ 			m66592->bulk--;
+ 	} else
+-		printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
++		pr_err("ep_release: unexpect pipenum (%d)\n",
+ 				info->pipe);
+ }
+ 
+@@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
+ 			ep->fifosel = M66592_D0FIFOSEL;
+ 			ep->fifoctr = M66592_D0FIFOCTR;
+ 			ep->fifotrn = M66592_D0FIFOTRN;
++#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
+ 		} else if (m66592->num_dma == 1) {
+ 			m66592->num_dma++;
+ 			ep->use_dma = 1;
+@@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
+ 			ep->fifosel = M66592_D1FIFOSEL;
+ 			ep->fifoctr = M66592_D1FIFOCTR;
+ 			ep->fifotrn = M66592_D1FIFOTRN;
++#endif
+ 		} else {
+ 			ep->use_dma = 0;
+ 			ep->fifoaddr = M66592_CFIFO;
+@@ -422,7 +430,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
+ 	case USB_ENDPOINT_XFER_BULK:
+ 		if (m66592->bulk >= M66592_MAX_NUM_BULK) {
+ 			if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+-				printk(KERN_ERR "bulk pipe is insufficient\n");
++				pr_err("bulk pipe is insufficient\n");
+ 				return -ENODEV;
+ 			} else {
+ 				info.pipe = M66592_BASE_PIPENUM_ISOC
+@@ -438,7 +446,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
+ 		break;
+ 	case USB_ENDPOINT_XFER_INT:
+ 		if (m66592->interrupt >= M66592_MAX_NUM_INT) {
+-			printk(KERN_ERR "interrupt pipe is insufficient\n");
++			pr_err("interrupt pipe is insufficient\n");
+ 			return -ENODEV;
+ 		}
+ 		info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
+@@ -447,7 +455,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
+ 		break;
+ 	case USB_ENDPOINT_XFER_ISOC:
+ 		if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+-			printk(KERN_ERR "isochronous pipe is insufficient\n");
++			pr_err("isochronous pipe is insufficient\n");
+ 			return -ENODEV;
+ 		}
+ 		info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
+@@ -455,7 +463,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
+ 		counter = &m66592->isochronous;
+ 		break;
+ 	default:
+-		printk(KERN_ERR "unexpect xfer type\n");
++		pr_err("unexpect xfer type\n");
+ 		return -EINVAL;
+ 	}
+ 	ep->type = info.type;
+@@ -470,7 +478,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
+ 
+ 	ret = pipe_buffer_setting(m66592, &info);
+ 	if (ret < 0) {
+-		printk(KERN_ERR "pipe_buffer_setting fail\n");
++		pr_err("pipe_buffer_setting fail\n");
+ 		return ret;
+ 	}
+ 
+@@ -606,11 +614,33 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
+ 		control_end(ep->m66592, 0);
+ 		break;
+ 	default:
+-		printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
++		pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq);
+ 		break;
+ 	}
+ }
+ 
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++static void init_controller(struct m66592 *m66592)
++{
++	usbf_start_clock();
++	m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);		/* High spd */
++	m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
++	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
++	m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
++
++	/* This is a workaound for SH7722 2nd cut */
++	m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
++	m66592_bset(m66592, 0x1000, M66592_TESTMODE);
++	m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
++
++	m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
++
++	m66592_write(m66592, 0, M66592_CFBCFG);
++	m66592_write(m66592, 0, M66592_D0FBCFG);
++	m66592_bset(m66592, endian, M66592_CFBCFG);
++	m66592_bset(m66592, endian, M66592_D0FBCFG);
++}
++#else	/* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+ static void init_controller(struct m66592 *m66592)
+ {
+ 	m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+@@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592)
+ 	m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+ 			M66592_DMA0CFG);
+ }
++#endif	/* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+ 
+ static void disable_controller(struct m66592 *m66592)
+ {
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++	usbf_stop_clock();
++#else
+ 	m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+ 	udelay(1);
+ 	m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+@@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592)
+ 	m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+ 	udelay(1);
+ 	m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
++#endif
+ }
+ 
+ static void m66592_start_xclock(struct m66592 *m66592)
+ {
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++	usbf_start_clock();
++#else
+ 	u16 tmp;
+ 
+ 	tmp = m66592_read(m66592, M66592_SYSCFG);
+ 	if (!(tmp & M66592_XCKE))
+ 		m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
++#endif
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -709,7 +748,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+ 	do {
+ 		tmp = m66592_read(m66592, ep->fifoctr);
+ 		if (i++ > 100000) {
+-			printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
++			pr_err("pipe0 is busy. maybe cpu i/o bus "
+ 				"conflict. please power off this controller.");
+ 			return;
+ 		}
+@@ -759,7 +798,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+ 	if (unlikely((tmp & M66592_FRDY) == 0)) {
+ 		pipe_stop(m66592, pipenum);
+ 		pipe_irq_disable(m66592, pipenum);
+-		printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
++		pr_err("write fifo not ready. pipnum=%d\n", pipenum);
+ 		return;
+ 	}
+ 
+@@ -808,7 +847,7 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+ 		req->req.status = -EPIPE;
+ 		pipe_stop(m66592, pipenum);
+ 		pipe_irq_disable(m66592, pipenum);
+-		printk(KERN_ERR "read fifo not ready");
++		pr_err("read fifo not ready");
+ 		return;
+ 	}
+ 
+@@ -1063,7 +1102,7 @@ static void m66592_update_usb_speed(struct m66592 *m66592)
+ 		break;
+ 	default:
+ 		m66592->gadget.speed = USB_SPEED_UNKNOWN;
+-		printk(KERN_ERR "USB speed unknown\n");
++		pr_err("USB speed unknown\n");
+ 	}
+ }
+ 
+@@ -1122,7 +1161,7 @@ __acquires(m66592->lock)
+ 		control_end(m66592, 0);
+ 		break;
+ 	default:
+-		printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
++		pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ 		break;
+ 	}
+ }
+@@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
+ 	intsts0 = m66592_read(m66592, M66592_INTSTS0);
+ 	intenb0 = m66592_read(m66592, M66592_INTENB0);
+ 
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++	if (!intsts0 && !intenb0) {
++		/*
++		 * When USB clock stops, it cannot read register. Even if a
++		 * clock stops, the interrupt occurs. So this driver turn on
++		 * a clock by this timing and do re-reading of register.
++		 */
++		m66592_start_xclock(m66592);
++		intsts0 = m66592_read(m66592, M66592_INTSTS0);
++		intenb0 = m66592_read(m66592, M66592_INTENB0);
++	}
++#endif
++
+ 	savepipe = m66592_read(m66592, M66592_CFIFOSEL);
+ 
+ 	mask0 = intsts0 & intenb0;
+@@ -1409,13 +1461,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+ 
+ 	retval = device_add(&m66592->gadget.dev);
+ 	if (retval) {
+-		printk(KERN_ERR "device_add error (%d)\n", retval);
++		pr_err("device_add error (%d)\n", retval);
+ 		goto error;
+ 	}
+ 
+ 	retval = driver->bind (&m66592->gadget);
+ 	if (retval) {
+-		printk(KERN_ERR "bind to driver error (%d)\n", retval);
++		pr_err("bind to driver error (%d)\n", retval);
+ 		device_del(&m66592->gadget.dev);
+ 		goto error;
+ 	}
+@@ -1456,6 +1508,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ 	m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+ 
+ 	driver->unbind(&m66592->gadget);
++	m66592->gadget.dev.driver = NULL;
+ 
+ 	init_controller(m66592);
+ 	disable_controller(m66592);
+@@ -1485,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev)
+ 	iounmap(m66592->reg);
+ 	free_irq(platform_get_irq(pdev, 0), m66592);
+ 	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
++	usbf_stop_clock();
+ 	kfree(m66592);
+ 	return 0;
+ }
+@@ -1508,28 +1562,28 @@ static int __init m66592_probe(struct platform_device *pdev)
+ 			(char *)udc_name);
+ 	if (!res) {
+ 		ret = -ENODEV;
+-		printk(KERN_ERR "platform_get_resource_byname error.\n");
++		pr_err("platform_get_resource_byname error.\n");
+ 		goto clean_up;
+ 	}
+ 
+ 	irq = platform_get_irq(pdev, 0);
+ 	if (irq < 0) {
+ 		ret = -ENODEV;
+-		printk(KERN_ERR "platform_get_irq error.\n");
++		pr_err("platform_get_irq error.\n");
+ 		goto clean_up;
+ 	}
+ 
+ 	reg = ioremap(res->start, resource_len(res));
+ 	if (reg == NULL) {
+ 		ret = -ENOMEM;
+-		printk(KERN_ERR "ioremap error.\n");
++		pr_err("ioremap error.\n");
+ 		goto clean_up;
+ 	}
+ 
+ 	/* initialize ucd */
+ 	m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
+ 	if (m66592 == NULL) {
+-		printk(KERN_ERR "kzalloc error\n");
++		pr_err("kzalloc error\n");
+ 		goto clean_up;
+ 	}
+ 
+@@ -1555,7 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev)
+ 	ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ 			udc_name, m66592);
+ 	if (ret < 0) {
+-		printk(KERN_ERR "request_irq error (%d)\n", ret);
++		pr_err("request_irq error (%d)\n", ret);
+ 		goto clean_up;
+ 	}
+ 
+diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
+index bfa0c64..17b792b 100644
+--- a/drivers/usb/gadget/m66592-udc.h
++++ b/drivers/usb/gadget/m66592-udc.h
+@@ -72,6 +72,11 @@
+ #define   M66592_P_TST_J	 0x0001		/* PERI TEST J */
+ #define   M66592_P_TST_NORMAL	 0x0000		/* PERI Normal Mode */
+ 
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++#define M66592_CFBCFG		0x0A
++#define M66592_D0FBCFG		0x0C
++#define M66592_LITTLE		0x0100	/* b8: Little endian mode */
++#else
+ #define M66592_PINCFG		0x0A
+ #define M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
+ #define M66592_BIGEND		0x0100	/* b8: Big endian mode */
+@@ -91,6 +96,7 @@
+ #define M66592_PKTM		0x0020	/* b5: Packet mode */
+ #define M66592_DENDE		0x0010	/* b4: Dend enable */
+ #define M66592_OBUS		0x0004	/* b2: OUTbus mode */
++#endif	/* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+ 
+ #define M66592_CFIFO		0x10
+ #define M66592_D0FIFO		0x14
+@@ -103,9 +109,13 @@
+ #define M66592_REW		0x4000	/* b14: Buffer rewind */
+ #define M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
+ #define M66592_DREQE		0x1000	/* b12: DREQ output enable */
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++#define M66592_MBW		0x0800	/* b11: Maximum bit width for FIFO */
++#else
+ #define M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO */
+ #define   M66592_MBW_8		 0x0000   /*  8bit */
+ #define   M66592_MBW_16		 0x0400   /* 16bit */
++#endif	/* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+ #define M66592_TRENB		0x0200	/* b9: Transaction counter enable */
+ #define M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
+ #define M66592_DEZPM		0x0080	/* b7: Zero-length packet mode */
+@@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592,
+ {
+ 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+ 
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++	len = (len + 3) / 4;
++	insl(fifoaddr, buf, len);
++#else
+ 	len = (len + 1) / 2;
+ 	insw(fifoaddr, buf, len);
++#endif
+ }
+ 
+ static inline void m66592_write(struct m66592 *m66592, u16 val,
+@@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
+ 		void *buf, unsigned long len)
+ {
+ 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++	unsigned long count;
++	unsigned char *pb;
++	int i;
++
++	count = len / 4;
++	outsl(fifoaddr, buf, count);
++
++	if (len & 0x00000003) {
++		pb = buf + count * 4;
++		for (i = 0; i < (len & 0x00000003); i++) {
++			if (m66592_read(m66592, M66592_CFBCFG))	/* little */
++				outb(pb[i], fifoaddr + (3 - i));
++			else
++				outb(pb[i], fifoaddr + i);
++		}
++	}
++#else
+ 	unsigned long odd = len & 0x0001;
+ 
+ 	len = len / 2;
+@@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
+ 		unsigned char *p = buf + len*2;
+ 		outb(*p, fifoaddr);
+ 	}
++#endif	/* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+ }
+ 
+ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+@@ -570,6 +604,26 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+ #define m66592_bset(m66592, val, offset)	\
+ 			m66592_mdfy(m66592, val, 0, offset)
+ 
++#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
++#include <asm/io.h>
++#define MSTPCR2		0xA4150038	/* for SH7722 */
++#define MSTPCR2_USB	0x00000800
++
++static inline void usbf_start_clock(void)
++{
++	ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2);
++}
++
++static inline void usbf_stop_clock(void)
++{
++	ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2);
++}
++
++#else
++#define usbf_start_clock(x)
++#define usbf_stop_clock(x)
++#endif	/* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
++
+ #endif	/* ifndef __M66592_UDC_H__ */
+ 
+ 
+diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
+index d5d473f..33469cf 100644
+--- a/drivers/usb/gadget/net2280.c
++++ b/drivers/usb/gadget/net2280.c
+@@ -2435,7 +2435,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
+ 			break;
+ 		default:
+ delegate:
+-			VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
++			VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x "
+ 				"ep_cfg %08x\n",
+ 				u.r.bRequestType, u.r.bRequest,
+ 				w_value, w_index, w_length,
+diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
+index d377154..e6d68bd 100644
+--- a/drivers/usb/gadget/omap_udc.c
++++ b/drivers/usb/gadget/omap_udc.c
+@@ -4,6 +4,8 @@
+  * Copyright (C) 2004 Texas Instruments, Inc.
+  * Copyright (C) 2004-2005 David Brownell
+  *
++ * OMAP2 & DMA support by Kyungmin Park <kyungmin.park at samsung.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
+@@ -60,11 +62,6 @@
+ /* bulk DMA seems to be behaving for both IN and OUT */
+ #define	USE_DMA
+ 
+-/* FIXME: OMAP2 currently has some problem in DMA mode */
+-#ifdef CONFIG_ARCH_OMAP2
+-#undef USE_DMA
+-#endif
+-
+ /* ISO too */
+ #define	USE_ISO
+ 
+@@ -73,6 +70,8 @@
+ 
+ #define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+ 
++#define OMAP2_DMA_CH(ch)	(((ch) - 1) << 1)
++#define OMAP24XX_DMA(name, ch)	(OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
+ 
+ /*
+  * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
+@@ -571,20 +570,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
+ 	const int	sync_mode = cpu_is_omap15xx()
+ 				? OMAP_DMA_SYNC_FRAME
+ 				: OMAP_DMA_SYNC_ELEMENT;
++	int		dma_trigger = 0;
++
++	if (cpu_is_omap24xx())
++		dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
+ 
+ 	/* measure length in either bytes or packets */
+ 	if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
++			|| (cpu_is_omap24xx() && length < ep->maxpacket)
+ 			|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ 		txdma_ctrl = UDC_TXN_EOT | length;
+ 		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+-				length, 1, sync_mode, 0, 0);
++				length, 1, sync_mode, dma_trigger, 0);
+ 	} else {
+ 		length = min(length / ep->maxpacket,
+ 				(unsigned) UDC_TXN_TSC + 1);
+ 		txdma_ctrl = length;
+ 		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+ 				ep->ep.maxpacket >> 1, length, sync_mode,
+-				0, 0);
++				dma_trigger, 0);
+ 		length *= ep->maxpacket;
+ 	}
+ 	omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
+@@ -622,20 +626,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
+ 
+ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
+ {
+-	unsigned packets;
++	unsigned packets = req->req.length - req->req.actual;
++	int dma_trigger = 0;
++
++	if (cpu_is_omap24xx())
++		dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
+ 
+ 	/* NOTE:  we filtered out "short reads" before, so we know
+ 	 * the buffer has only whole numbers of packets.
++	 * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
+ 	 */
+-
+-	/* set up this DMA transfer, enable the fifo, start */
+-	packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
+-	packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+-	req->dma_bytes = packets * ep->ep.maxpacket;
+-	omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+-			ep->ep.maxpacket >> 1, packets,
+-			OMAP_DMA_SYNC_ELEMENT,
+-			0, 0);
++	if (cpu_is_omap24xx() && packets < ep->maxpacket) {
++		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
++				packets, 1, OMAP_DMA_SYNC_ELEMENT,
++				dma_trigger, 0);
++		req->dma_bytes = packets;
++	} else {
++		/* set up this DMA transfer, enable the fifo, start */
++		packets /= ep->ep.maxpacket;
++		packets = min(packets, (unsigned)UDC_RXN_TC + 1);
++		req->dma_bytes = packets * ep->ep.maxpacket;
++		omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
++				ep->ep.maxpacket >> 1, packets,
++				OMAP_DMA_SYNC_ELEMENT,
++				dma_trigger, 0);
++	}
+ 	omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
+ 		OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+ 		0, 0);
+@@ -743,6 +758,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+ {
+ 	u16	reg;
+ 	int	status, restart, is_in;
++	int	dma_channel;
+ 
+ 	is_in = ep->bEndpointAddress & USB_DIR_IN;
+ 	if (is_in)
+@@ -769,11 +785,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+ 	ep->dma_channel = channel;
+ 
+ 	if (is_in) {
+-		status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel,
++		if (cpu_is_omap24xx())
++			dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
++		else
++			dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
++		status = omap_request_dma(dma_channel,
+ 			ep->ep.name, dma_error, ep, &ep->lch);
+ 		if (status == 0) {
+ 			UDC_TXDMA_CFG_REG = reg;
+-			/* EMIFF */
++			/* EMIFF or SDRC */
+ 			omap_set_dma_src_burst_mode(ep->lch,
+ 						OMAP_DMA_DATA_BURST_4);
+ 			omap_set_dma_src_data_pack(ep->lch, 1);
+@@ -785,7 +805,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+ 				0, 0);
+ 		}
+ 	} else {
+-		status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
++		if (cpu_is_omap24xx())
++			dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
++		else
++			dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
++
++		status = omap_request_dma(dma_channel,
+ 			ep->ep.name, dma_error, ep, &ep->lch);
+ 		if (status == 0) {
+ 			UDC_RXDMA_CFG_REG = reg;
+@@ -795,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+ 				OMAP_DMA_AMODE_CONSTANT,
+ 				(unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+ 				0, 0);
+-			/* EMIFF */
++			/* EMIFF or SDRC */
+ 			omap_set_dma_dest_burst_mode(ep->lch,
+ 						OMAP_DMA_DATA_BURST_4);
+ 			omap_set_dma_dest_data_pack(ep->lch, 1);
+@@ -808,7 +833,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+ 		omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
+ 
+ 		/* channel type P: hw synch (fifo) */
+-		if (!cpu_is_omap15xx())
++		if (cpu_class_is_omap1() && !cpu_is_omap15xx())
+ 			OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
+ 	}
+ 
+@@ -926,11 +951,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+ 
+ 	/* this isn't bogus, but OMAP DMA isn't the only hardware to
+ 	 * have a hard time with partial packet reads...  reject it.
++	 * Except OMAP2 can handle the small packets.
+ 	 */
+ 	if (use_dma
+ 			&& ep->has_dma
+ 			&& ep->bEndpointAddress != 0
+ 			&& (ep->bEndpointAddress & USB_DIR_IN) == 0
++			&& !cpu_class_is_omap2()
+ 			&& (req->req.length % ep->ep.maxpacket) != 0) {
+ 		DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
+ 		return -EMSGSIZE;
+@@ -1001,7 +1028,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+ 
+ 				/* STATUS for zero length DATA stages is
+ 				 * always an IN ... even for IN transfers,
+-				 * a wierd case which seem to stall OMAP.
++				 * a weird case which seem to stall OMAP.
+ 				 */
+ 				UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
+ 				UDC_CTRL_REG = UDC_CLR_EP;
+diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
+index 1dc398b..c6b9cbc 100644
+--- a/drivers/usb/gadget/omap_udc.h
++++ b/drivers/usb/gadget/omap_udc.h
+@@ -182,21 +182,16 @@ struct omap_udc {
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-#ifdef DEBUG
+-#define DBG(stuff...)		printk(KERN_DEBUG "udc: " stuff)
+-#else
+-#define DBG(stuff...)		do{}while(0)
+-#endif
+-
+ #ifdef VERBOSE
+ #    define VDBG		DBG
+ #else
+ #    define VDBG(stuff...)	do{}while(0)
+ #endif
+ 
+-#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+-#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+-#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
++#define ERR(stuff...)		pr_err("udc: " stuff)
++#define WARN(stuff...)		pr_warning("udc: " stuff)
++#define INFO(stuff...)		pr_info("udc: " stuff)
++#define DBG(stuff...)		pr_debug("udc: " stuff)
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
+new file mode 100644
+index 0000000..9fdabc8
+--- /dev/null
++++ b/drivers/usb/gadget/printer.c
+@@ -0,0 +1,1592 @@
++/*
++ * printer.c -- Printer gadget driver
++ *
++ * Copyright (C) 2003-2005 David Brownell
++ * Copyright (C) 2006 Craig W. Nadler
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++#include <linux/fs.h>
++#include <linux/poll.h>
++#include <linux/types.h>
++#include <linux/ctype.h>
++#include <linux/cdev.h>
++
++#include <asm/byteorder.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <asm/system.h>
++#include <linux/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb/g_printer.h>
++
++#include "gadget_chips.h"
++
++#define DRIVER_DESC		"Printer Gadget"
++#define DRIVER_VERSION		"2007 OCT 06"
++
++static const char shortname [] = "printer";
++static const char driver_desc [] = DRIVER_DESC;
++
++static dev_t g_printer_devno;
++
++static struct class *usb_gadget_class;
++
++/*-------------------------------------------------------------------------*/
++
++struct printer_dev {
++	spinlock_t		lock;		/* lock this structure */
++	/* lock buffer lists during read/write calls */
++	spinlock_t		lock_printer_io;
++	struct usb_gadget	*gadget;
++	struct usb_request	*req;		/* for control responses */
++	u8			config;
++	s8			interface;
++	struct usb_ep		*in_ep, *out_ep;
++	const struct usb_endpoint_descriptor
++				*in, *out;
++	struct list_head	rx_reqs;	/* List of free RX structs */
++	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
++	struct list_head	rx_buffers;	/* List of completed xfers */
++	/* wait until there is data to be read. */
++	wait_queue_head_t	rx_wait;
++	struct list_head	tx_reqs;	/* List of free TX structs */
++	struct list_head	tx_reqs_active; /* List of Active TX xfers */
++	/* Wait until there are write buffers available to use. */
++	wait_queue_head_t	tx_wait;
++	/* Wait until all write buffers have been sent. */
++	wait_queue_head_t	tx_flush_wait;
++	struct usb_request	*current_rx_req;
++	size_t			current_rx_bytes;
++	u8			*current_rx_buf;
++	u8			printer_status;
++	u8			reset_printer;
++	struct class_device	*printer_class_dev;
++	struct cdev		printer_cdev;
++	struct device		*pdev;
++	u8			printer_cdev_open;
++	wait_queue_head_t	wait;
++};
++
++static struct printer_dev usb_printer_gadget;
++
++/*-------------------------------------------------------------------------*/
++
++/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
++ * Instead:  allocate your own, using normal USB-IF procedures.
++ */
++
++/* Thanks to NetChip Technologies for donating this product ID.
++ */
++#define PRINTER_VENDOR_NUM	0x0525		/* NetChip */
++#define PRINTER_PRODUCT_NUM	0xa4a8		/* Linux-USB Printer Gadget */
++
++/* Some systems will want different product identifers published in the
++ * device descriptor, either numbers or strings or both.  These string
++ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
++ */
++
++static ushort __initdata idVendor;
++module_param(idVendor, ushort, S_IRUGO);
++MODULE_PARM_DESC(idVendor, "USB Vendor ID");
++
++static ushort __initdata idProduct;
++module_param(idProduct, ushort, S_IRUGO);
++MODULE_PARM_DESC(idProduct, "USB Product ID");
++
++static ushort __initdata bcdDevice;
++module_param(bcdDevice, ushort, S_IRUGO);
++MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
++
++static char *__initdata iManufacturer;
++module_param(iManufacturer, charp, S_IRUGO);
++MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
++
++static char *__initdata iProduct;
++module_param(iProduct, charp, S_IRUGO);
++MODULE_PARM_DESC(iProduct, "USB Product string");
++
++static char *__initdata iSerialNum;
++module_param(iSerialNum, charp, S_IRUGO);
++MODULE_PARM_DESC(iSerialNum, "1");
++
++static char *__initdata iPNPstring;
++module_param(iPNPstring, charp, S_IRUGO);
++MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
++
++/* Number of requests to allocate per endpoint, not used for ep0. */
++static unsigned qlen = 10;
++module_param(qlen, uint, S_IRUGO|S_IWUSR);
++
++#define QLEN	qlen
++
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++#define DEVSPEED	USB_SPEED_HIGH
++#else   /* full speed (low speed doesn't do bulk) */
++#define DEVSPEED        USB_SPEED_FULL
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++#define xprintk(d, level, fmt, args...) \
++	printk(level "%s: " fmt, DRIVER_DESC, ## args)
++
++#ifdef DEBUG
++#define DBG(dev, fmt, args...) \
++	xprintk(dev, KERN_DEBUG, fmt, ## args)
++#else
++#define DBG(dev, fmt, args...) \
++	do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDBG(dev, fmt, args...) \
++	xprintk(dev, KERN_DEBUG, fmt, ## args)
++#else
++#define VDBG(dev, fmt, args...) \
++	do { } while (0)
++#endif /* VERBOSE */
++
++#define ERROR(dev, fmt, args...) \
++	xprintk(dev, KERN_ERR, fmt, ## args)
++#define WARN(dev, fmt, args...) \
++	xprintk(dev, KERN_WARNING, fmt, ## args)
++#define INFO(dev, fmt, args...) \
++	xprintk(dev, KERN_INFO, fmt, ## args)
++
++/*-------------------------------------------------------------------------*/
++
++/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
++ * ep0 implementation:  descriptors, config management, setup().
++ * also optional class-specific notification interrupt transfer.
++ */
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full) configuration
++ * descriptors are built on demand.
++ */
++
++#define STRING_MANUFACTURER		1
++#define STRING_PRODUCT			2
++#define STRING_SERIALNUM		3
++
++/* holds our biggest descriptor */
++#define USB_DESC_BUFSIZE		256
++#define USB_BUFSIZE			8192
++
++/* This device advertises one configuration. */
++#define DEV_CONFIG_VALUE		1
++#define	PRINTER_INTERFACE		0
++
++static struct usb_device_descriptor device_desc = {
++	.bLength =		sizeof device_desc,
++	.bDescriptorType =	USB_DT_DEVICE,
++	.bcdUSB =		__constant_cpu_to_le16(0x0200),
++	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
++	.bDeviceSubClass =	0,
++	.bDeviceProtocol =	0,
++	.idVendor =		__constant_cpu_to_le16(PRINTER_VENDOR_NUM),
++	.idProduct =		__constant_cpu_to_le16(PRINTER_PRODUCT_NUM),
++	.iManufacturer =	STRING_MANUFACTURER,
++	.iProduct =		STRING_PRODUCT,
++	.iSerialNumber =	STRING_SERIALNUM,
++	.bNumConfigurations =	1
++};
++
++static struct usb_otg_descriptor otg_desc = {
++	.bLength =		sizeof otg_desc,
++	.bDescriptorType =	USB_DT_OTG,
++	.bmAttributes =		USB_OTG_SRP
++};
++
++static struct usb_config_descriptor config_desc = {
++	.bLength =		sizeof config_desc,
++	.bDescriptorType =	USB_DT_CONFIG,
++
++	/* compute wTotalLength on the fly */
++	.bNumInterfaces =	1,
++	.bConfigurationValue =	DEV_CONFIG_VALUE,
++	.iConfiguration =	0,
++	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++	.bMaxPower =		1	/* Self-Powered */
++};
++
++static struct usb_interface_descriptor intf_desc = {
++	.bLength =		sizeof intf_desc,
++	.bDescriptorType =	USB_DT_INTERFACE,
++	.bInterfaceNumber =	PRINTER_INTERFACE,
++	.bNumEndpoints =	2,
++	.bInterfaceClass =	USB_CLASS_PRINTER,
++	.bInterfaceSubClass =	1,	/* Printer Sub-Class */
++	.bInterfaceProtocol =	2,	/* Bi-Directional */
++	.iInterface =		0
++};
++
++static struct usb_endpoint_descriptor fs_ep_in_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bEndpointAddress =	USB_DIR_IN,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK
++};
++
++static struct usb_endpoint_descriptor fs_ep_out_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bEndpointAddress =	USB_DIR_OUT,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK
++};
++
++static const struct usb_descriptor_header *fs_printer_function [11] = {
++	(struct usb_descriptor_header *) &otg_desc,
++	(struct usb_descriptor_header *) &intf_desc,
++	(struct usb_descriptor_header *) &fs_ep_in_desc,
++	(struct usb_descriptor_header *) &fs_ep_out_desc,
++	NULL
++};
++
++#ifdef	CONFIG_USB_GADGET_DUALSPEED
++
++/*
++ * usb 2.0 devices need to expose both high speed and full speed
++ * descriptors, unless they only run at full speed.
++ */
++
++static struct usb_endpoint_descriptor hs_ep_in_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize =	__constant_cpu_to_le16(512)
++};
++
++static struct usb_endpoint_descriptor hs_ep_out_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize =	__constant_cpu_to_le16(512)
++};
++
++static struct usb_qualifier_descriptor dev_qualifier = {
++	.bLength =		sizeof dev_qualifier,
++	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
++	.bcdUSB =		__constant_cpu_to_le16(0x0200),
++	.bDeviceClass =		USB_CLASS_PRINTER,
++	.bNumConfigurations =	1
++};
++
++static const struct usb_descriptor_header *hs_printer_function [11] = {
++	(struct usb_descriptor_header *) &otg_desc,
++	(struct usb_descriptor_header *) &intf_desc,
++	(struct usb_descriptor_header *) &hs_ep_in_desc,
++	(struct usb_descriptor_header *) &hs_ep_out_desc,
++	NULL
++};
++
++/* maxpacket and other transfer characteristics vary by speed. */
++#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
++
++#else
++
++/* if there's no high speed support, maxpacket doesn't change. */
++#define ep_desc(g, hs, fs) (((void)(g)), (fs))
++
++#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
++
++/*-------------------------------------------------------------------------*/
++
++/* descriptors that are built on-demand */
++
++static char				manufacturer [50];
++static char				product_desc [40] = DRIVER_DESC;
++static char				serial_num [40] = "1";
++static char				pnp_string [1024] =
++	"XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
++
++/* static strings, in UTF-8 */
++static struct usb_string		strings [] = {
++	{ STRING_MANUFACTURER,	manufacturer, },
++	{ STRING_PRODUCT,	product_desc, },
++	{ STRING_SERIALNUM,	serial_num, },
++	{  }		/* end of list */
++};
++
++static struct usb_gadget_strings	stringtab = {
++	.language	= 0x0409,	/* en-us */
++	.strings	= strings,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *
++printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
++{
++	struct usb_request	*req;
++
++	req = usb_ep_alloc_request(ep, gfp_flags);
++
++	if (req != NULL) {
++		req->length = len;
++		req->buf = kmalloc(len, gfp_flags);
++		if (req->buf == NULL) {
++			usb_ep_free_request(ep, req);
++			return NULL;
++		}
++	}
++
++	return req;
++}
++
++static void
++printer_req_free(struct usb_ep *ep, struct usb_request *req)
++{
++	if (ep != NULL && req != NULL) {
++		kfree(req->buf);
++		usb_ep_free_request(ep, req);
++	}
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void rx_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	struct printer_dev	*dev = ep->driver_data;
++	int			status = req->status;
++	unsigned long		flags;
++
++	spin_lock_irqsave(&dev->lock, flags);
++
++	list_del_init(&req->list);	/* Remode from Active List */
++
++	switch (status) {
++
++	/* normal completion */
++	case 0:
++		list_add_tail(&req->list, &dev->rx_buffers);
++		wake_up_interruptible(&dev->rx_wait);
++		DBG(dev, "G_Printer : rx length %d\n", req->actual);
++		break;
++
++	/* software-driven interface shutdown */
++	case -ECONNRESET:		/* unlink */
++	case -ESHUTDOWN:		/* disconnect etc */
++		VDBG(dev, "rx shutdown, code %d\n", status);
++		list_add(&req->list, &dev->rx_reqs);
++		break;
++
++	/* for hardware automagic (such as pxa) */
++	case -ECONNABORTED:		/* endpoint reset */
++		DBG(dev, "rx %s reset\n", ep->name);
++		list_add(&req->list, &dev->rx_reqs);
++		break;
++
++	/* data overrun */
++	case -EOVERFLOW:
++		/* FALLTHROUGH */
++
++	default:
++		DBG(dev, "rx status %d\n", status);
++		list_add(&req->list, &dev->rx_reqs);
++		break;
++	}
++	spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++static void tx_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	struct printer_dev	*dev = ep->driver_data;
++
++	switch (req->status) {
++	default:
++		VDBG(dev, "tx err %d\n", req->status);
++		/* FALLTHROUGH */
++	case -ECONNRESET:		/* unlink */
++	case -ESHUTDOWN:		/* disconnect etc */
++		break;
++	case 0:
++		break;
++	}
++
++	spin_lock(&dev->lock);
++	/* Take the request struct off the active list and put it on the
++	 * free list.
++	 */
++	list_del_init(&req->list);
++	list_add(&req->list, &dev->tx_reqs);
++	wake_up_interruptible(&dev->tx_wait);
++	if (likely(list_empty(&dev->tx_reqs_active)))
++		wake_up_interruptible(&dev->tx_flush_wait);
++
++	spin_unlock(&dev->lock);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++printer_open(struct inode *inode, struct file *fd)
++{
++	struct printer_dev	*dev;
++	unsigned long		flags;
++	int			ret = -EBUSY;
++
++	dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
++
++	spin_lock_irqsave(&dev->lock, flags);
++
++	if (!dev->printer_cdev_open) {
++		dev->printer_cdev_open = 1;
++		fd->private_data = dev;
++		ret = 0;
++		/* Change the printer status to show that it's on-line. */
++		dev->printer_status |= PRINTER_SELECTED;
++	}
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	DBG(dev, "printer_open returned %x\n", ret);
++
++	return ret;
++}
++
++static int
++printer_close(struct inode *inode, struct file *fd)
++{
++	struct printer_dev	*dev = fd->private_data;
++	unsigned long		flags;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	dev->printer_cdev_open = 0;
++	fd->private_data = NULL;
++	/* Change printer status to show that the printer is off-line. */
++	dev->printer_status &= ~PRINTER_SELECTED;
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	DBG(dev, "printer_close\n");
++
++	return 0;
++}
++
++static ssize_t
++printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
++{
++	struct printer_dev		*dev = fd->private_data;
++	unsigned long			flags;
++	size_t				size;
++	size_t				bytes_copied;
++	struct usb_request		*req;
++	/* This is a pointer to the current USB rx request. */
++	struct usb_request		*current_rx_req;
++	/* This is the number of bytes in the current rx buffer. */
++	size_t				current_rx_bytes;
++	/* This is a pointer to the current rx buffer. */
++	u8				*current_rx_buf;
++
++	if (len == 0)
++		return -EINVAL;
++
++	DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
++
++	spin_lock(&dev->lock_printer_io);
++	spin_lock_irqsave(&dev->lock, flags);
++
++	/* We will use this flag later to check if a printer reset happened
++	 * after we turn interrupts back on.
++	 */
++	dev->reset_printer = 0;
++
++	while (likely(!list_empty(&dev->rx_reqs))) {
++		int error;
++
++		req = container_of(dev->rx_reqs.next,
++				struct usb_request, list);
++		list_del_init(&req->list);
++
++		/* The USB Host sends us whatever amount of data it wants to
++		 * so we always set the length field to the full USB_BUFSIZE.
++		 * If the amount of data is more than the read() caller asked
++		 * for it will be stored in the request buffer until it is
++		 * asked for by read().
++		 */
++		req->length = USB_BUFSIZE;
++		req->complete = rx_complete;
++
++		error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
++		if (error) {
++			DBG(dev, "rx submit --> %d\n", error);
++			list_add(&req->list, &dev->rx_reqs);
++			break;
++		} else {
++			list_add(&req->list, &dev->rx_reqs_active);
++		}
++	}
++
++	bytes_copied = 0;
++	current_rx_req = dev->current_rx_req;
++	current_rx_bytes = dev->current_rx_bytes;
++	current_rx_buf = dev->current_rx_buf;
++	dev->current_rx_req = NULL;
++	dev->current_rx_bytes = 0;
++	dev->current_rx_buf = NULL;
++
++	/* Check if there is any data in the read buffers. Please note that
++	 * current_rx_bytes is the number of bytes in the current rx buffer.
++	 * If it is zero then check if there are any other rx_buffers that
++	 * are on the completed list. We are only out of data if all rx
++	 * buffers are empty.
++	 */
++	if ((current_rx_bytes == 0) &&
++			(likely(list_empty(&dev->rx_buffers)))) {
++		/* Turn interrupts back on before sleeping. */
++		spin_unlock_irqrestore(&dev->lock, flags);
++
++		/*
++		 * If no data is available check if this is a NON-Blocking
++		 * call or not.
++		 */
++		if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
++			spin_unlock(&dev->lock_printer_io);
++			return -EAGAIN;
++		}
++
++		/* Sleep until data is available */
++		wait_event_interruptible(dev->rx_wait,
++				(likely(!list_empty(&dev->rx_buffers))));
++		spin_lock_irqsave(&dev->lock, flags);
++	}
++
++	/* We have data to return then copy it to the caller's buffer.*/
++	while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
++			&& len) {
++		if (current_rx_bytes == 0) {
++			req = container_of(dev->rx_buffers.next,
++					struct usb_request, list);
++			list_del_init(&req->list);
++
++			if (req->actual && req->buf) {
++				current_rx_req = req;
++				current_rx_bytes = req->actual;
++				current_rx_buf = req->buf;
++			} else {
++				list_add(&req->list, &dev->rx_reqs);
++				continue;
++			}
++		}
++
++		/* Don't leave irqs off while doing memory copies */
++		spin_unlock_irqrestore(&dev->lock, flags);
++
++		if (len > current_rx_bytes)
++			size = current_rx_bytes;
++		else
++			size = len;
++
++		size -= copy_to_user(buf, current_rx_buf, size);
++		bytes_copied += size;
++		len -= size;
++		buf += size;
++
++		spin_lock_irqsave(&dev->lock, flags);
++
++		/* We've disconnected or reset free the req and buffer */
++		if (dev->reset_printer) {
++			printer_req_free(dev->out_ep, current_rx_req);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			spin_unlock(&dev->lock_printer_io);
++			return -EAGAIN;
++		}
++
++		/* If we not returning all the data left in this RX request
++		 * buffer then adjust the amount of data left in the buffer.
++		 * Othewise if we are done with this RX request buffer then
++		 * requeue it to get any incoming data from the USB host.
++		 */
++		if (size < current_rx_bytes) {
++			current_rx_bytes -= size;
++			current_rx_buf += size;
++		} else {
++			list_add(&current_rx_req->list, &dev->rx_reqs);
++			current_rx_bytes = 0;
++			current_rx_buf = NULL;
++			current_rx_req = NULL;
++		}
++	}
++
++	dev->current_rx_req = current_rx_req;
++	dev->current_rx_bytes = current_rx_bytes;
++	dev->current_rx_buf = current_rx_buf;
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++	spin_unlock(&dev->lock_printer_io);
++
++	DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
++
++	if (bytes_copied)
++		return bytes_copied;
++	else
++		return -EAGAIN;
++}
++
++static ssize_t
++printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
++{
++	struct printer_dev	*dev = fd->private_data;
++	unsigned long		flags;
++	size_t			size;	/* Amount of data in a TX request. */
++	size_t			bytes_copied = 0;
++	struct usb_request	*req;
++
++	DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
++
++	if (len == 0)
++		return -EINVAL;
++
++	spin_lock(&dev->lock_printer_io);
++	spin_lock_irqsave(&dev->lock, flags);
++
++	/* Check if a printer reset happens while we have interrupts on */
++	dev->reset_printer = 0;
++
++	/* Check if there is any available write buffers */
++	if (likely(list_empty(&dev->tx_reqs))) {
++		/* Turn interrupts back on before sleeping. */
++		spin_unlock_irqrestore(&dev->lock, flags);
++
++		/*
++		 * If write buffers are available check if this is
++		 * a NON-Blocking call or not.
++		 */
++		if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
++			spin_unlock(&dev->lock_printer_io);
++			return -EAGAIN;
++		}
++
++		/* Sleep until a write buffer is available */
++		wait_event_interruptible(dev->tx_wait,
++				(likely(!list_empty(&dev->tx_reqs))));
++		spin_lock_irqsave(&dev->lock, flags);
++	}
++
++	while (likely(!list_empty(&dev->tx_reqs)) && len) {
++
++		if (len > USB_BUFSIZE)
++			size = USB_BUFSIZE;
++		else
++			size = len;
++
++		req = container_of(dev->tx_reqs.next, struct usb_request,
++				list);
++		list_del_init(&req->list);
++
++		req->complete = tx_complete;
++		req->length = size;
++
++		/* Check if we need to send a zero length packet. */
++		if (len > size)
++			/* They will be more TX requests so no yet. */
++			req->zero = 0;
++		else
++			/* If the data amount is not a multple of the
++			 * maxpacket size then send a zero length packet.
++			 */
++			req->zero = ((len % dev->in_ep->maxpacket) == 0);
++
++		/* Don't leave irqs off while doing memory copies */
++		spin_unlock_irqrestore(&dev->lock, flags);
++
++		if (copy_from_user(req->buf, buf, size)) {
++			list_add(&req->list, &dev->tx_reqs);
++			spin_unlock(&dev->lock_printer_io);
++			return bytes_copied;
++		}
++
++		bytes_copied += size;
++		len -= size;
++		buf += size;
++
++		spin_lock_irqsave(&dev->lock, flags);
++
++		/* We've disconnected or reset so free the req and buffer */
++		if (dev->reset_printer) {
++			printer_req_free(dev->in_ep, req);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			spin_unlock(&dev->lock_printer_io);
++			return -EAGAIN;
++		}
++
++		if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
++			list_add(&req->list, &dev->tx_reqs);
++			spin_unlock_irqrestore(&dev->lock, flags);
++			spin_unlock(&dev->lock_printer_io);
++			return -EAGAIN;
++		}
++
++		list_add(&req->list, &dev->tx_reqs_active);
++
++	}
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++	spin_unlock(&dev->lock_printer_io);
++
++	DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
++
++	if (bytes_copied) {
++		return bytes_copied;
++	} else {
++		return -EAGAIN;
++	}
++}
++
++static int
++printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
++{
++	struct printer_dev	*dev = fd->private_data;
++	unsigned long		flags;
++	int			tx_list_empty;
++
++	spin_lock_irqsave(&dev->lock, flags);
++	tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	if (!tx_list_empty) {
++		/* Sleep until all data has been sent */
++		wait_event_interruptible(dev->tx_flush_wait,
++				(likely(list_empty(&dev->tx_reqs_active))));
++	}
++
++	return 0;
++}
++
++static unsigned int
++printer_poll(struct file *fd, poll_table *wait)
++{
++	struct printer_dev	*dev = fd->private_data;
++	unsigned long		flags;
++	int			status = 0;
++
++	poll_wait(fd, &dev->rx_wait, wait);
++	poll_wait(fd, &dev->tx_wait, wait);
++
++	spin_lock_irqsave(&dev->lock, flags);
++	if (likely(!list_empty(&dev->tx_reqs)))
++		status |= POLLOUT | POLLWRNORM;
++
++	if (likely(!list_empty(&dev->rx_buffers)))
++		status |= POLLIN | POLLRDNORM;
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	return status;
++}
++
++static int
++printer_ioctl(struct inode *inode, struct file *fd, unsigned int code,
++		unsigned long arg)
++{
++	struct printer_dev	*dev = fd->private_data;
++	unsigned long		flags;
++	int			status = 0;
++
++	DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
++
++	/* handle ioctls */
++
++	spin_lock_irqsave(&dev->lock, flags);
++
++	switch (code) {
++	case GADGET_GET_PRINTER_STATUS:
++		status = (int)dev->printer_status;
++		break;
++	case GADGET_SET_PRINTER_STATUS:
++		dev->printer_status = (u8)arg;
++		break;
++	default:
++		/* could not handle ioctl */
++		DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
++				code);
++		status = -ENOTTY;
++	}
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	return status;
++}
++
++/* used after endpoint configuration */
++static struct file_operations printer_io_operations = {
++	.owner =	THIS_MODULE,
++	.open =		printer_open,
++	.read =		printer_read,
++	.write =	printer_write,
++	.fsync =	printer_fsync,
++	.poll =		printer_poll,
++	.ioctl =	printer_ioctl,
++	.release =	printer_close
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int
++set_printer_interface(struct printer_dev *dev)
++{
++	int			result = 0;
++
++	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
++	dev->in_ep->driver_data = dev;
++
++	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
++	dev->out_ep->driver_data = dev;
++
++	result = usb_ep_enable(dev->in_ep, dev->in);
++	if (result != 0) {
++		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
++		goto done;
++	}
++
++	result = usb_ep_enable(dev->out_ep, dev->out);
++	if (result != 0) {
++		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
++		goto done;
++	}
++
++done:
++	/* on error, disable any endpoints  */
++	if (result != 0) {
++		(void) usb_ep_disable(dev->in_ep);
++		(void) usb_ep_disable(dev->out_ep);
++		dev->in = NULL;
++		dev->out = NULL;
++	}
++
++	/* caller is responsible for cleanup on error */
++	return result;
++}
++
++static void printer_reset_interface(struct printer_dev *dev)
++{
++	if (dev->interface < 0)
++		return;
++
++	DBG(dev, "%s\n", __FUNCTION__);
++
++	if (dev->in)
++		usb_ep_disable(dev->in_ep);
++
++	if (dev->out)
++		usb_ep_disable(dev->out_ep);
++
++	dev->interface = -1;
++}
++
++/* change our operational config.  must agree with the code
++ * that returns config descriptors, and altsetting code.
++ */
++static int
++printer_set_config(struct printer_dev *dev, unsigned number)
++{
++	int			result = 0;
++	struct usb_gadget	*gadget = dev->gadget;
++
++	if (gadget_is_sa1100(gadget) && dev->config) {
++		/* tx fifo is full, but we can't clear it...*/
++		INFO(dev, "can't change configurations\n");
++		return -ESPIPE;
++	}
++
++	switch (number) {
++	case DEV_CONFIG_VALUE:
++		result = 0;
++		break;
++	default:
++		result = -EINVAL;
++		/* FALL THROUGH */
++	case 0:
++		break;
++	}
++
++	if (result) {
++		usb_gadget_vbus_draw(dev->gadget,
++				dev->gadget->is_otg ? 8 : 100);
++	} else {
++		char *speed;
++		unsigned power;
++
++		power = 2 * config_desc.bMaxPower;
++		usb_gadget_vbus_draw(dev->gadget, power);
++
++		switch (gadget->speed) {
++		case USB_SPEED_FULL:	speed = "full"; break;
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++		case USB_SPEED_HIGH:	speed = "high"; break;
++#endif
++		default:		speed = "?"; break;
++		}
++
++		dev->config = number;
++		INFO(dev, "%s speed config #%d: %d mA, %s\n",
++				speed, number, power, driver_desc);
++	}
++	return result;
++}
++
++static int
++config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
++		int is_otg)
++{
++	int					len;
++	const struct usb_descriptor_header	**function;
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++	int					hs = (speed == USB_SPEED_HIGH);
++
++	if (type == USB_DT_OTHER_SPEED_CONFIG)
++		hs = !hs;
++
++	if (hs) {
++		function = hs_printer_function;
++	} else {
++		function = fs_printer_function;
++	}
++#else
++	function = fs_printer_function;
++#endif
++
++	if (index >= device_desc.bNumConfigurations)
++		return -EINVAL;
++
++	/* for now, don't advertise srp-only devices */
++	if (!is_otg)
++		function++;
++
++	len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
++			function);
++	if (len < 0)
++		return len;
++	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++	return len;
++}
++
++/* Change our operational Interface. */
++static int
++set_interface(struct printer_dev *dev, unsigned number)
++{
++	int			result = 0;
++
++	if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
++		/* tx fifo is full, but we can't clear it...*/
++		INFO(dev, "can't change interfaces\n");
++		return -ESPIPE;
++	}
++
++	/* Free the current interface */
++	switch (dev->interface) {
++	case PRINTER_INTERFACE:
++		printer_reset_interface(dev);
++		break;
++	}
++
++	switch (number) {
++	case PRINTER_INTERFACE:
++		result = set_printer_interface(dev);
++		if (result) {
++			printer_reset_interface(dev);
++		} else {
++			dev->interface = PRINTER_INTERFACE;
++		}
++		break;
++	default:
++		result = -EINVAL;
++		/* FALL THROUGH */
++	}
++
++	if (!result)
++		INFO(dev, "Using interface %x\n", number);
++
++	return result;
++}
++
++static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	if (req->status || req->actual != req->length)
++		DBG((struct printer_dev *) ep->driver_data,
++				"setup complete --> %d, %d/%d\n",
++				req->status, req->actual, req->length);
++}
++
++static void printer_soft_reset(struct printer_dev *dev)
++{
++	struct usb_request	*req;
++
++	INFO(dev, "Received Printer Reset Request\n");
++
++	if (usb_ep_disable(dev->in_ep))
++		DBG(dev, "Failed to disable USB in_ep\n");
++	if (usb_ep_disable(dev->out_ep))
++		DBG(dev, "Failed to disable USB out_ep\n");
++
++	if (dev->current_rx_req != NULL) {
++		list_add(&dev->current_rx_req->list, &dev->rx_reqs);
++		dev->current_rx_req = NULL;
++	}
++	dev->current_rx_bytes = 0;
++	dev->current_rx_buf = NULL;
++	dev->reset_printer = 1;
++
++	while (likely(!(list_empty(&dev->rx_buffers)))) {
++		req = container_of(dev->rx_buffers.next, struct usb_request,
++				list);
++		list_del_init(&req->list);
++		list_add(&req->list, &dev->rx_reqs);
++	}
++
++	while (likely(!(list_empty(&dev->rx_reqs_active)))) {
++		req = container_of(dev->rx_buffers.next, struct usb_request,
++				list);
++		list_del_init(&req->list);
++		list_add(&req->list, &dev->rx_reqs);
++	}
++
++	while (likely(!(list_empty(&dev->tx_reqs_active)))) {
++		req = container_of(dev->tx_reqs_active.next,
++				struct usb_request, list);
++		list_del_init(&req->list);
++		list_add(&req->list, &dev->tx_reqs);
++	}
++
++	if (usb_ep_enable(dev->in_ep, dev->in))
++		DBG(dev, "Failed to enable USB in_ep\n");
++	if (usb_ep_enable(dev->out_ep, dev->out))
++		DBG(dev, "Failed to enable USB out_ep\n");
++
++	wake_up_interruptible(&dev->tx_wait);
++	wake_up_interruptible(&dev->tx_flush_wait);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * The setup() callback implements all the ep0 functionality that's not
++ * handled lower down.
++ */
++static int
++printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++{
++	struct printer_dev	*dev = get_gadget_data(gadget);
++	struct usb_request	*req = dev->req;
++	int			value = -EOPNOTSUPP;
++	u16			wIndex = le16_to_cpu(ctrl->wIndex);
++	u16			wValue = le16_to_cpu(ctrl->wValue);
++	u16			wLength = le16_to_cpu(ctrl->wLength);
++
++	DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
++		ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
++
++	req->complete = printer_setup_complete;
++
++	switch (ctrl->bRequestType&USB_TYPE_MASK) {
++
++	case USB_TYPE_STANDARD:
++		switch (ctrl->bRequest) {
++
++		case USB_REQ_GET_DESCRIPTOR:
++			if (ctrl->bRequestType != USB_DIR_IN)
++				break;
++			switch (wValue >> 8) {
++
++			case USB_DT_DEVICE:
++				value = min(wLength, (u16) sizeof device_desc);
++				memcpy(req->buf, &device_desc, value);
++				break;
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++			case USB_DT_DEVICE_QUALIFIER:
++				if (!gadget->is_dualspeed)
++					break;
++				value = min(wLength,
++						(u16) sizeof dev_qualifier);
++				memcpy(req->buf, &dev_qualifier, value);
++				break;
++
++			case USB_DT_OTHER_SPEED_CONFIG:
++				if (!gadget->is_dualspeed)
++					break;
++				/* FALLTHROUGH */
++#endif /* CONFIG_USB_GADGET_DUALSPEED */
++			case USB_DT_CONFIG:
++				value = config_buf(gadget->speed, req->buf,
++						wValue >> 8,
++						wValue & 0xff,
++						gadget->is_otg);
++				if (value >= 0)
++					value = min(wLength, (u16) value);
++				break;
++
++			case USB_DT_STRING:
++				value = usb_gadget_get_string(&stringtab,
++						wValue & 0xff, req->buf);
++				if (value >= 0)
++					value = min(wLength, (u16) value);
++				break;
++			}
++			break;
++
++		case USB_REQ_SET_CONFIGURATION:
++			if (ctrl->bRequestType != 0)
++				break;
++			if (gadget->a_hnp_support)
++				DBG(dev, "HNP available\n");
++			else if (gadget->a_alt_hnp_support)
++				DBG(dev, "HNP needs a different root port\n");
++			value = printer_set_config(dev, wValue);
++			break;
++		case USB_REQ_GET_CONFIGURATION:
++			if (ctrl->bRequestType != USB_DIR_IN)
++				break;
++			*(u8 *)req->buf = dev->config;
++			value = min(wLength, (u16) 1);
++			break;
++
++		case USB_REQ_SET_INTERFACE:
++			if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
++					!dev->config)
++				break;
++
++			value = set_interface(dev, PRINTER_INTERFACE);
++			break;
++		case USB_REQ_GET_INTERFACE:
++			if (ctrl->bRequestType !=
++					(USB_DIR_IN|USB_RECIP_INTERFACE)
++					|| !dev->config)
++				break;
++
++			*(u8 *)req->buf = dev->interface;
++			value = min(wLength, (u16) 1);
++			break;
++
++		default:
++			goto unknown;
++		}
++		break;
++
++	case USB_TYPE_CLASS:
++		switch (ctrl->bRequest) {
++		case 0: /* Get the IEEE-1284 PNP String */
++			/* Only one printer interface is supported. */
++			if ((wIndex>>8) != PRINTER_INTERFACE)
++				break;
++
++			value = (pnp_string[0]<<8)|pnp_string[1];
++			memcpy(req->buf, pnp_string, value);
++			DBG(dev, "1284 PNP String: %x %s\n", value,
++					&pnp_string[2]);
++			break;
++
++		case 1: /* Get Port Status */
++			/* Only one printer interface is supported. */
++			if (wIndex != PRINTER_INTERFACE)
++				break;
++
++			*(u8 *)req->buf = dev->printer_status;
++			value = min(wLength, (u16) 1);
++			break;
++
++		case 2: /* Soft Reset */
++			/* Only one printer interface is supported. */
++			if (wIndex != PRINTER_INTERFACE)
++				break;
++
++			printer_soft_reset(dev);
++
++			value = 0;
++			break;
++
++		default:
++			goto unknown;
++		}
++		break;
++
++	default:
++unknown:
++		VDBG(dev,
++			"unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
++			ctrl->bRequestType, ctrl->bRequest,
++			wValue, wIndex, wLength);
++		break;
++	}
++
++	/* respond with data transfer before status phase? */
++	if (value >= 0) {
++		req->length = value;
++		req->zero = value < wLength
++				&& (value % gadget->ep0->maxpacket) == 0;
++		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
++		if (value < 0) {
++			DBG(dev, "ep_queue --> %d\n", value);
++			req->status = 0;
++			printer_setup_complete(gadget->ep0, req);
++		}
++	}
++
++	/* host either stalls (value < 0) or reports success */
++	return value;
++}
++
++static void
++printer_disconnect(struct usb_gadget *gadget)
++{
++	struct printer_dev	*dev = get_gadget_data(gadget);
++	unsigned long		flags;
++
++	DBG(dev, "%s\n", __FUNCTION__);
++
++	spin_lock_irqsave(&dev->lock, flags);
++
++	printer_reset_interface(dev);
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++static void
++printer_unbind(struct usb_gadget *gadget)
++{
++	struct printer_dev	*dev = get_gadget_data(gadget);
++	struct usb_request	*req;
++
++
++	DBG(dev, "%s\n", __FUNCTION__);
++
++	/* Remove sysfs files */
++	device_destroy(usb_gadget_class, g_printer_devno);
++
++	/* Remove Character Device */
++	cdev_del(&dev->printer_cdev);
++
++	/* we must already have been disconnected ... no i/o may be active */
++	WARN_ON(!list_empty(&dev->tx_reqs_active));
++	WARN_ON(!list_empty(&dev->rx_reqs_active));
++
++	/* Free all memory for this driver. */
++	while (!list_empty(&dev->tx_reqs)) {
++		req = container_of(dev->tx_reqs.next, struct usb_request,
++				list);
++		list_del(&req->list);
++		printer_req_free(dev->in_ep, req);
++	}
++
++	if (dev->current_rx_req != NULL);
++		printer_req_free(dev->out_ep, dev->current_rx_req);
++
++	while (!list_empty(&dev->rx_reqs)) {
++		req = container_of(dev->rx_reqs.next,
++				struct usb_request, list);
++		list_del(&req->list);
++		printer_req_free(dev->out_ep, req);
++	}
++
++	while (!list_empty(&dev->rx_buffers)) {
++		req = container_of(dev->rx_buffers.next,
++				struct usb_request, list);
++		list_del(&req->list);
++		printer_req_free(dev->out_ep, req);
++	}
++
++	if (dev->req) {
++		printer_req_free(gadget->ep0, dev->req);
++		dev->req = NULL;
++	}
++
++	set_gadget_data(gadget, NULL);
++}
++
++static int __init
++printer_bind(struct usb_gadget *gadget)
++{
++	struct printer_dev	*dev;
++	struct usb_ep		*in_ep, *out_ep;
++	int			status = -ENOMEM;
++	int			gcnum;
++	size_t			len;
++	u32			i;
++	struct usb_request	*req;
++
++	dev = &usb_printer_gadget;
++
++
++	/* Setup the sysfs files for the printer gadget. */
++	dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
++			"g_printer");
++	if (IS_ERR(dev->pdev)) {
++		ERROR(dev, "Failed to create device: g_printer\n");
++		goto fail;
++	}
++
++	/*
++	 * Register a character device as an interface to a user mode
++	 * program that handles the printer specific functionality.
++	 */
++	cdev_init(&dev->printer_cdev, &printer_io_operations);
++	dev->printer_cdev.owner = THIS_MODULE;
++	status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
++	if (status) {
++		ERROR(dev, "Failed to open char device\n");
++		goto fail;
++	}
++
++	if (gadget_is_sa1100(gadget)) {
++		/* hardware can't write zero length packets. */
++		ERROR(dev, "SA1100 controller is unsupport by this driver\n");
++		goto fail;
++	}
++
++	gcnum = usb_gadget_controller_number(gadget);
++	if (gcnum >= 0) {
++		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
++	} else {
++		dev_warn(&gadget->dev, "controller '%s' not recognized\n",
++			gadget->name);
++		/* unrecognized, but safe unless bulk is REALLY quirky */
++		device_desc.bcdDevice =
++			__constant_cpu_to_le16(0xFFFF);
++	}
++	snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
++		init_utsname()->sysname, init_utsname()->release,
++		gadget->name);
++
++	device_desc.idVendor =
++		__constant_cpu_to_le16(PRINTER_VENDOR_NUM);
++	device_desc.idProduct =
++		__constant_cpu_to_le16(PRINTER_PRODUCT_NUM);
++
++	/* support optional vendor/distro customization */
++	if (idVendor) {
++		if (!idProduct) {
++			dev_err(&gadget->dev, "idVendor needs idProduct!\n");
++			return -ENODEV;
++		}
++		device_desc.idVendor = cpu_to_le16(idVendor);
++		device_desc.idProduct = cpu_to_le16(idProduct);
++		if (bcdDevice)
++			device_desc.bcdDevice = cpu_to_le16(bcdDevice);
++	}
++
++	if (iManufacturer)
++		strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
++
++	if (iProduct)
++		strlcpy(product_desc, iProduct, sizeof product_desc);
++
++	if (iSerialNum)
++		strlcpy(serial_num, iSerialNum, sizeof serial_num);
++
++	if (iPNPstring)
++		strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
++
++	len = strlen(pnp_string);
++	pnp_string[0] = (len >> 8) & 0xFF;
++	pnp_string[1] = len & 0xFF;
++
++	/* all we really need is bulk IN/OUT */
++	usb_ep_autoconfig_reset(gadget);
++	in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc);
++	if (!in_ep) {
++autoconf_fail:
++		dev_err(&gadget->dev, "can't autoconfigure on %s\n",
++			gadget->name);
++		return -ENODEV;
++	}
++	in_ep->driver_data = in_ep;	/* claim */
++
++	out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc);
++	if (!out_ep)
++		goto autoconf_fail;
++	out_ep->driver_data = out_ep;	/* claim */
++
++#ifdef	CONFIG_USB_GADGET_DUALSPEED
++	/* assumes ep0 uses the same value for both speeds ... */
++	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
++
++	/* and that all endpoints are dual-speed */
++	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
++	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
++#endif	/* DUALSPEED */
++
++	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++	usb_gadget_set_selfpowered(gadget);
++
++	if (gadget->is_otg) {
++		otg_desc.bmAttributes |= USB_OTG_HNP,
++		config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++		config_desc.bMaxPower = 4;
++	}
++
++	spin_lock_init(&dev->lock);
++	spin_lock_init(&dev->lock_printer_io);
++	INIT_LIST_HEAD(&dev->tx_reqs);
++	INIT_LIST_HEAD(&dev->tx_reqs_active);
++	INIT_LIST_HEAD(&dev->rx_reqs);
++	INIT_LIST_HEAD(&dev->rx_reqs_active);
++	INIT_LIST_HEAD(&dev->rx_buffers);
++	init_waitqueue_head(&dev->rx_wait);
++	init_waitqueue_head(&dev->tx_wait);
++	init_waitqueue_head(&dev->tx_flush_wait);
++
++	dev->config = 0;
++	dev->interface = -1;
++	dev->printer_cdev_open = 0;
++	dev->printer_status = PRINTER_NOT_ERROR;
++	dev->current_rx_req = NULL;
++	dev->current_rx_bytes = 0;
++	dev->current_rx_buf = NULL;
++
++	dev->in_ep = in_ep;
++	dev->out_ep = out_ep;
++
++	/* preallocate control message data and buffer */
++	dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
++			GFP_KERNEL);
++	if (!dev->req) {
++		status = -ENOMEM;
++		goto fail;
++	}
++
++	for (i = 0; i < QLEN; i++) {
++		req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
++		if (!req) {
++			while (!list_empty(&dev->tx_reqs)) {
++				req = container_of(dev->tx_reqs.next,
++						struct usb_request, list);
++				list_del(&req->list);
++				printer_req_free(dev->in_ep, req);
++			}
++			return -ENOMEM;
++		}
++		list_add(&req->list, &dev->tx_reqs);
++	}
++
++	for (i = 0; i < QLEN; i++) {
++		req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
++		if (!req) {
++			while (!list_empty(&dev->rx_reqs)) {
++				req = container_of(dev->rx_reqs.next,
++						struct usb_request, list);
++				list_del(&req->list);
++				printer_req_free(dev->out_ep, req);
++			}
++			return -ENOMEM;
++		}
++		list_add(&req->list, &dev->rx_reqs);
++	}
++
++	dev->req->complete = printer_setup_complete;
++
++	/* finish hookup to lower layer ... */
++	dev->gadget = gadget;
++	set_gadget_data(gadget, dev);
++	gadget->ep0->driver_data = dev;
++
++	INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
++	INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
++			in_ep->name);
++
++	return 0;
++
++fail:
++	printer_unbind(gadget);
++	return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver printer_driver = {
++	.speed		= DEVSPEED,
++
++	.function	= (char *) driver_desc,
++	.bind		= printer_bind,
++	.unbind		= printer_unbind,
++
++	.setup		= printer_setup,
++	.disconnect	= printer_disconnect,
++
++	.driver		= {
++		.name		= (char *) shortname,
++		.owner		= THIS_MODULE,
++	},
++};
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Craig Nadler");
++MODULE_LICENSE("GPL");
++
++static int __init
++init(void)
++{
++	int status;
++
++	usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
++	if (IS_ERR(usb_gadget_class)) {
++		status = PTR_ERR(usb_gadget_class);
++		ERROR(dev, "unable to create usb_gadget class %d\n", status);
++		return status;
++	}
++
++	status = alloc_chrdev_region(&g_printer_devno, 0, 1,
++			"USB printer gadget");
++	if (status) {
++		ERROR(dev, "alloc_chrdev_region %d\n", status);
++		class_destroy(usb_gadget_class);
++		return status;
++	}
++
++	status = usb_gadget_register_driver(&printer_driver);
++	if (status) {
++		class_destroy(usb_gadget_class);
++		unregister_chrdev_region(g_printer_devno, 1);
++		DBG(dev, "usb_gadget_register_driver %x\n", status);
++	}
++
++	return status;
++}
++module_init(init);
++
++static void __exit
++cleanup(void)
++{
++	int status;
++
++	spin_lock(&usb_printer_gadget.lock_printer_io);
++	class_destroy(usb_gadget_class);
++	unregister_chrdev_region(g_printer_devno, 2);
++
++	status = usb_gadget_unregister_driver(&printer_driver);
++	if (status)
++		ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
++
++	spin_unlock(&usb_printer_gadget.lock_printer_io);
++}
++module_exit(cleanup);
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+index 3173b39..4402d6f 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ b/drivers/usb/gadget/pxa2xx_udc.c
+@@ -24,7 +24,7 @@
+  *
+  */
+ 
+-// #define	VERBOSE	DBG_VERBOSE
++/* #define VERBOSE_DEBUG */
+ 
+ #include <linux/device.h>
+ #include <linux/module.h>
+@@ -38,13 +38,14 @@
+ #include <linux/timer.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+-#include <linux/proc_fs.h>
+ #include <linux/mm.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/irq.h>
+ #include <linux/clk.h>
+ #include <linux/err.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
+ 
+ #include <asm/byteorder.h>
+ #include <asm/dma.h>
+@@ -127,8 +128,10 @@ static int is_vbus_present(void)
+ {
+ 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
+ 
+-	if (mach->gpio_vbus)
+-		return gpio_get_value(mach->gpio_vbus);
++	if (mach->gpio_vbus) {
++		int value = gpio_get_value(mach->gpio_vbus);
++		return mach->gpio_vbus_inverted ? !value : value;
++	}
+ 	if (mach->udc_is_connected)
+ 		return mach->udc_is_connected();
+ 	return 1;
+@@ -677,7 +680,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+ 
+ 	/* kickstart this i/o queue? */
+ 	if (list_empty(&ep->queue) && !ep->stopped) {
+-		if (ep->desc == 0 /* ep0 */) {
++		if (ep->desc == NULL/* ep0 */) {
+ 			unsigned	length = _req->length;
+ 
+ 			switch (dev->ep0state) {
+@@ -731,7 +734,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+ 	}
+ 
+ 	/* pio or dma irq handler advances the queue. */
+-	if (likely (req != 0))
++	if (likely(req != NULL))
+ 		list_add_tail(&req->queue, &ep->queue);
+ 	local_irq_restore(flags);
+ 
+@@ -991,45 +994,32 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = {
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+-
+-static const char proc_node_name [] = "driver/udc";
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ 
+ static int
+-udc_proc_read(char *page, char **start, off_t off, int count,
+-		int *eof, void *_dev)
++udc_seq_show(struct seq_file *m, void *d)
+ {
+-	char			*buf = page;
+-	struct pxa2xx_udc	*dev = _dev;
+-	char			*next = buf;
+-	unsigned		size = count;
++	struct pxa2xx_udc	*dev = m->private;
+ 	unsigned long		flags;
+-	int			i, t;
++	int			i;
+ 	u32			tmp;
+ 
+-	if (off != 0)
+-		return 0;
+-
+ 	local_irq_save(flags);
+ 
+ 	/* basic device status */
+-	t = scnprintf(next, size, DRIVER_DESC "\n"
++	seq_printf(m, DRIVER_DESC "\n"
+ 		"%s version: %s\nGadget driver: %s\nHost %s\n\n",
+ 		driver_name, DRIVER_VERSION SIZE_STR "(pio)",
+ 		dev->driver ? dev->driver->driver.name : "(none)",
+ 		is_vbus_present() ? "full speed" : "disconnected");
+-	size -= t;
+-	next += t;
+ 
+ 	/* registers for device and ep0 */
+-	t = scnprintf(next, size,
++	seq_printf(m,
+ 		"uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+ 		UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+-	size -= t;
+-	next += t;
+ 
+ 	tmp = UDCCR;
+-	t = scnprintf(next, size,
++	seq_printf(m,
+ 		"udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
+ 		(tmp & UDCCR_REM) ? " rem" : "",
+ 		(tmp & UDCCR_RSTIR) ? " rstir" : "",
+@@ -1039,11 +1029,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+ 		(tmp & UDCCR_RSM) ? " rsm" : "",
+ 		(tmp & UDCCR_UDA) ? " uda" : "",
+ 		(tmp & UDCCR_UDE) ? " ude" : "");
+-	size -= t;
+-	next += t;
+ 
+ 	tmp = UDCCS0;
+-	t = scnprintf(next, size,
++	seq_printf(m,
+ 		"udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
+ 		(tmp & UDCCS0_SA) ? " sa" : "",
+ 		(tmp & UDCCS0_RNE) ? " rne" : "",
+@@ -1053,28 +1041,22 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+ 		(tmp & UDCCS0_FTF) ? " ftf" : "",
+ 		(tmp & UDCCS0_IPR) ? " ipr" : "",
+ 		(tmp & UDCCS0_OPR) ? " opr" : "");
+-	size -= t;
+-	next += t;
+ 
+ 	if (dev->has_cfr) {
+ 		tmp = UDCCFR;
+-		t = scnprintf(next, size,
++		seq_printf(m,
+ 			"udccfr %02X =%s%s\n", tmp,
+ 			(tmp & UDCCFR_AREN) ? " aren" : "",
+ 			(tmp & UDCCFR_ACM) ? " acm" : "");
+-		size -= t;
+-		next += t;
+ 	}
+ 
+ 	if (!is_vbus_present() || !dev->driver)
+ 		goto done;
+ 
+-	t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
++	seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+ 		dev->stats.write.bytes, dev->stats.write.ops,
+ 		dev->stats.read.bytes, dev->stats.read.ops,
+ 		dev->stats.irqs);
+-	size -= t;
+-	next += t;
+ 
+ 	/* dump endpoint queues */
+ 	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+@@ -1082,61 +1064,68 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+ 		struct pxa2xx_request	*req;
+ 
+ 		if (i != 0) {
+-			const struct usb_endpoint_descriptor	*d;
++			const struct usb_endpoint_descriptor	*desc;
+ 
+-			d = ep->desc;
+-			if (!d)
++			desc = ep->desc;
++			if (!desc)
+ 				continue;
+ 			tmp = *dev->ep [i].reg_udccs;
+-			t = scnprintf(next, size,
++			seq_printf(m,
+ 				"%s max %d %s udccs %02x irqs %lu\n",
+-				ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
++				ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
+ 				"pio", tmp, ep->pio_irqs);
+ 			/* TODO translate all five groups of udccs bits! */
+ 
+ 		} else /* ep0 should only have one transfer queued */
+-			t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",
++			seq_printf(m, "ep0 max 16 pio irqs %lu\n",
+ 				ep->pio_irqs);
+-		if (t <= 0 || t > size)
+-			goto done;
+-		size -= t;
+-		next += t;
+ 
+ 		if (list_empty(&ep->queue)) {
+-			t = scnprintf(next, size, "\t(nothing queued)\n");
+-			if (t <= 0 || t > size)
+-				goto done;
+-			size -= t;
+-			next += t;
++			seq_printf(m, "\t(nothing queued)\n");
+ 			continue;
+ 		}
+ 		list_for_each_entry(req, &ep->queue, queue) {
+-			t = scnprintf(next, size,
++			seq_printf(m,
+ 					"\treq %p len %d/%d buf %p\n",
+ 					&req->req, req->req.actual,
+ 					req->req.length, req->req.buf);
+-			if (t <= 0 || t > size)
+-				goto done;
+-			size -= t;
+-			next += t;
+ 		}
+ 	}
+ 
+ done:
+ 	local_irq_restore(flags);
+-	*eof = 1;
+-	return count - size;
++	return 0;
+ }
+ 
+-#define create_proc_files() \
+-	create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
+-#define remove_proc_files() \
+-	remove_proc_entry(proc_node_name, NULL)
++static int
++udc_debugfs_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, udc_seq_show, inode->i_private);
++}
++
++static const struct file_operations debug_fops = {
++	.open		= udc_debugfs_open,
++	.read		= seq_read,
++	.llseek		= seq_lseek,
++	.release	= single_release,
++	.owner		= THIS_MODULE,
++};
++
++#define create_debug_files(dev) \
++	do { \
++		dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
++			S_IRUGO, NULL, dev, &debug_fops); \
++	} while (0)
++#define remove_debug_files(dev) \
++	do { \
++		if (dev->debugfs_udc) \
++			debugfs_remove(dev->debugfs_udc); \
++	} while (0)
+ 
+ #else	/* !CONFIG_USB_GADGET_DEBUG_FILES */
+ 
+-#define create_proc_files() do {} while (0)
+-#define remove_proc_files() do {} while (0)
++#define create_debug_files(dev) do {} while (0)
++#define remove_debug_files(dev) do {} while (0)
+ 
+ #endif	/* CONFIG_USB_GADGET_DEBUG_FILES */
+ 
+@@ -1345,6 +1334,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ 	local_irq_enable();
+ 
+ 	driver->unbind(&dev->gadget);
++	dev->gadget.dev.driver = NULL;
+ 	dev->driver = NULL;
+ 
+ 	device_del (&dev->gadget.dev);
+@@ -1397,6 +1387,9 @@ static irqreturn_t udc_vbus_irq(int irq, void *_dev)
+ 	struct pxa2xx_udc	*dev = _dev;
+ 	int			vbus = gpio_get_value(dev->mach->gpio_vbus);
+ 
++	if (dev->mach->gpio_vbus_inverted)
++		vbus = !vbus;
++
+ 	pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+ 	return IRQ_HANDLED;
+ }
+@@ -2099,7 +2092,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+ 	/* insist on Intel/ARM/XScale */
+ 	asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
+ 	if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
+-		printk(KERN_ERR "%s: not XScale!\n", driver_name);
++		pr_err("%s: not XScale!\n", driver_name);
+ 		return -ENODEV;
+ 	}
+ 
+@@ -2128,7 +2121,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+ 		break;
+ #endif
+ 	default:
+-		printk(KERN_ERR "%s: unrecognized processor: %08x\n",
++		pr_err("%s: unrecognized processor: %08x\n",
+ 			driver_name, chiprev);
+ 		/* iop3xx, ixp4xx, ... */
+ 		return -ENODEV;
+@@ -2199,7 +2192,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+ 	retval = request_irq(irq, pxa2xx_udc_irq,
+ 			IRQF_DISABLED, driver_name, dev);
+ 	if (retval != 0) {
+-		printk(KERN_ERR "%s: can't get irq %d, err %d\n",
++		pr_err("%s: can't get irq %d, err %d\n",
+ 			driver_name, irq, retval);
+ 		goto err_irq1;
+ 	}
+@@ -2212,7 +2205,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
+ 				IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ 				driver_name, dev);
+ 		if (retval != 0) {
+-			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
++			pr_err("%s: can't get irq %i, err %d\n",
+ 				driver_name, LUBBOCK_USB_DISC_IRQ, retval);
+ lubbock_fail0:
+ 			goto err_irq_lub;
+@@ -2222,7 +2215,7 @@ lubbock_fail0:
+ 				IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ 				driver_name, dev);
+ 		if (retval != 0) {
+-			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
++			pr_err("%s: can't get irq %i, err %d\n",
+ 				driver_name, LUBBOCK_USB_IRQ, retval);
+ 			free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+ 			goto lubbock_fail0;
+@@ -2235,12 +2228,12 @@ lubbock_fail0:
+ 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ 				driver_name, dev);
+ 		if (retval != 0) {
+-			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
++			pr_err("%s: can't get irq %i, err %d\n",
+ 				driver_name, vbus_irq, retval);
+ 			goto err_vbus_irq;
+ 		}
+ 	}
+-	create_proc_files();
++	create_debug_files(dev);
+ 
+ 	return 0;
+ 
+@@ -2277,7 +2270,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
+ 		return -EBUSY;
+ 
+ 	udc_disable(dev);
+-	remove_proc_files();
++	remove_debug_files(dev);
+ 
+ 	if (dev->got_irq) {
+ 		free_irq(platform_get_irq(pdev, 0), dev);
+@@ -2361,7 +2354,7 @@ static struct platform_driver udc_driver = {
+ 
+ static int __init udc_init(void)
+ {
+-	printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
++	pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
+ 	return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
+ }
+ module_init(udc_init);
+diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
+index 1db46d7..b67e3ff 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.h
++++ b/drivers/usb/gadget/pxa2xx_udc.h
+@@ -129,6 +129,10 @@ struct pxa2xx_udc {
+ 	struct pxa2xx_udc_mach_info		*mach;
+ 	u64					dma_mask;
+ 	struct pxa2xx_ep			ep [PXA_UDC_NUM_ENDPOINTS];
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
++	struct dentry				*debugfs_udc;
++#endif
+ };
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -151,17 +155,19 @@ static struct pxa2xx_udc *the_controller;
+ #define DBG_NOISY	3	/* ... even more: request level */
+ #define DBG_VERY_NOISY	4	/* ... even more: packet level */
+ 
++#define DMSG(stuff...)	pr_debug("udc: " stuff)
++
+ #ifdef DEBUG
+ 
++static int is_vbus_present(void);
++
+ static const char *state_name[] = {
+ 	"EP0_IDLE",
+ 	"EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
+ 	"EP0_END_XFER", "EP0_STALL"
+ };
+ 
+-#define DMSG(stuff...) printk(KERN_DEBUG "udc: " stuff)
+-
+-#ifdef VERBOSE
++#ifdef VERBOSE_DEBUG
+ #    define UDC_DEBUG DBG_VERBOSE
+ #else
+ #    define UDC_DEBUG DBG_NORMAL
+@@ -207,7 +213,7 @@ dump_state(struct pxa2xx_udc *dev)
+ 	unsigned	i;
+ 
+ 	DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+-		is_usb_connected() ? "host " : "disconnected",
++		is_vbus_present() ? "host " : "disconnected",
+ 		state_name[dev->ep0state],
+ 		UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+ 	dump_udccr("udccr");
+@@ -224,7 +230,7 @@ dump_state(struct pxa2xx_udc *dev)
+ 	} else
+ 		DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
+ 
+-	if (!is_usb_connected())
++	if (!is_vbus_present())
+ 		return;
+ 
+ 	dump_udccs0 ("udccs0");
+@@ -233,7 +239,7 @@ dump_state(struct pxa2xx_udc *dev)
+ 		dev->stats.read.bytes, dev->stats.read.ops);
+ 
+ 	for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-		if (dev->ep [i].desc == 0)
++		if (dev->ep [i].desc == NULL)
+ 			continue;
+ 		DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
+ 	}
+@@ -241,8 +247,6 @@ dump_state(struct pxa2xx_udc *dev)
+ 
+ #else
+ 
+-#define DMSG(stuff...)		do{}while(0)
+-
+ #define	dump_udccr(x)	do{}while(0)
+ #define	dump_udccs0(x)	do{}while(0)
+ #define	dump_state(x)	do{}while(0)
+@@ -253,8 +257,9 @@ dump_state(struct pxa2xx_udc *dev)
+ 
+ #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
+ 
+-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
+-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
++#define ERR(stuff...)		pr_err("udc: " stuff)
++#define WARN(stuff...)		pr_warning("udc: " stuff)
++#define INFO(stuff...)		pr_info("udc: " stuff)
+ 
+ 
+ #endif /* __LINUX_USB_GADGET_PXA2XX_H */
+diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
+index db1b2bf..3d03664 100644
+--- a/drivers/usb/gadget/rndis.c
++++ b/drivers/usb/gadget/rndis.c
+@@ -53,21 +53,18 @@
+  */
+ 
+ #if 0
+-#define DBG(str,args...) do { \
+-	if (rndis_debug) \
+-		printk(KERN_DEBUG str , ## args ); \
+-	} while (0)
+ static int rndis_debug = 0;
+-
+ module_param (rndis_debug, int, 0);
+ MODULE_PARM_DESC (rndis_debug, "enable debugging");
+-
+ #else
+-
+ #define rndis_debug		0
+-#define DBG(str,args...)	do{}while(0)
+ #endif
+ 
++#define DBG(str,args...) do { \
++	if (rndis_debug) \
++		pr_debug(str , ## args); \
++	} while (0)
++
+ #define RNDIS_MAX_CONFIGS	1
+ 
+ 
+@@ -679,7 +676,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+ #endif
+ 
+ 	default:
+-		printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
++		pr_warning("%s: query unknown OID 0x%08X\n",
+ 			 __FUNCTION__, OID);
+ 	}
+ 	if (retval < 0)
+@@ -804,7 +801,7 @@ update_linkstate:
+ #endif	/* RNDIS_PM */
+ 
+ 	default:
+-		printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
++		pr_warning("%s: set unknown OID 0x%08X, size %d\n",
+ 			 __FUNCTION__, OID, buf_len);
+ 	}
+ 
+@@ -1126,8 +1123,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
+ 		 * In one case those messages seemed to relate to the host
+ 		 * suspending itself.
+ 		 */
+-		printk (KERN_WARNING
+-			"%s: unknown RNDIS message 0x%08X len %d\n",
++		pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
+ 			__FUNCTION__ , MsgType, MsgLength);
+ 		{
+ 			unsigned i;
+diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
+index 4ce050c..aadc420 100644
+--- a/drivers/usb/gadget/s3c2410_udc.c
++++ b/drivers/usb/gadget/s3c2410_udc.c
+@@ -893,7 +893,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+ /*
+  *	s3c2410_udc_irq - interrupt handler
+  */
+-static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
++static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
+ {
+ 	struct s3c2410_udc *dev = _dev;
+ 	int usb_status;
+@@ -1016,7 +1016,7 @@ static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+ 		}
+ 	}
+ 
+-	dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
++	dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
+ 
+ 	/* Restore old index */
+ 	udc_write(idx, S3C2410_UDC_INDEX_REG);
+diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
+index f5738eb..f5c3896 100644
+--- a/drivers/usb/gadget/serial.c
++++ b/drivers/usb/gadget/serial.c
+@@ -89,9 +89,9 @@ static int debug = 1;
+ #endif
+ 
+ #define gs_debug(format, arg...) \
+-	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
++	do { if (debug) pr_debug(format, ## arg); } while (0)
+ #define gs_debug_level(level, format, arg...) \
+-	do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
++	do { if (debug >= level) pr_debug(format, ## arg); } while (0)
+ 
+ 
+ /* Thanks to NetChip Technologies for donating this product ID.
+@@ -553,7 +553,8 @@ static int __init gs_module_init(void)
+ 
+ 	retval = usb_gadget_register_driver(&gs_gadget_driver);
+ 	if (retval) {
+-		printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval);
++		pr_err("gs_module_init: cannot register gadget driver, "
++			"ret=%d\n", retval);
+ 		return retval;
+ 	}
+ 
+@@ -579,11 +580,13 @@ static int __init gs_module_init(void)
+ 	if (retval) {
+ 		usb_gadget_unregister_driver(&gs_gadget_driver);
+ 		put_tty_driver(gs_tty_driver);
+-		printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval);
++		pr_err("gs_module_init: cannot register tty driver, "
++				"ret=%d\n", retval);
+ 		return retval;
+ 	}
+ 
+-	printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR);
++	pr_info("gs_module_init: %s %s loaded\n",
++			GS_LONG_NAME, GS_VERSION_STR);
+ 	return 0;
+ }
+ 
+@@ -598,7 +601,8 @@ static void __exit gs_module_exit(void)
+ 	put_tty_driver(gs_tty_driver);
+ 	usb_gadget_unregister_driver(&gs_gadget_driver);
+ 
+-	printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR);
++	pr_info("gs_module_exit: %s %s unloaded\n",
++			GS_LONG_NAME, GS_VERSION_STR);
+ }
+ 
+ /* TTY Driver */
+@@ -621,7 +625,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 	gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
+ 
+ 	if (port_num < 0 || port_num >= GS_NUM_PORTS) {
+-		printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
++		pr_err("gs_open: (%d,%p,%p) invalid port number\n",
+ 			port_num, tty, file);
+ 		return -ENODEV;
+ 	}
+@@ -629,15 +633,14 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 	dev = gs_device;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n",
++		pr_err("gs_open: (%d,%p,%p) NULL device pointer\n",
+ 			port_num, tty, file);
+ 		return -ENODEV;
+ 	}
+ 
+ 	mtx = &gs_open_close_lock[port_num];
+ 	if (mutex_lock_interruptible(mtx)) {
+-		printk(KERN_ERR
+-		"gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
++		pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
+ 			port_num, tty, file);
+ 		return -ERESTARTSYS;
+ 	}
+@@ -645,8 +648,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 	spin_lock_irqsave(&dev->dev_lock, flags);
+ 
+ 	if (dev->dev_config == GS_NO_CONFIG_ID) {
+-		printk(KERN_ERR
+-			"gs_open: (%d,%p,%p) device is not connected\n",
++		pr_err("gs_open: (%d,%p,%p) device is not connected\n",
+ 			port_num, tty, file);
+ 		ret = -ENODEV;
+ 		goto exit_unlock_dev;
+@@ -655,7 +657,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 	port = dev->dev_port[port_num];
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
++		pr_err("gs_open: (%d,%p,%p) NULL port pointer\n",
+ 			port_num, tty, file);
+ 		ret = -ENODEV;
+ 		goto exit_unlock_dev;
+@@ -665,7 +667,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 	spin_unlock(&dev->dev_lock);
+ 
+ 	if (port->port_dev == NULL) {
+-		printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
++		pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n",
+ 			port_num, tty, file);
+ 		ret = -EIO;
+ 		goto exit_unlock_port;
+@@ -692,8 +694,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 
+ 		/* might have been disconnected while asleep, check */
+ 		if (port->port_dev == NULL) {
+-			printk(KERN_ERR
+-				"gs_open: (%d,%p,%p) port disconnected (2)\n",
++			pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n",
+ 				port_num, tty, file);
+ 			port->port_in_use = 0;
+ 			ret = -EIO;
+@@ -701,7 +702,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 		}
+ 
+ 		if ((port->port_write_buf=buf) == NULL) {
+-			printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
++			pr_err("gs_open: (%d,%p,%p) cannot allocate "
++				"port write buffer\n",
+ 				port_num, tty, file);
+ 			port->port_in_use = 0;
+ 			ret = -ENOMEM;
+@@ -714,7 +716,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
+ 
+ 	/* might have been disconnected while asleep, check */
+ 	if (port->port_dev == NULL) {
+-		printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
++		pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n",
+ 			port_num, tty, file);
+ 		port->port_in_use = 0;
+ 		ret = -EIO;
+@@ -762,7 +764,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
+ 	struct mutex *mtx;
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_close: NULL port pointer\n");
++		pr_err("gs_close: NULL port pointer\n");
+ 		return;
+ 	}
+ 
+@@ -774,8 +776,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
+ 	spin_lock_irq(&port->port_lock);
+ 
+ 	if (port->port_open_count == 0) {
+-		printk(KERN_ERR
+-			"gs_close: (%d,%p,%p) port is already closed\n",
++		pr_err("gs_close: (%d,%p,%p) port is already closed\n",
+ 			port->port_num, tty, file);
+ 		goto exit;
+ 	}
+@@ -837,7 +838,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
+ 	int ret;
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_write: NULL port pointer\n");
++		pr_err("gs_write: NULL port pointer\n");
+ 		return -EIO;
+ 	}
+ 
+@@ -850,14 +851,14 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
+ 	spin_lock_irqsave(&port->port_lock, flags);
+ 
+ 	if (port->port_dev == NULL) {
+-		printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
++		pr_err("gs_write: (%d,%p) port is not connected\n",
+ 			port->port_num, tty);
+ 		ret = -EIO;
+ 		goto exit;
+ 	}
+ 
+ 	if (port->port_open_count == 0) {
+-		printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
++		pr_err("gs_write: (%d,%p) port is closed\n",
+ 			port->port_num, tty);
+ 		ret = -EBADF;
+ 		goto exit;
+@@ -888,7 +889,7 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+ 	struct gs_port *port = tty->driver_data;
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_put_char: NULL port pointer\n");
++		pr_err("gs_put_char: NULL port pointer\n");
+ 		return;
+ 	}
+ 
+@@ -898,13 +899,13 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+ 	spin_lock_irqsave(&port->port_lock, flags);
+ 
+ 	if (port->port_dev == NULL) {
+-		printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
++		pr_err("gs_put_char: (%d,%p) port is not connected\n",
+ 			port->port_num, tty);
+ 		goto exit;
+ 	}
+ 
+ 	if (port->port_open_count == 0) {
+-		printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
++		pr_err("gs_put_char: (%d,%p) port is closed\n",
+ 			port->port_num, tty);
+ 		goto exit;
+ 	}
+@@ -924,7 +925,7 @@ static void gs_flush_chars(struct tty_struct *tty)
+ 	struct gs_port *port = tty->driver_data;
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_flush_chars: NULL port pointer\n");
++		pr_err("gs_flush_chars: NULL port pointer\n");
+ 		return;
+ 	}
+ 
+@@ -933,14 +934,13 @@ static void gs_flush_chars(struct tty_struct *tty)
+ 	spin_lock_irqsave(&port->port_lock, flags);
+ 
+ 	if (port->port_dev == NULL) {
+-		printk(KERN_ERR
+-			"gs_flush_chars: (%d,%p) port is not connected\n",
++		pr_err("gs_flush_chars: (%d,%p) port is not connected\n",
+ 			port->port_num, tty);
+ 		goto exit;
+ 	}
+ 
+ 	if (port->port_open_count == 0) {
+-		printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
++		pr_err("gs_flush_chars: (%d,%p) port is closed\n",
+ 			port->port_num, tty);
+ 		goto exit;
+ 	}
+@@ -1038,7 +1038,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
+ 	struct gs_port *port = tty->driver_data;
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_ioctl: NULL port pointer\n");
++		pr_err("gs_ioctl: NULL port pointer\n");
+ 		return -EIO;
+ 	}
+ 
+@@ -1076,7 +1076,7 @@ static int gs_send(struct gs_dev *dev)
+ 	struct gs_req_entry *req_entry;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_send: NULL device pointer\n");
++		pr_err("gs_send: NULL device pointer\n");
+ 		return -ENODEV;
+ 	}
+ 
+@@ -1103,7 +1103,7 @@ static int gs_send(struct gs_dev *dev)
+ 			req->length = len;
+ 			spin_unlock_irqrestore(&dev->dev_lock, flags);
+ 			if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-				printk(KERN_ERR
++				pr_err(
+ 				"gs_send: cannot queue read request, ret=%d\n",
+ 					ret);
+ 				spin_lock_irqsave(&dev->dev_lock, flags);
+@@ -1144,9 +1144,7 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size)
+ 	port = dev->dev_port[0];
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR
+-			"gs_send_packet: port=%d, NULL port pointer\n",
+-			0);
++		pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0);
+ 		return -EIO;
+ 	}
+ 
+@@ -1193,7 +1191,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
+ 	port = dev->dev_port[0];
+ 
+ 	if (port == NULL) {
+-		printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n",
++		pr_err("gs_recv_packet: port=%d, NULL port pointer\n",
+ 			port->port_num);
+ 		return -EIO;
+ 	}
+@@ -1201,7 +1199,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
+ 	spin_lock(&port->port_lock);
+ 
+ 	if (port->port_open_count == 0) {
+-		printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
++		pr_err("gs_recv_packet: port=%d, port is closed\n",
+ 			port->port_num);
+ 		ret = -EIO;
+ 		goto exit;
+@@ -1211,14 +1209,14 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
+ 	tty = port->port_tty;
+ 
+ 	if (tty == NULL) {
+-		printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
++		pr_err("gs_recv_packet: port=%d, NULL tty pointer\n",
+ 			port->port_num);
+ 		ret = -EIO;
+ 		goto exit;
+ 	}
+ 
+ 	if (port->port_tty->magic != TTY_MAGIC) {
+-		printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
++		pr_err("gs_recv_packet: port=%d, bad tty magic\n",
+ 			port->port_num);
+ 		ret = -EIO;
+ 		goto exit;
+@@ -1245,7 +1243,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
+ 	struct gs_dev *dev = ep->driver_data;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_read_complete: NULL device pointer\n");
++		pr_err("gs_read_complete: NULL device pointer\n");
+ 		return;
+ 	}
+ 
+@@ -1256,7 +1254,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
+ requeue:
+ 		req->length = ep->maxpacket;
+ 		if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-			printk(KERN_ERR
++			pr_err(
+ 			"gs_read_complete: cannot queue read request, ret=%d\n",
+ 				ret);
+ 		}
+@@ -1270,7 +1268,7 @@ requeue:
+ 
+ 	default:
+ 		/* unexpected */
+-		printk(KERN_ERR
++		pr_err(
+ 		"gs_read_complete: unexpected status error, status=%d\n",
+ 			req->status);
+ 		goto requeue;
+@@ -1287,7 +1285,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
+ 	struct gs_req_entry *gs_req = req->context;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_write_complete: NULL device pointer\n");
++		pr_err("gs_write_complete: NULL device pointer\n");
+ 		return;
+ 	}
+ 
+@@ -1296,8 +1294,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
+ 		/* normal completion */
+ requeue:
+ 		if (gs_req == NULL) {
+-			printk(KERN_ERR
+-				"gs_write_complete: NULL request pointer\n");
++			pr_err("gs_write_complete: NULL request pointer\n");
+ 			return;
+ 		}
+ 
+@@ -1316,7 +1313,7 @@ requeue:
+ 		break;
+ 
+ 	default:
+-		printk(KERN_ERR
++		pr_err(
+ 		"gs_write_complete: unexpected status error, status=%d\n",
+ 			req->status);
+ 		goto requeue;
+@@ -1351,7 +1348,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
+ 		gs_device_desc.bcdDevice =
+ 				cpu_to_le16(GS_VERSION_NUM | gcnum);
+ 	else {
+-		printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
++		pr_warning("gs_bind: controller '%s' not recognized\n",
+ 			gadget->name);
+ 		/* unrecognized, but safe unless bulk is REALLY quirky */
+ 		gs_device_desc.bcdDevice =
+@@ -1375,7 +1372,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
+ 	if (use_acm) {
+ 		ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
+ 		if (!ep) {
+-			printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
++			pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
+ 			goto autoconf_fail;
+ 		}
+ 		gs_device_desc.idProduct = __constant_cpu_to_le16(
+@@ -1425,7 +1422,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
+ 	set_gadget_data(gadget, dev);
+ 
+ 	if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) {
+-		printk(KERN_ERR "gs_bind: cannot allocate ports\n");
++		pr_err("gs_bind: cannot allocate ports\n");
+ 		gs_unbind(gadget);
+ 		return ret;
+ 	}
+@@ -1441,13 +1438,13 @@ static int __init gs_bind(struct usb_gadget *gadget)
+ 
+ 	gadget->ep0->driver_data = dev;
+ 
+-	printk(KERN_INFO "gs_bind: %s %s bound\n",
++	pr_info("gs_bind: %s %s bound\n",
+ 		GS_LONG_NAME, GS_VERSION_STR);
+ 
+ 	return 0;
+ 
+ autoconf_fail:
+-	printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name);
++	pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
+ 	return -ENODEV;
+ }
+ 
+@@ -1480,7 +1477,7 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
+ 		set_gadget_data(gadget, NULL);
+ 	}
+ 
+-	printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME,
++	pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+ 		GS_VERSION_STR);
+ }
+ 
+@@ -1513,7 +1510,8 @@ static int gs_setup(struct usb_gadget *gadget,
+ 		break;
+ 
+ 	default:
+-		printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
++		pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
++			"value=%04x, index=%04x, length=%d\n",
+ 			ctrl->bRequestType, ctrl->bRequest,
+ 			wValue, wIndex, wLength);
+ 		break;
+@@ -1526,7 +1524,7 @@ static int gs_setup(struct usb_gadget *gadget,
+ 				&& (ret % gadget->ep0->maxpacket) == 0;
+ 		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ 		if (ret < 0) {
+-			printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n",
++			pr_err("gs_setup: cannot queue response, ret=%d\n",
+ 				ret);
+ 			req->status = 0;
+ 			gs_setup_complete(gadget->ep0, req);
+@@ -1656,7 +1654,8 @@ set_interface_done:
+ 		break;
+ 
+ 	default:
+-		printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
++		pr_err("gs_setup: unknown standard request, type=%02x, "
++			"request=%02x, value=%04x, index=%04x, length=%d\n",
+ 			ctrl->bRequestType, ctrl->bRequest,
+ 			wValue, wIndex, wLength);
+ 		break;
+@@ -1682,7 +1681,7 @@ static int gs_setup_class(struct usb_gadget *gadget,
+ 		 * handler copy that data to port->port_line_coding (iff
+ 		 * it's valid) and maybe pass it on.  Until then, fail.
+ 		 */
+-		printk(KERN_WARNING "gs_setup: set_line_coding "
++		pr_warning("gs_setup: set_line_coding "
+ 				"unuspported\n");
+ 		break;
+ 
+@@ -1702,12 +1701,12 @@ static int gs_setup_class(struct usb_gadget *gadget,
+ 		 * handler use that to set the state (iff it's valid) and
+ 		 * maybe pass it on.  Until then, fail.
+ 		 */
+-		printk(KERN_WARNING "gs_setup: set_control_line_state "
++		pr_warning("gs_setup: set_control_line_state "
+ 				"unuspported\n");
+ 		break;
+ 
+ 	default:
+-		printk(KERN_ERR "gs_setup: unknown class request, "
++		pr_err("gs_setup: unknown class request, "
+ 				"type=%02x, request=%02x, value=%04x, "
+ 				"index=%04x, length=%d\n",
+ 			ctrl->bRequestType, ctrl->bRequest,
+@@ -1724,7 +1723,8 @@ static int gs_setup_class(struct usb_gadget *gadget,
+ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
+ {
+ 	if (req->status || req->actual != req->length) {
+-		printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n",
++		pr_err("gs_setup_complete: status error, status=%d, "
++			"actual=%d, length=%d\n",
+ 			req->status, req->actual, req->length);
+ 	}
+ }
+@@ -1751,11 +1751,11 @@ static void gs_disconnect(struct usb_gadget *gadget)
+ 
+ 	/* re-allocate ports for the next connection */
+ 	if (gs_alloc_ports(dev, GFP_ATOMIC) != 0)
+-		printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n");
++		pr_err("gs_disconnect: cannot re-allocate ports\n");
+ 
+ 	spin_unlock_irqrestore(&dev->dev_lock, flags);
+ 
+-	printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME);
++	pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+ }
+ 
+ /*
+@@ -1778,7 +1778,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 	struct gs_req_entry *req_entry;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_set_config: NULL device pointer\n");
++		pr_err("gs_set_config: NULL device pointer\n");
+ 		return 0;
+ 	}
+ 
+@@ -1823,7 +1823,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 				dev->dev_notify_ep = ep;
+ 				dev->dev_notify_ep_desc = ep_desc;
+ 			} else {
+-				printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n",
++				pr_err("gs_set_config: cannot enable NOTIFY "
++					"endpoint %s, ret=%d\n",
+ 					ep->name, ret);
+ 				goto exit_reset_config;
+ 			}
+@@ -1839,7 +1840,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 				dev->dev_in_ep = ep;
+ 				dev->dev_in_ep_desc = ep_desc;
+ 			} else {
+-				printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
++				pr_err("gs_set_config: cannot enable IN "
++					"endpoint %s, ret=%d\n",
+ 					ep->name, ret);
+ 				goto exit_reset_config;
+ 			}
+@@ -1855,7 +1857,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 				dev->dev_out_ep = ep;
+ 				dev->dev_out_ep_desc = ep_desc;
+ 			} else {
+-				printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
++				pr_err("gs_set_config: cannot enable OUT "
++					"endpoint %s, ret=%d\n",
+ 					ep->name, ret);
+ 				goto exit_reset_config;
+ 			}
+@@ -1865,7 +1868,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 
+ 	if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
+ 	|| (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
+-		printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
++		pr_err("gs_set_config: cannot find endpoints\n");
+ 		ret = -ENODEV;
+ 		goto exit_reset_config;
+ 	}
+@@ -1876,11 +1879,12 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 		if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
+ 			req->complete = gs_read_complete;
+ 			if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
+-				printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n",
+-					ret);
++				pr_err("gs_set_config: cannot queue read "
++					"request, ret=%d\n", ret);
+ 			}
+ 		} else {
+-			printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
++			pr_err("gs_set_config: cannot allocate "
++					"read requests\n");
+ 			ret = -ENOMEM;
+ 			goto exit_reset_config;
+ 		}
+@@ -1893,13 +1897,14 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
+ 			req_entry->re_req->complete = gs_write_complete;
+ 			list_add(&req_entry->re_entry, &dev->dev_req_list);
+ 		} else {
+-			printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
++			pr_err("gs_set_config: cannot allocate "
++					"write requests\n");
+ 			ret = -ENOMEM;
+ 			goto exit_reset_config;
+ 		}
+ 	}
+ 
+-	printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
++	pr_info("gs_set_config: %s configured, %s speed %s config\n",
+ 		GS_LONG_NAME,
+ 		gadget->speed == USB_SPEED_HIGH ? "high" : "full",
+ 		config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
+@@ -1926,7 +1931,7 @@ static void gs_reset_config(struct gs_dev *dev)
+ 	struct gs_req_entry *req_entry;
+ 
+ 	if (dev == NULL) {
+-		printk(KERN_ERR "gs_reset_config: NULL device pointer\n");
++		pr_err("gs_reset_config: NULL device pointer\n");
+ 		return;
+ 	}
+ 
+diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
+index fcde5d9..d3d4f40 100644
+--- a/drivers/usb/gadget/zero.c
++++ b/drivers/usb/gadget/zero.c
+@@ -1115,7 +1115,7 @@ zero_bind (struct usb_gadget *gadget)
+ 	ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+ 	if (!ep) {
+ autoconf_fail:
+-		printk (KERN_ERR "%s: can't autoconfigure on %s\n",
++		pr_err("%s: can't autoconfigure on %s\n",
+ 			shortname, gadget->name);
+ 		return -ENODEV;
+ 	}
+@@ -1139,7 +1139,7 @@ autoconf_fail:
+ 		 * things like configuration and altsetting numbering
+ 		 * can need hardware-specific attention though.
+ 		 */
+-		printk (KERN_WARNING "%s: controller '%s' not recognized\n",
++		pr_warning("%s: controller '%s' not recognized\n",
+ 			shortname, gadget->name);
+ 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+ 	}
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 49a91c5..d97b16b 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -29,15 +29,6 @@ config USB_EHCI_HCD
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ehci-hcd.
+ 
+-config USB_EHCI_SPLIT_ISO
+-	bool "Full speed ISO transactions (EXPERIMENTAL)"
+-	depends on USB_EHCI_HCD && EXPERIMENTAL
+-	default n
+-	---help---
+-	  This code is new and hasn't been used with many different
+-	  EHCI or USB 2.0 transaction translator implementations.
+-	  It should work for ISO-OUT transfers, like audio.
+-
+ config USB_EHCI_ROOT_HUB_TT
+ 	bool "Root Hub Transaction Translators (EXPERIMENTAL)"
+ 	depends on USB_EHCI_HCD && EXPERIMENTAL
+@@ -69,21 +60,30 @@ config USB_EHCI_TT_NEWSCHED
+ 
+ config USB_EHCI_BIG_ENDIAN_MMIO
+ 	bool
+-	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
++	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX)
+ 	default y
+ 
+ config USB_EHCI_BIG_ENDIAN_DESC
+ 	bool
+-	depends on USB_EHCI_HCD && 440EPX
++	depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX)
+ 	default y
+ 
+ config USB_EHCI_FSL
+ 	bool
++	depends on USB_EHCI_HCD
+ 	select USB_EHCI_ROOT_HUB_TT
+ 	default y if MPC834x || PPC_MPC831x
+ 	---help---
+ 	  Variation of ARC USB block used in some Freescale chips.
+ 
++config USB_EHCI_HCD_PPC_OF
++	bool "EHCI support for PPC USB controller on OF platform bus"
++	depends on USB_EHCI_HCD && PPC_OF
++	default y
++	---help---
++	  Enables support for the USB controller present on the PowerPC
++	  OpenFirmware platform bus.
++
+ config USB_ISP116X_HCD
+ 	tristate "ISP116X HCD support"
+ 	depends on USB
+diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
+index 766ef68..da7532d 100644
+--- a/drivers/usb/host/ehci-au1xxx.c
++++ b/drivers/usb/host/ehci-au1xxx.c
+@@ -222,6 +222,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
+ 	.hub_control = ehci_hub_control,
+ 	.bus_suspend = ehci_bus_suspend,
+ 	.bus_resume = ehci_bus_resume,
++	.relinquish_port = ehci_relinquish_port,
+ };
+ 
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
+index c9cc441..64ebfc5 100644
+--- a/drivers/usb/host/ehci-dbg.c
++++ b/drivers/usb/host/ehci-dbg.c
+@@ -323,7 +323,43 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
+ 
+ #else
+ 
+-/* troubleshooting help: expose state in sysfs */
++/* troubleshooting help: expose state in debugfs */
++
++static int debug_async_open(struct inode *, struct file *);
++static int debug_periodic_open(struct inode *, struct file *);
++static int debug_registers_open(struct inode *, struct file *);
++static int debug_async_open(struct inode *, struct file *);
++static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
++static int debug_close(struct inode *, struct file *);
++
++static const struct file_operations debug_async_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_async_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++static const struct file_operations debug_periodic_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_periodic_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++static const struct file_operations debug_registers_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_registers_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++
++static struct dentry *ehci_debug_root;
++
++struct debug_buffer {
++	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
++	struct usb_bus *bus;
++	struct mutex mutex;	/* protect filling of buffer */
++	size_t count;		/* number of characters filled into buffer */
++	char *page;
++};
+ 
+ #define speed_char(info1) ({ char tmp; \
+ 		switch (info1 & (3 << 12)) { \
+@@ -441,10 +477,8 @@ done:
+ 	*nextp = next;
+ }
+ 
+-static ssize_t
+-show_async (struct class_device *class_dev, char *buf)
++static ssize_t fill_async_buffer(struct debug_buffer *buf)
+ {
+-	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+ 	struct ehci_hcd		*ehci;
+ 	unsigned long		flags;
+@@ -452,14 +486,13 @@ show_async (struct class_device *class_dev, char *buf)
+ 	char			*next;
+ 	struct ehci_qh		*qh;
+ 
+-	*buf = 0;
+-
+-	bus = class_get_devdata(class_dev);
+-	hcd = bus_to_hcd(bus);
++	hcd = bus_to_hcd(buf->bus);
+ 	ehci = hcd_to_ehci (hcd);
+-	next = buf;
++	next = buf->page;
+ 	size = PAGE_SIZE;
+ 
++	*next = 0;
++
+ 	/* dumps a snapshot of the async schedule.
+ 	 * usually empty except for long-term bulk reads, or head.
+ 	 * one QH per line, and TDs we know about
+@@ -477,16 +510,12 @@ show_async (struct class_device *class_dev, char *buf)
+ 	}
+ 	spin_unlock_irqrestore (&ehci->lock, flags);
+ 
+-	return strlen (buf);
++	return strlen(buf->page);
+ }
+-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+ 
+ #define DBG_SCHED_LIMIT 64
+-
+-static ssize_t
+-show_periodic (struct class_device *class_dev, char *buf)
++static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+ {
+-	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+ 	struct ehci_hcd		*ehci;
+ 	unsigned long		flags;
+@@ -500,10 +529,9 @@ show_periodic (struct class_device *class_dev, char *buf)
+ 		return 0;
+ 	seen_count = 0;
+ 
+-	bus = class_get_devdata(class_dev);
+-	hcd = bus_to_hcd(bus);
++	hcd = bus_to_hcd(buf->bus);
+ 	ehci = hcd_to_ehci (hcd);
+-	next = buf;
++	next = buf->page;
+ 	size = PAGE_SIZE;
+ 
+ 	temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
+@@ -623,14 +651,10 @@ show_periodic (struct class_device *class_dev, char *buf)
+ 
+ 	return PAGE_SIZE - size;
+ }
+-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+-
+ #undef DBG_SCHED_LIMIT
+ 
+-static ssize_t
+-show_registers (struct class_device *class_dev, char *buf)
++static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+ {
+-	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+ 	struct ehci_hcd		*ehci;
+ 	unsigned long		flags;
+@@ -639,15 +663,14 @@ show_registers (struct class_device *class_dev, char *buf)
+ 	static char		fmt [] = "%*s\n";
+ 	static char		label [] = "";
+ 
+-	bus = class_get_devdata(class_dev);
+-	hcd = bus_to_hcd(bus);
++	hcd = bus_to_hcd(buf->bus);
+ 	ehci = hcd_to_ehci (hcd);
+-	next = buf;
++	next = buf->page;
+ 	size = PAGE_SIZE;
+ 
+ 	spin_lock_irqsave (&ehci->lock, flags);
+ 
+-	if (bus->controller->power.power_state.event) {
++	if (buf->bus->controller->power.power_state.event) {
+ 		size = scnprintf (next, size,
+ 			"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+ 			"%s\n"
+@@ -763,9 +786,7 @@ show_registers (struct class_device *class_dev, char *buf)
+ 	}
+ 
+ 	if (ehci->reclaim) {
+-		temp = scnprintf (next, size, "reclaim qh %p%s\n",
+-				ehci->reclaim,
+-				ehci->reclaim_ready ? " ready" : "");
++		temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
+ 		size -= temp;
+ 		next += temp;
+ 	}
+@@ -789,26 +810,150 @@ done:
+ 
+ 	return PAGE_SIZE - size;
+ }
+-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+ 
+-static inline void create_debug_files (struct ehci_hcd *ehci)
++static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
++				ssize_t (*fill_func)(struct debug_buffer *))
+ {
+-	struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+-	int retval;
++	struct debug_buffer *buf;
++
++	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+ 
+-	retval = class_device_create_file(cldev, &class_device_attr_async);
+-	retval = class_device_create_file(cldev, &class_device_attr_periodic);
+-	retval = class_device_create_file(cldev, &class_device_attr_registers);
++	if (buf) {
++		buf->bus = bus;
++		buf->fill_func = fill_func;
++		mutex_init(&buf->mutex);
++	}
++
++	return buf;
+ }
+ 
+-static inline void remove_debug_files (struct ehci_hcd *ehci)
++static int fill_buffer(struct debug_buffer *buf)
+ {
+-	struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
++	int ret = 0;
++
++	if (!buf->page)
++		buf->page = (char *)get_zeroed_page(GFP_KERNEL);
++
++	if (!buf->page) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = buf->fill_func(buf);
+ 
+-	class_device_remove_file(cldev, &class_device_attr_async);
+-	class_device_remove_file(cldev, &class_device_attr_periodic);
+-	class_device_remove_file(cldev, &class_device_attr_registers);
++	if (ret >= 0) {
++		buf->count = ret;
++		ret = 0;
++	}
++
++out:
++	return ret;
+ }
+ 
+-#endif /* STUB_DEBUG_FILES */
++static ssize_t debug_output(struct file *file, char __user *user_buf,
++			    size_t len, loff_t *offset)
++{
++	struct debug_buffer *buf = file->private_data;
++	int ret = 0;
++
++	mutex_lock(&buf->mutex);
++	if (buf->count == 0) {
++		ret = fill_buffer(buf);
++		if (ret != 0) {
++			mutex_unlock(&buf->mutex);
++			goto out;
++		}
++	}
++	mutex_unlock(&buf->mutex);
++
++	ret = simple_read_from_buffer(user_buf, len, offset,
++				      buf->page, buf->count);
++
++out:
++	return ret;
++
++}
++
++static int debug_close(struct inode *inode, struct file *file)
++{
++	struct debug_buffer *buf = file->private_data;
+ 
++	if (buf) {
++		if (buf->page)
++			free_page((unsigned long)buf->page);
++		kfree(buf);
++	}
++
++	return 0;
++}
++static int debug_async_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static int debug_periodic_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private,
++					  fill_periodic_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static int debug_registers_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private,
++					  fill_registers_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static inline void create_debug_files (struct ehci_hcd *ehci)
++{
++	struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
++
++	ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
++	if (!ehci->debug_dir)
++		goto dir_error;
++
++	ehci->debug_async = debugfs_create_file("async", S_IRUGO,
++						ehci->debug_dir, bus,
++						&debug_async_fops);
++	if (!ehci->debug_async)
++		goto async_error;
++
++	ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
++						   ehci->debug_dir, bus,
++						   &debug_periodic_fops);
++	if (!ehci->debug_periodic)
++		goto periodic_error;
++
++	ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
++						    ehci->debug_dir, bus,
++						    &debug_registers_fops);
++	if (!ehci->debug_registers)
++		goto registers_error;
++	return;
++
++registers_error:
++	debugfs_remove(ehci->debug_periodic);
++periodic_error:
++	debugfs_remove(ehci->debug_async);
++async_error:
++	debugfs_remove(ehci->debug_dir);
++dir_error:
++	ehci->debug_periodic = NULL;
++	ehci->debug_async = NULL;
++	ehci->debug_dir = NULL;
++}
++
++static inline void remove_debug_files (struct ehci_hcd *ehci)
++{
++	debugfs_remove(ehci->debug_registers);
++	debugfs_remove(ehci->debug_periodic);
++	debugfs_remove(ehci->debug_async);
++	debugfs_remove(ehci->debug_dir);
++}
++
++#endif /* STUB_DEBUG_FILES */
+diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
+index 430821c..adb0def 100644
+--- a/drivers/usb/host/ehci-fsl.c
++++ b/drivers/usb/host/ehci-fsl.c
+@@ -25,7 +25,7 @@
+ 
+ #include "ehci-fsl.h"
+ 
+-/* FIXME: Power Managment is un-ported so temporarily disable it */
++/* FIXME: Power Management is un-ported so temporarily disable it */
+ #undef CONFIG_PM
+ 
+ /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+@@ -323,6 +323,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
+ 	.hub_control = ehci_hub_control,
+ 	.bus_suspend = ehci_bus_suspend,
+ 	.bus_resume = ehci_bus_resume,
++	.relinquish_port = ehci_relinquish_port,
+ };
+ 
+ static int ehci_fsl_drv_probe(struct platform_device *pdev)
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index 5f2d74e..4caa6a8 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -33,6 +33,7 @@
+ #include <linux/usb.h>
+ #include <linux/moduleparam.h>
+ #include <linux/dma-mapping.h>
++#include <linux/debugfs.h>
+ 
+ #include "../core/hcd.h"
+ 
+@@ -109,7 +110,7 @@ static const char	hcd_name [] = "ehci_hcd";
+ #define	EHCI_TUNE_MULT_TT	1
+ #define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
+ 
+-#define EHCI_IAA_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
++#define EHCI_IAA_MSECS		10		/* arbitrary */
+ #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
+ #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
+ #define EHCI_SHRINK_JIFFIES	(HZ/200)	/* async qh unlink delay */
+@@ -266,6 +267,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
+ 
+ /*-------------------------------------------------------------------------*/
+ 
++static void end_unlink_async(struct ehci_hcd *ehci);
+ static void ehci_work(struct ehci_hcd *ehci);
+ 
+ #include "ehci-hub.c"
+@@ -275,25 +277,41 @@ static void ehci_work(struct ehci_hcd *ehci);
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static void ehci_watchdog (unsigned long param)
++static void ehci_iaa_watchdog(unsigned long param)
+ {
+ 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+ 	unsigned long		flags;
++	u32			status, cmd;
+ 
+ 	spin_lock_irqsave (&ehci->lock, flags);
++	WARN_ON(!ehci->reclaim);
+ 
+-	/* lost IAA irqs wedge things badly; seen with a vt8235 */
++	status = ehci_readl(ehci, &ehci->regs->status);
++	cmd = ehci_readl(ehci, &ehci->regs->command);
++	ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
++
++	/* lost IAA irqs wedge things badly; seen first with a vt8235 */
+ 	if (ehci->reclaim) {
+-		u32		status = ehci_readl(ehci, &ehci->regs->status);
+ 		if (status & STS_IAA) {
+ 			ehci_vdbg (ehci, "lost IAA\n");
+ 			COUNT (ehci->stats.lost_iaa);
+ 			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
+-			ehci->reclaim_ready = 1;
+ 		}
++		ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
++		end_unlink_async(ehci);
+ 	}
+ 
+- 	/* stop async processing after it's idled a bit */
++	spin_unlock_irqrestore(&ehci->lock, flags);
++}
++
++static void ehci_watchdog(unsigned long param)
++{
++	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
++	unsigned long		flags;
++
++	spin_lock_irqsave(&ehci->lock, flags);
++
++	/* stop async processing after it's idled a bit */
+ 	if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
+ 		start_unlink_async (ehci, ehci->async);
+ 
+@@ -363,8 +381,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+ static void ehci_work (struct ehci_hcd *ehci)
+ {
+ 	timer_action_done (ehci, TIMER_IO_WATCHDOG);
+-	if (ehci->reclaim_ready)
+-		end_unlink_async (ehci);
+ 
+ 	/* another CPU may drop ehci->lock during a schedule scan while
+ 	 * it reports urb completions.  this flag guards against bogus
+@@ -399,6 +415,7 @@ static void ehci_stop (struct usb_hcd *hcd)
+ 
+ 	/* no more interrupts ... */
+ 	del_timer_sync (&ehci->watchdog);
++	del_timer_sync(&ehci->iaa_watchdog);
+ 
+ 	spin_lock_irq(&ehci->lock);
+ 	if (HC_IS_RUNNING (hcd->state))
+@@ -447,6 +464,10 @@ static int ehci_init(struct usb_hcd *hcd)
+ 	ehci->watchdog.function = ehci_watchdog;
+ 	ehci->watchdog.data = (unsigned long) ehci;
+ 
++	init_timer(&ehci->iaa_watchdog);
++	ehci->iaa_watchdog.function = ehci_iaa_watchdog;
++	ehci->iaa_watchdog.data = (unsigned long) ehci;
++
+ 	/*
+ 	 * hw default: 1K periodic list heads, one per frame.
+ 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+@@ -463,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd)
+ 		ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+ 
+ 	ehci->reclaim = NULL;
+-	ehci->reclaim_ready = 0;
+ 	ehci->next_uframe = -1;
+ 
+ 	/*
+@@ -654,8 +674,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ 	/* complete the unlinking of some qh [4.15.2.3] */
+ 	if (status & STS_IAA) {
+ 		COUNT (ehci->stats.reclaim);
+-		ehci->reclaim_ready = 1;
+-		bh = 1;
++		end_unlink_async(ehci);
+ 	}
+ 
+ 	/* remote wakeup [4.3.1] */
+@@ -761,10 +780,16 @@ static int ehci_urb_enqueue (
+ 
+ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ {
+-	/* if we need to use IAA and it's busy, defer */
+-	if (qh->qh_state == QH_STATE_LINKED
+-			&& ehci->reclaim
+-			&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
++	/* failfast */
++	if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
++		end_unlink_async(ehci);
++
++	/* if it's not linked then there's nothing to do */
++	if (qh->qh_state != QH_STATE_LINKED)
++		;
++
++	/* defer till later if busy */
++	else if (ehci->reclaim) {
+ 		struct ehci_qh		*last;
+ 
+ 		for (last = ehci->reclaim;
+@@ -774,12 +799,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ 		qh->qh_state = QH_STATE_UNLINK_WAIT;
+ 		last->reclaim = qh;
+ 
+-	/* bypass IAA if the hc can't care */
+-	} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
+-		end_unlink_async (ehci);
+-
+-	/* something else might have unlinked the qh by now */
+-	if (qh->qh_state == QH_STATE_LINKED)
++	/* start IAA cycle */
++	} else
+ 		start_unlink_async (ehci, qh);
+ }
+ 
+@@ -806,7 +827,19 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+ 		qh = (struct ehci_qh *) urb->hcpriv;
+ 		if (!qh)
+ 			break;
+-		unlink_async (ehci, qh);
++		switch (qh->qh_state) {
++		case QH_STATE_LINKED:
++		case QH_STATE_COMPLETING:
++			unlink_async(ehci, qh);
++			break;
++		case QH_STATE_UNLINK:
++		case QH_STATE_UNLINK_WAIT:
++			/* already started */
++			break;
++		case QH_STATE_IDLE:
++			WARN_ON(1);
++			break;
++		}
+ 		break;
+ 
+ 	case PIPE_INTERRUPT:
+@@ -829,16 +862,16 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+ 		/* reschedule QH iff another request is queued */
+ 		if (!list_empty (&qh->qtd_list)
+ 				&& HC_IS_RUNNING (hcd->state)) {
+-			int status;
++			int schedule_status;
+ 
+-			status = qh_schedule (ehci, qh);
++			schedule_status = qh_schedule (ehci, qh);
+ 			spin_unlock_irqrestore (&ehci->lock, flags);
+ 
+-			if (status != 0) {
++			if (schedule_status != 0) {
+ 				// shouldn't happen often, but ...
+ 				// FIXME kill those tds' urbs
+ 				err ("can't reschedule qh %p, err %d",
+-					qh, status);
++					qh, schedule_status);
+ 			}
+ 			return status;
+ 		}
+@@ -898,6 +931,7 @@ rescan:
+ 		unlink_async (ehci, qh);
+ 		/* FALL THROUGH */
+ 	case QH_STATE_UNLINK:		/* wait for hw to finish? */
++	case QH_STATE_UNLINK_WAIT:
+ idle_timeout:
+ 		spin_unlock_irqrestore (&ehci->lock, flags);
+ 		schedule_timeout_uninterruptible(1);
+@@ -959,11 +993,26 @@ MODULE_LICENSE ("GPL");
+ #define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_driver
+ #endif
+ 
+-#ifdef CONFIG_440EPX
++#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
+ #include "ehci-ppc-soc.c"
+ #define	PLATFORM_DRIVER		ehci_ppc_soc_driver
+ #endif
+ 
++#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
++#include "ehci-ppc-of.c"
++#define OF_PLATFORM_DRIVER	ehci_hcd_ppc_of_driver
++#endif
++
++#ifdef CONFIG_ARCH_ORION
++#include "ehci-orion.c"
++#define	PLATFORM_DRIVER		ehci_orion_driver
++#endif
++
++#ifdef CONFIG_ARCH_IXP4XX
++#include "ehci-ixp4xx.c"
++#define	PLATFORM_DRIVER		ixp4xx_ehci_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+     !defined(PS3_SYSTEM_BUS_DRIVER)
+ #error "missing bus glue for ehci-hcd"
+@@ -978,41 +1027,66 @@ static int __init ehci_hcd_init(void)
+ 		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
+ 		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+ 
++#ifdef DEBUG
++	ehci_debug_root = debugfs_create_dir("ehci", NULL);
++	if (!ehci_debug_root)
++		return -ENOENT;
++#endif
++
+ #ifdef PLATFORM_DRIVER
+ 	retval = platform_driver_register(&PLATFORM_DRIVER);
+ 	if (retval < 0)
+-		return retval;
++		goto clean0;
+ #endif
+ 
+ #ifdef PCI_DRIVER
+ 	retval = pci_register_driver(&PCI_DRIVER);
+-	if (retval < 0) {
+-#ifdef PLATFORM_DRIVER
+-		platform_driver_unregister(&PLATFORM_DRIVER);
+-#endif
+-		return retval;
+-	}
++	if (retval < 0)
++		goto clean1;
+ #endif
+ 
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+-	if (retval < 0) {
+-#ifdef PLATFORM_DRIVER
+-		platform_driver_unregister(&PLATFORM_DRIVER);
++	if (retval < 0)
++		goto clean2;
++#endif
++
++#ifdef OF_PLATFORM_DRIVER
++	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
++	if (retval < 0)
++		goto clean3;
++#endif
++	return retval;
++
++#ifdef OF_PLATFORM_DRIVER
++	/* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
++clean3:
++#endif
++#ifdef PS3_SYSTEM_BUS_DRIVER
++	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
++clean2:
+ #endif
+ #ifdef PCI_DRIVER
+-		pci_unregister_driver(&PCI_DRIVER);
++	pci_unregister_driver(&PCI_DRIVER);
++clean1:
+ #endif
+-		return retval;
+-	}
++#ifdef PLATFORM_DRIVER
++	platform_driver_unregister(&PLATFORM_DRIVER);
++clean0:
++#endif
++#ifdef DEBUG
++	debugfs_remove(ehci_debug_root);
++	ehci_debug_root = NULL;
+ #endif
+-
+ 	return retval;
+ }
+ module_init(ehci_hcd_init);
+ 
+ static void __exit ehci_hcd_cleanup(void)
+ {
++#ifdef OF_PLATFORM_DRIVER
++	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
++#endif
+ #ifdef PLATFORM_DRIVER
+ 	platform_driver_unregister(&PLATFORM_DRIVER);
+ #endif
+@@ -1022,6 +1096,9 @@ static void __exit ehci_hcd_cleanup(void)
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ #endif
++#ifdef DEBUG
++	debugfs_remove(ehci_debug_root);
++#endif
+ }
+ module_exit(ehci_hcd_cleanup);
+ 
+diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
+index 735db4a..40e8240 100644
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -123,6 +123,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
+ 
+ 	if (time_before (jiffies, ehci->next_statechange))
+ 		msleep(5);
++	del_timer_sync(&ehci->watchdog);
++	del_timer_sync(&ehci->iaa_watchdog);
+ 
+ 	port = HCS_N_PORTS (ehci->hcs_params);
+ 	spin_lock_irq (&ehci->lock);
+@@ -134,7 +136,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
+ 	}
+ 	ehci->command = ehci_readl(ehci, &ehci->regs->command);
+ 	if (ehci->reclaim)
+-		ehci->reclaim_ready = 1;
++		end_unlink_async(ehci);
+ 	ehci_work(ehci);
+ 
+ 	/* Unlike other USB host controller types, EHCI doesn't have
+@@ -170,8 +172,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
+ 		}
+ 	}
+ 
++	/* Apparently some devices need a >= 1-uframe delay here */
++	if (ehci->bus_suspended)
++		udelay(150);
++
+ 	/* turn off now-idle HC */
+-	del_timer_sync (&ehci->watchdog);
+ 	ehci_halt (ehci);
+ 	hcd->state = HC_STATE_SUSPENDED;
+ 
+@@ -291,14 +296,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
+ /*-------------------------------------------------------------------------*/
+ 
+ /* Display the ports dedicated to the companion controller */
+-static ssize_t show_companion(struct class_device *class_dev, char *buf)
++static ssize_t show_companion(struct device *dev,
++			      struct device_attribute *attr,
++			      char *buf)
+ {
+ 	struct ehci_hcd		*ehci;
+ 	int			nports, index, n;
+ 	int			count = PAGE_SIZE;
+ 	char			*ptr = buf;
+ 
+-	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
++	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+ 	nports = HCS_N_PORTS(ehci->hcs_params);
+ 
+ 	for (index = 0; index < nports; ++index) {
+@@ -312,40 +319,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf)
+ }
+ 
+ /*
+- * Dedicate or undedicate a port to the companion controller.
+- * Syntax is "[-]portnum", where a leading '-' sign means
+- * return control of the port to the EHCI controller.
++ * Sets the owner of a port
+  */
+-static ssize_t store_companion(struct class_device *class_dev,
+-		const char *buf, size_t count)
++static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
+ {
+-	struct ehci_hcd		*ehci;
+-	int			portnum, new_owner, try;
+ 	u32 __iomem		*status_reg;
+ 	u32			port_status;
++	int 			try;
+ 
+-	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+-	new_owner = PORT_OWNER;		/* Owned by companion */
+-	if (sscanf(buf, "%d", &portnum) != 1)
+-		return -EINVAL;
+-	if (portnum < 0) {
+-		portnum = - portnum;
+-		new_owner = 0;		/* Owned by EHCI */
+-	}
+-	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+-		return -ENOENT;
+-	status_reg = &ehci->regs->port_status[--portnum];
+-	if (new_owner)
+-		set_bit(portnum, &ehci->companion_ports);
+-	else
+-		clear_bit(portnum, &ehci->companion_ports);
++	status_reg = &ehci->regs->port_status[portnum];
+ 
+ 	/*
+ 	 * The controller won't set the OWNER bit if the port is
+ 	 * enabled, so this loop will sometimes require at least two
+ 	 * iterations: one to disable the port and one to set OWNER.
+ 	 */
+-
+ 	for (try = 4; try > 0; --try) {
+ 		spin_lock_irq(&ehci->lock);
+ 		port_status = ehci_readl(ehci, status_reg);
+@@ -362,9 +350,39 @@ static ssize_t store_companion(struct class_device *class_dev,
+ 		if (try > 1)
+ 			msleep(5);
+ 	}
++}
++
++/*
++ * Dedicate or undedicate a port to the companion controller.
++ * Syntax is "[-]portnum", where a leading '-' sign means
++ * return control of the port to the EHCI controller.
++ */
++static ssize_t store_companion(struct device *dev,
++			       struct device_attribute *attr,
++			       const char *buf, size_t count)
++{
++	struct ehci_hcd		*ehci;
++	int			portnum, new_owner;
++
++	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
++	new_owner = PORT_OWNER;		/* Owned by companion */
++	if (sscanf(buf, "%d", &portnum) != 1)
++		return -EINVAL;
++	if (portnum < 0) {
++		portnum = - portnum;
++		new_owner = 0;		/* Owned by EHCI */
++	}
++	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
++		return -ENOENT;
++	portnum--;
++	if (new_owner)
++		set_bit(portnum, &ehci->companion_ports);
++	else
++		clear_bit(portnum, &ehci->companion_ports);
++	set_owner(ehci, portnum, new_owner);
+ 	return count;
+ }
+-static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
++static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+ 
+ static inline void create_companion_file(struct ehci_hcd *ehci)
+ {
+@@ -372,16 +390,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
+ 
+ 	/* with integrated TT there is no companion! */
+ 	if (!ehci_is_TDI(ehci))
+-		i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+-				&class_device_attr_companion);
++		i = device_create_file(ehci_to_hcd(ehci)->self.dev,
++				       &dev_attr_companion);
+ }
+ 
+ static inline void remove_companion_file(struct ehci_hcd *ehci)
+ {
+ 	/* with integrated TT there is no companion! */
+ 	if (!ehci_is_TDI(ehci))
+-		class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+-				&class_device_attr_companion);
++		device_remove_file(ehci_to_hcd(ehci)->self.dev,
++				   &dev_attr_companion);
+ }
+ 
+ 
+@@ -393,10 +411,8 @@ static int check_reset_complete (
+ 	u32 __iomem	*status_reg,
+ 	int		port_status
+ ) {
+-	if (!(port_status & PORT_CONNECT)) {
+-		ehci->reset_done [index] = 0;
++	if (!(port_status & PORT_CONNECT))
+ 		return port_status;
+-	}
+ 
+ 	/* if reset finished and it's still not enabled -- handoff */
+ 	if (!(port_status & PORT_PE)) {
+@@ -475,8 +491,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+ 		 * controller by the user.
+ 		 */
+ 
+-		if (!(temp & PORT_CONNECT))
+-			ehci->reset_done [i] = 0;
+ 		if ((temp & mask) != 0
+ 				|| ((temp & PORT_RESUME) != 0
+ 					&& time_after_eq(jiffies,
+@@ -864,3 +878,13 @@ error:
+ 	spin_unlock_irqrestore (&ehci->lock, flags);
+ 	return retval;
+ }
++
++static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
++{
++	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
++
++	if (ehci_is_TDI(ehci))
++		return;
++	set_owner(ehci, --portnum, PORT_OWNER);
++}
++
+diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
+new file mode 100644
+index 0000000..3041d8f
+--- /dev/null
++++ b/drivers/usb/host/ehci-ixp4xx.c
+@@ -0,0 +1,152 @@
++/*
++ * IXP4XX EHCI Host Controller Driver
++ *
++ * Author: Vladimir Barinov <vbarinov at ru.mvista.com>
++ *
++ * Based on "ehci-fsl.c" by Randy Vinson <rvinson at mvista.com>
++ *
++ * 2007 (c) MontaVista Software, Inc. This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#include <linux/platform_device.h>
++
++static int ixp4xx_ehci_init(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int retval = 0;
++
++	ehci->big_endian_desc = 1;
++	ehci->big_endian_mmio = 1;
++
++	ehci->caps = hcd->regs + 0x100;
++	ehci->regs = hcd->regs + 0x100
++		+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	ehci->is_tdi_rh_tt = 1;
++	ehci_reset(ehci);
++
++	retval = ehci_init(hcd);
++	if (retval)
++		return retval;
++
++	ehci_port_power(ehci, 0);
++
++	return retval;
++}
++
++static const struct hc_driver ixp4xx_ehci_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "IXP4XX EHCI Host Controller",
++	.hcd_priv_size		= sizeof(struct ehci_hcd),
++	.irq			= ehci_irq,
++	.flags			= HCD_MEMORY | HCD_USB2,
++	.reset			= ixp4xx_ehci_init,
++	.start			= ehci_run,
++	.stop			= ehci_stop,
++	.shutdown		= ehci_shutdown,
++	.urb_enqueue		= ehci_urb_enqueue,
++	.urb_dequeue		= ehci_urb_dequeue,
++	.endpoint_disable	= ehci_endpoint_disable,
++	.get_frame_number	= ehci_get_frame,
++	.hub_status_data	= ehci_hub_status_data,
++	.hub_control		= ehci_hub_control,
++#if defined(CONFIG_PM)
++	.bus_suspend		= ehci_bus_suspend,
++	.bus_resume		= ehci_bus_resume,
++#endif
++};
++
++static int ixp4xx_ehci_probe(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd;
++	const struct hc_driver *driver = &ixp4xx_ehci_hc_driver;
++	struct resource *res;
++	int irq;
++	int retval;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no IRQ. Check %s setup!\n",
++			pdev->dev.bus_id);
++		return -ENODEV;
++	}
++	irq = res->start;
++
++	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
++	if (!hcd) {
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no register addr. Check %s setup!\n",
++			pdev->dev.bus_id);
++		retval = -ENODEV;
++		goto fail_request_resource;
++	}
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = res->end - res->start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++				driver->description)) {
++		dev_dbg(&pdev->dev, "controller already in use\n");
++		retval = -EBUSY;
++		goto fail_request_resource;
++	}
++
++	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
++	if (hcd->regs == NULL) {
++		dev_dbg(&pdev->dev, "error mapping memory\n");
++		retval = -EFAULT;
++		goto fail_ioremap;
++	}
++
++	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++	if (retval)
++		goto fail_add_hcd;
++
++	return retval;
++
++fail_add_hcd:
++	iounmap(hcd->regs);
++fail_ioremap:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++fail_request_resource:
++	usb_put_hcd(hcd);
++fail_create_hcd:
++	dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
++	return retval;
++}
++
++static int ixp4xx_ehci_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++
++	return 0;
++}
++
++MODULE_ALIAS("ixp4xx-ehci");
++
++static struct platform_driver ixp4xx_ehci_driver = {
++	.probe = ixp4xx_ehci_probe,
++	.remove = ixp4xx_ehci_remove,
++	.driver = {
++		.name = "ixp4xx-ehci",
++		.bus = &platform_bus_type
++	},
++};
+diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
+new file mode 100644
+index 0000000..e129981
+--- /dev/null
++++ b/drivers/usb/host/ehci-orion.c
+@@ -0,0 +1,272 @@
++/*
++ * drivers/usb/host/ehci-orion.c
++ *
++ * Tzachi Perelstein <tzachi at marvell.com>
++ *
++ * This file is licensed under  the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <asm/arch/orion.h>
++
++#define rdl(off)	__raw_readl(hcd->regs + (off))
++#define wrl(off, val)	__raw_writel((val), hcd->regs + (off))
++
++#define USB_CAUSE		0x310
++#define USB_MASK		0x314
++#define USB_CMD			0x140
++#define USB_MODE		0x1a8
++#define USB_IPG			0x360
++#define USB_PHY_PWR_CTRL	0x400
++#define USB_PHY_TX_CTRL		0x420
++#define USB_PHY_RX_CTRL		0x430
++#define USB_PHY_IVREF_CTRL	0x440
++#define USB_PHY_TST_GRP_CTRL	0x450
++
++/*
++ * Implement Orion USB controller specification guidelines
++ */
++static void orion_usb_setup(struct usb_hcd *hcd)
++{
++	/*
++	 * Clear interrupt cause and mask
++	 */
++	wrl(USB_CAUSE, 0);
++	wrl(USB_MASK, 0);
++
++	/*
++	 * Reset controller
++	 */
++	wrl(USB_CMD, rdl(USB_CMD) | 0x2);
++	while (rdl(USB_CMD) & 0x2);
++
++	/*
++	 * GL# USB-10: Set IPG for non start of frame packets
++	 * Bits[14:8]=0xc
++	 */
++	wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00);
++
++	/*
++	 * GL# USB-9: USB 2.0 Power Control
++	 * BG_VSEL[7:6]=0x1
++	 */
++	wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40);
++
++	/*
++	 * GL# USB-1: USB PHY Tx Control - force calibration to '8'
++	 * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8
++	 */
++	wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040);
++
++	/*
++	 * GL# USB-3 GL# USB-9: USB PHY Rx Control
++	 * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0,
++	 * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1
++	 */
++	wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010);
++
++	/*
++	 * GL# USB-3 GL# USB-9: USB PHY IVREF Control
++	 * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0
++	 */
++	wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32);
++
++	/*
++	 * GL# USB-3 GL# USB-9: USB PHY Test Group Control
++	 * REG_FIFO_SQ_RST[15]=0
++	 */
++	wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000);
++
++	/*
++	 * Stop and reset controller
++	 */
++	wrl(USB_CMD, rdl(USB_CMD) & ~0x1);
++	wrl(USB_CMD, rdl(USB_CMD) | 0x2);
++	while (rdl(USB_CMD) & 0x2);
++
++	/*
++	 * GL# USB-5 Streaming disable REG_USB_MODE[4]=1
++	 * TBD: This need to be done after each reset!
++	 * GL# USB-4 Setup USB Host mode
++	 */
++	wrl(USB_MODE, 0x13);
++}
++
++static int ehci_orion_setup(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int retval;
++
++	retval = ehci_halt(ehci);
++	if (retval)
++		return retval;
++
++	/*
++	 * data structure init
++	 */
++	retval = ehci_init(hcd);
++	if (retval)
++		return retval;
++
++	ehci_reset(ehci);
++	ehci_port_power(ehci, 0);
++
++	return retval;
++}
++
++static const struct hc_driver ehci_orion_hc_driver = {
++	.description = hcd_name,
++	.product_desc = "Marvell Orion EHCI",
++	.hcd_priv_size = sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq = ehci_irq,
++	.flags = HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset = ehci_orion_setup,
++	.start = ehci_run,
++#ifdef CONFIG_PM
++	.suspend = ehci_bus_suspend,
++	.resume = ehci_bus_resume,
++#endif
++	.stop = ehci_stop,
++	.shutdown = ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue = ehci_urb_enqueue,
++	.urb_dequeue = ehci_urb_dequeue,
++	.endpoint_disable = ehci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number = ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data = ehci_hub_status_data,
++	.hub_control = ehci_hub_control,
++	.bus_suspend = ehci_bus_suspend,
++	.bus_resume = ehci_bus_resume,
++};
++
++static int __init ehci_orion_drv_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct usb_hcd *hcd;
++	struct ehci_hcd *ehci;
++	void __iomem *regs;
++	int irq, err;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	pr_debug("Initializing Orion-SoC USB Host Controller\n");
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq <= 0) {
++		dev_err(&pdev->dev,
++			"Found HC with no IRQ. Check %s setup!\n",
++			pdev->dev.bus_id);
++		err = -ENODEV;
++		goto err1;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no register addr. Check %s setup!\n",
++			pdev->dev.bus_id);
++		err = -ENODEV;
++		goto err1;
++	}
++
++	if (!request_mem_region(res->start, res->end - res->start + 1,
++				ehci_orion_hc_driver.description)) {
++		dev_dbg(&pdev->dev, "controller already in use\n");
++		err = -EBUSY;
++		goto err1;
++	}
++
++	regs = ioremap(res->start, res->end - res->start + 1);
++	if (regs == NULL) {
++		dev_dbg(&pdev->dev, "error mapping memory\n");
++		err = -EFAULT;
++		goto err2;
++	}
++
++	hcd = usb_create_hcd(&ehci_orion_hc_driver,
++			&pdev->dev, pdev->dev.bus_id);
++	if (!hcd) {
++		err = -ENOMEM;
++		goto err3;
++	}
++
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = res->end - res->start + 1;
++	hcd->regs = regs;
++
++	ehci = hcd_to_ehci(hcd);
++	ehci->caps = hcd->regs + 0x100;
++	ehci->regs = hcd->regs + 0x100 +
++		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++	ehci->is_tdi_rh_tt = 1;
++	ehci->sbrn = 0x20;
++
++	/*
++	 * setup Orion USB controller
++	 */
++	orion_usb_setup(hcd);
++
++	err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
++	if (err)
++		goto err4;
++
++	return 0;
++
++err4:
++	usb_put_hcd(hcd);
++err3:
++	iounmap(regs);
++err2:
++	release_mem_region(res->start, res->end - res->start + 1);
++err1:
++	dev_err(&pdev->dev, "init %s fail, %d\n",
++		pdev->dev.bus_id, err);
++
++	return err;
++}
++
++static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++
++	return 0;
++}
++
++MODULE_ALIAS("platform:orion-ehci");
++
++static struct platform_driver ehci_orion_driver = {
++	.probe		= ehci_orion_drv_probe,
++	.remove		= __exit_p(ehci_orion_drv_remove),
++	.shutdown	= usb_hcd_platform_shutdown,
++	.driver.name	= "orion-ehci",
++};
+diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
+index ad0d496..3ba0166 100644
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
+ 	/* emptying the schedule aborts any urbs */
+ 	spin_lock_irq(&ehci->lock);
+ 	if (ehci->reclaim)
+-		ehci->reclaim_ready = 1;
++		end_unlink_async(ehci);
+ 	ehci_work(ehci);
+ 	spin_unlock_irq(&ehci->lock);
+ 
+@@ -364,6 +364,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
+ 	.hub_control =		ehci_hub_control,
+ 	.bus_suspend =		ehci_bus_suspend,
+ 	.bus_resume =		ehci_bus_resume,
++	.relinquish_port = 	ehci_relinquish_port,
+ };
+ 
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
+new file mode 100644
+index 0000000..ee305b1
+--- /dev/null
++++ b/drivers/usb/host/ehci-ppc-of.c
+@@ -0,0 +1,238 @@
++/*
++ * EHCI HCD (Host Controller Driver) for USB.
++ *
++ * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus
++ * Tested on AMCC PPC 440EPx
++ *
++ * Valentine Barshak <vbarshak at ru.mvista.com>
++ *
++ * Based on "ehci-ppc-soc.c" by Stefan Roese <sr at denx.de>
++ * and "ohci-ppc-of.c" by Sylvain Munaut <tnt at 246tNt.com>
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/signal.h>
++
++#include <linux/of.h>
++#include <linux/of_platform.h>
++
++/* called during probe() after chip reset completes */
++static int ehci_ppc_of_setup(struct usb_hcd *hcd)
++{
++	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
++	int		retval;
++
++	retval = ehci_halt(ehci);
++	if (retval)
++		return retval;
++
++	retval = ehci_init(hcd);
++	if (retval)
++		return retval;
++
++	ehci->sbrn = 0x20;
++	return ehci_reset(ehci);
++}
++
++
++static const struct hc_driver ehci_ppc_of_hc_driver = {
++	.description		= hcd_name,
++	.product_desc		= "OF EHCI",
++	.hcd_priv_size		= sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq			= ehci_irq,
++	.flags			= HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset			= ehci_ppc_of_setup,
++	.start			= ehci_run,
++	.stop			= ehci_stop,
++	.shutdown		= ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue		= ehci_urb_enqueue,
++	.urb_dequeue		= ehci_urb_dequeue,
++	.endpoint_disable	= ehci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number	= ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data	= ehci_hub_status_data,
++	.hub_control		= ehci_hub_control,
++#ifdef	CONFIG_PM
++	.bus_suspend		= ehci_bus_suspend,
++	.bus_resume		= ehci_bus_resume,
++#endif
++};
++
++
++/*
++ * 440EPx Errata USBH_3
++ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
++ */
++#define PPC440EPX_EHCI0_INSREG_BMT	(0x1 << 0)
++static int __devinit
++ppc44x_enable_bmt(struct device_node *dn)
++{
++	__iomem u32 *insreg_virt;
++
++	insreg_virt = of_iomap(dn, 1);
++	if (!insreg_virt)
++		return  -EINVAL;
++
++	out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
++
++	iounmap(insreg_virt);
++	return 0;
++}
++
++
++static int __devinit
++ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
++{
++	struct device_node *dn = op->node;
++	struct usb_hcd *hcd;
++	struct ehci_hcd	*ehci;
++	struct resource res;
++	int irq;
++	int rv;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
++
++	rv = of_address_to_resource(dn, 0, &res);
++	if (rv)
++		return rv;
++
++	hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
++	if (!hcd)
++		return -ENOMEM;
++
++	hcd->rsrc_start = res.start;
++	hcd->rsrc_len = res.end - res.start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
++		rv = -EBUSY;
++		goto err_rmr;
++	}
++
++	irq = irq_of_parse_and_map(dn, 0);
++	if (irq == NO_IRQ) {
++		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
++		rv = -EBUSY;
++		goto err_irq;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (!hcd->regs) {
++		printk(KERN_ERR __FILE__ ": ioremap failed\n");
++		rv = -ENOMEM;
++		goto err_ioremap;
++	}
++
++	ehci = hcd_to_ehci(hcd);
++
++	if (of_get_property(dn, "big-endian", NULL)) {
++		ehci->big_endian_mmio = 1;
++		ehci->big_endian_desc = 1;
++	}
++	if (of_get_property(dn, "big-endian-regs", NULL))
++		ehci->big_endian_mmio = 1;
++	if (of_get_property(dn, "big-endian-desc", NULL))
++		ehci->big_endian_desc = 1;
++
++	ehci->caps = hcd->regs;
++	ehci->regs = hcd->regs +
++			HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++
++	/* cache this readonly data; minimize chip reads */
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
++		rv = ppc44x_enable_bmt(dn);
++		ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
++				rv ? "NOT ": "");
++	}
++
++	rv = usb_add_hcd(hcd, irq, 0);
++	if (rv == 0)
++		return 0;
++
++	iounmap(hcd->regs);
++err_ioremap:
++	irq_dispose_mapping(irq);
++err_irq:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_rmr:
++	usb_put_hcd(hcd);
++
++	return rv;
++}
++
++
++static int ehci_hcd_ppc_of_remove(struct of_device *op)
++{
++	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
++	dev_set_drvdata(&op->dev, NULL);
++
++	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
++
++	usb_remove_hcd(hcd);
++
++	iounmap(hcd->regs);
++	irq_dispose_mapping(hcd->irq);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++
++	usb_put_hcd(hcd);
++
++	return 0;
++}
++
++
++static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
++{
++	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
++
++	if (hcd->driver->shutdown)
++		hcd->driver->shutdown(hcd);
++
++	return 0;
++}
++
++
++static struct of_device_id ehci_hcd_ppc_of_match[] = {
++	{
++		.compatible = "usb-ehci",
++	},
++	{},
++};
++MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
++
++
++static struct of_platform_driver ehci_hcd_ppc_of_driver = {
++	.name		= "ppc-of-ehci",
++	.match_table	= ehci_hcd_ppc_of_match,
++	.probe		= ehci_hcd_ppc_of_probe,
++	.remove		= ehci_hcd_ppc_of_remove,
++	.shutdown	= ehci_hcd_ppc_of_shutdown,
++	.driver		= {
++		.name	= "ppc-of-ehci",
++		.owner	= THIS_MODULE,
++	},
++};
+diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
+index 452d4b1..a324907 100644
+--- a/drivers/usb/host/ehci-ppc-soc.c
++++ b/drivers/usb/host/ehci-ppc-soc.c
+@@ -162,6 +162,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
+ 	.hub_control = ehci_hub_control,
+ 	.bus_suspend = ehci_bus_suspend,
+ 	.bus_resume = ehci_bus_resume,
++	.relinquish_port = ehci_relinquish_port,
+ };
+ 
+ static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
+diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
+index 03a6b2f..bbda58e 100644
+--- a/drivers/usb/host/ehci-ps3.c
++++ b/drivers/usb/host/ehci-ps3.c
+@@ -72,6 +72,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
+ 	.bus_suspend		= ehci_bus_suspend,
+ 	.bus_resume		= ehci_bus_resume,
+ #endif
++	.relinquish_port	= ehci_relinquish_port,
+ };
+ 
+ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
+diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
+index b10f39c..776a97f 100644
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -198,7 +198,8 @@ static int qtd_copy_status (
+ 
+ 		/* if async CSPLIT failed, try cleaning out the TT buffer */
+ 		if (status != -EPIPE
+-				&& urb->dev->tt && !usb_pipeint (urb->pipe)
++				&& urb->dev->tt
++				&& !usb_pipeint(urb->pipe)
+ 				&& ((token & QTD_STS_MMF) != 0
+ 					|| QTD_CERR(token) == 0)
+ 				&& (!ehci_is_TDI(ehci)
+@@ -211,6 +212,9 @@ static int qtd_copy_status (
+ 				urb->dev->ttport, urb->dev->devnum,
+ 				usb_pipeendpoint (urb->pipe), token);
+ #endif /* DEBUG */
++			/* REVISIT ARC-derived cores don't clear the root
++			 * hub TT buffer in this way...
++			 */
+ 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
+ 		}
+ 	}
+@@ -638,6 +642,7 @@ qh_make (
+ 	u32			info1 = 0, info2 = 0;
+ 	int			is_input, type;
+ 	int			maxp = 0;
++	struct usb_tt		*tt = urb->dev->tt;
+ 
+ 	if (!qh)
+ 		return qh;
+@@ -661,8 +666,9 @@ qh_make (
+ 	 * For control/bulk requests, the HC or TT handles these.
+ 	 */
+ 	if (type == PIPE_INTERRUPT) {
+-		qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+-				hb_mult (maxp) * max_packet (maxp)));
++		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
++				is_input, 0,
++				hb_mult(maxp) * max_packet(maxp)));
+ 		qh->start = NO_FRAME;
+ 
+ 		if (urb->dev->speed == USB_SPEED_HIGH) {
+@@ -680,7 +686,6 @@ qh_make (
+ 				goto done;
+ 			}
+ 		} else {
+-			struct usb_tt	*tt = urb->dev->tt;
+ 			int		think_time;
+ 
+ 			/* gap is f(FS/LS transfer times) */
+@@ -736,10 +741,8 @@ qh_make (
+ 		/* set the address of the TT; for TDI's integrated
+ 		 * root hub tt, leave it zeroed.
+ 		 */
+-		if (!ehci_is_TDI(ehci)
+-				|| urb->dev->tt->hub !=
+-					ehci_to_hcd(ehci)->self.root_hub)
+-			info2 |= urb->dev->tt->hub->devnum << 16;
++		if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub)
++			info2 |= tt->hub->devnum << 16;
+ 
+ 		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+ 
+@@ -973,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
+ 	struct ehci_qh		*qh = ehci->reclaim;
+ 	struct ehci_qh		*next;
+ 
+-	timer_action_done (ehci, TIMER_IAA_WATCHDOG);
++	iaa_watchdog_done(ehci);
+ 
+ 	// qh->hw_next = cpu_to_hc32(qh->qh_dma);
+ 	qh->qh_state = QH_STATE_IDLE;
+@@ -983,7 +986,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
+ 	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
+ 	next = qh->reclaim;
+ 	ehci->reclaim = next;
+-	ehci->reclaim_ready = 0;
+ 	qh->reclaim = NULL;
+ 
+ 	qh_completions (ehci, qh);
+@@ -1059,11 +1061,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ 		return;
+ 	}
+ 
+-	ehci->reclaim_ready = 0;
+ 	cmd |= CMD_IAAD;
+ 	ehci_writel(ehci, cmd, &ehci->regs->command);
+ 	(void)ehci_readl(ehci, &ehci->regs->command);
+-	timer_action (ehci, TIMER_IAA_WATCHDOG);
++	iaa_watchdog_start(ehci);
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
+index 80d99bc..8a8e08a 100644
+--- a/drivers/usb/host/ehci-sched.c
++++ b/drivers/usb/host/ehci-sched.c
+@@ -119,7 +119,8 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+ 			q = &q->fstn->fstn_next;
+ 			break;
+ 		case Q_TYPE_ITD:
+-			usecs += q->itd->usecs [uframe];
++			if (q->itd->hw_transaction[uframe])
++				usecs += q->itd->stream->usecs;
+ 			hw_p = &q->itd->hw_next;
+ 			q = &q->itd->itd_next;
+ 			break;
+@@ -211,7 +212,7 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
+  * low/fullspeed transfer can "carry over" from one uframe to the next,
+  * since the TT just performs downstream transfers in sequence.
+  *
+- * For example two seperate 100 usec transfers can start in the same uframe,
++ * For example two separate 100 usec transfers can start in the same uframe,
+  * and the second one would "carry over" 75 usecs into the next uframe.
+  */
+ static void
+@@ -1536,7 +1537,6 @@ itd_link_urb (
+ 		uframe = next_uframe & 0x07;
+ 		frame = next_uframe >> 3;
+ 
+-		itd->usecs [uframe] = stream->usecs;
+ 		itd_patch(ehci, itd, iso_sched, packet, uframe);
+ 
+ 		next_uframe += stream->interval;
+@@ -1565,6 +1565,16 @@ itd_link_urb (
+ 
+ #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+ 
++/* Process and recycle a completed ITD.  Return true iff its urb completed,
++ * and hence its completion callback probably added things to the hardware
++ * schedule.
++ *
++ * Note that we carefully avoid recycling this descriptor until after any
++ * completion callback runs, so that it won't be reused quickly.  That is,
++ * assuming (a) no more than two urbs per frame on this endpoint, and also
++ * (b) only this endpoint's completions submit URBs.  It seems some silicon
++ * corrupts things if you reuse completed descriptors very quickly...
++ */
+ static unsigned
+ itd_complete (
+ 	struct ehci_hcd	*ehci,
+@@ -1577,6 +1587,7 @@ itd_complete (
+ 	int					urb_index = -1;
+ 	struct ehci_iso_stream			*stream = itd->stream;
+ 	struct usb_device			*dev;
++	unsigned				retval = false;
+ 
+ 	/* for each uframe with a packet */
+ 	for (uframe = 0; uframe < 8; uframe++) {
+@@ -1610,30 +1621,21 @@ itd_complete (
+ 		}
+ 	}
+ 
+-	usb_put_urb (urb);
+-	itd->urb = NULL;
+-	itd->stream = NULL;
+-	list_move (&itd->itd_list, &stream->free_list);
+-	iso_stream_put (ehci, stream);
+-
+ 	/* handle completion now? */
+ 	if (likely ((urb_index + 1) != urb->number_of_packets))
+-		return 0;
++		goto done;
+ 
+ 	/* ASSERT: it's really the last itd for this urb
+ 	list_for_each_entry (itd, &stream->td_list, itd_list)
+ 		BUG_ON (itd->urb == urb);
+ 	 */
+ 
+-	/* give urb back to the driver ... can be out-of-order */
++	/* give urb back to the driver; completion often (re)submits */
+ 	dev = urb->dev;
+ 	ehci_urb_done(ehci, urb, 0);
++	retval = true;
+ 	urb = NULL;
+-
+-	/* defer stopping schedule; completion can submit */
+ 	ehci->periodic_sched--;
+-	if (unlikely (!ehci->periodic_sched))
+-		(void) disable_periodic (ehci);
+ 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ 
+ 	if (unlikely (list_empty (&stream->td_list))) {
+@@ -1645,8 +1647,15 @@ itd_complete (
+ 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+ 	}
+ 	iso_stream_put (ehci, stream);
++	/* OK to recycle this ITD now that its completion callback ran. */
++done:
++	usb_put_urb(urb);
++	itd->urb = NULL;
++	itd->stream = NULL;
++	list_move(&itd->itd_list, &stream->free_list);
++	iso_stream_put(ehci, stream);
+ 
+-	return 1;
++	return retval;
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -1712,8 +1721,6 @@ done:
+ 	return status;
+ }
+ 
+-#ifdef CONFIG_USB_EHCI_SPLIT_ISO
+-
+ /*-------------------------------------------------------------------------*/
+ 
+ /*
+@@ -1950,6 +1957,16 @@ sitd_link_urb (
+ #define	SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
+ 				| SITD_STS_XACT | SITD_STS_MMF)
+ 
++/* Process and recycle a completed SITD.  Return true iff its urb completed,
++ * and hence its completion callback probably added things to the hardware
++ * schedule.
++ *
++ * Note that we carefully avoid recycling this descriptor until after any
++ * completion callback runs, so that it won't be reused quickly.  That is,
++ * assuming (a) no more than two urbs per frame on this endpoint, and also
++ * (b) only this endpoint's completions submit URBs.  It seems some silicon
++ * corrupts things if you reuse completed descriptors very quickly...
++ */
+ static unsigned
+ sitd_complete (
+ 	struct ehci_hcd		*ehci,
+@@ -1961,6 +1978,7 @@ sitd_complete (
+ 	int					urb_index = -1;
+ 	struct ehci_iso_stream			*stream = sitd->stream;
+ 	struct usb_device			*dev;
++	unsigned				retval = false;
+ 
+ 	urb_index = sitd->index;
+ 	desc = &urb->iso_frame_desc [urb_index];
+@@ -1981,32 +1999,23 @@ sitd_complete (
+ 		desc->status = 0;
+ 		desc->actual_length = desc->length - SITD_LENGTH (t);
+ 	}
+-
+-	usb_put_urb (urb);
+-	sitd->urb = NULL;
+-	sitd->stream = NULL;
+-	list_move (&sitd->sitd_list, &stream->free_list);
+ 	stream->depth -= stream->interval << 3;
+-	iso_stream_put (ehci, stream);
+ 
+ 	/* handle completion now? */
+ 	if ((urb_index + 1) != urb->number_of_packets)
+-		return 0;
++		goto done;
+ 
+ 	/* ASSERT: it's really the last sitd for this urb
+ 	list_for_each_entry (sitd, &stream->td_list, sitd_list)
+ 		BUG_ON (sitd->urb == urb);
+ 	 */
+ 
+-	/* give urb back to the driver */
++	/* give urb back to the driver; completion often (re)submits */
+ 	dev = urb->dev;
+ 	ehci_urb_done(ehci, urb, 0);
++	retval = true;
+ 	urb = NULL;
+-
+-	/* defer stopping schedule; completion can submit */
+ 	ehci->periodic_sched--;
+-	if (!ehci->periodic_sched)
+-		(void) disable_periodic (ehci);
+ 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
+ 
+ 	if (list_empty (&stream->td_list)) {
+@@ -2018,8 +2027,15 @@ sitd_complete (
+ 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+ 	}
+ 	iso_stream_put (ehci, stream);
++	/* OK to recycle this SITD now that its completion callback ran. */
++done:
++	usb_put_urb(urb);
++	sitd->urb = NULL;
++	sitd->stream = NULL;
++	list_move(&sitd->sitd_list, &stream->free_list);
++	iso_stream_put(ehci, stream);
+ 
+-	return 1;
++	return retval;
+ }
+ 
+ 
+@@ -2082,26 +2098,6 @@ done:
+ 	return status;
+ }
+ 
+-#else
+-
+-static inline int
+-sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
+-{
+-	ehci_dbg (ehci, "split iso support is disabled\n");
+-	return -ENOSYS;
+-}
+-
+-static inline unsigned
+-sitd_complete (
+-	struct ehci_hcd		*ehci,
+-	struct ehci_sitd	*sitd
+-) {
+-	ehci_err (ehci, "sitd_complete %p?\n", sitd);
+-	return 0;
+-}
+-
+-#endif /* USB_EHCI_SPLIT_ISO */
+-
+ /*-------------------------------------------------------------------------*/
+ 
+ static void
+@@ -2127,17 +2123,9 @@ scan_periodic (struct ehci_hcd *ehci)
+ 	for (;;) {
+ 		union ehci_shadow	q, *q_p;
+ 		__hc32			type, *hw_p;
+-		unsigned		uframes;
++		unsigned		incomplete = false;
+ 
+-		/* don't scan past the live uframe */
+ 		frame = now_uframe >> 3;
+-		if (frame == (clock >> 3))
+-			uframes = now_uframe & 0x07;
+-		else {
+-			/* safe to scan the whole frame at once */
+-			now_uframe |= 0x07;
+-			uframes = 8;
+-		}
+ 
+ restart:
+ 		/* scan each element in frame's queue for completions */
+@@ -2175,12 +2163,15 @@ restart:
+ 				q = q.fstn->fstn_next;
+ 				break;
+ 			case Q_TYPE_ITD:
+-				/* skip itds for later in the frame */
++				/* If this ITD is still active, leave it for
++				 * later processing ... check the next entry.
++				 */
+ 				rmb ();
+-				for (uf = live ? uframes : 8; uf < 8; uf++) {
++				for (uf = 0; uf < 8 && live; uf++) {
+ 					if (0 == (q.itd->hw_transaction [uf]
+ 							& ITD_ACTIVE(ehci)))
+ 						continue;
++					incomplete = true;
+ 					q_p = &q.itd->itd_next;
+ 					hw_p = &q.itd->hw_next;
+ 					type = Q_NEXT_TYPE(ehci,
+@@ -2188,10 +2179,12 @@ restart:
+ 					q = *q_p;
+ 					break;
+ 				}
+-				if (uf != 8)
++				if (uf < 8 && live)
+ 					break;
+ 
+-				/* this one's ready ... HC won't cache the
++				/* Take finished ITDs out of the schedule
++				 * and process them:  recycle, maybe report
++				 * URB completion.  HC won't cache the
+ 				 * pointer for much longer, if at all.
+ 				 */
+ 				*q_p = q.itd->itd_next;
+@@ -2202,8 +2195,12 @@ restart:
+ 				q = *q_p;
+ 				break;
+ 			case Q_TYPE_SITD:
++				/* If this SITD is still active, leave it for
++				 * later processing ... check the next entry.
++				 */
+ 				if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
+ 						&& live) {
++					incomplete = true;
+ 					q_p = &q.sitd->sitd_next;
+ 					hw_p = &q.sitd->hw_next;
+ 					type = Q_NEXT_TYPE(ehci,
+@@ -2211,6 +2208,11 @@ restart:
+ 					q = *q_p;
+ 					break;
+ 				}
++
++				/* Take finished SITDs out of the schedule
++				 * and process them:  recycle, maybe report
++				 * URB completion.
++				 */
+ 				*q_p = q.sitd->sitd_next;
+ 				*hw_p = q.sitd->hw_next;
+ 				type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
+@@ -2226,11 +2228,24 @@ restart:
+ 			}
+ 
+ 			/* assume completion callbacks modify the queue */
+-			if (unlikely (modified))
+-				goto restart;
++			if (unlikely (modified)) {
++				if (likely(ehci->periodic_sched > 0))
++					goto restart;
++				/* maybe we can short-circuit this scan! */
++				disable_periodic(ehci);
++				now_uframe = clock;
++				break;
++			}
+ 		}
+ 
+-		/* stop when we catch up to the HC */
++		/* If we can tell we caught up to the hardware, stop now.
++		 * We can't advance our scan without collecting the ISO
++		 * transfers that are still pending in this frame.
++		 */
++		if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
++			ehci->next_uframe = now_uframe;
++			break;
++		}
+ 
+ 		// FIXME:  this assumes we won't get lapped when
+ 		// latencies climb; that should be rare, but...
+@@ -2243,7 +2258,8 @@ restart:
+ 		if (now_uframe == clock) {
+ 			unsigned	now;
+ 
+-			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
++			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
++					|| ehci->periodic_sched == 0)
+ 				break;
+ 			ehci->next_uframe = now_uframe;
+ 			now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
+diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
+index 951d69f..bf92d20 100644
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -74,7 +74,6 @@ struct ehci_hcd {			/* one per controller */
+ 	/* async schedule support */
+ 	struct ehci_qh		*async;
+ 	struct ehci_qh		*reclaim;
+-	unsigned		reclaim_ready : 1;
+ 	unsigned		scanning : 1;
+ 
+ 	/* periodic schedule support */
+@@ -105,6 +104,7 @@ struct ehci_hcd {			/* one per controller */
+ 	struct dma_pool		*itd_pool;	/* itd per iso urb */
+ 	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
+ 
++	struct timer_list	iaa_watchdog;
+ 	struct timer_list	watchdog;
+ 	unsigned long		actions;
+ 	unsigned		stamp;
+@@ -127,6 +127,14 @@ struct ehci_hcd {			/* one per controller */
+ #else
+ #	define COUNT(x) do {} while (0)
+ #endif
++
++	/* debug files */
++#ifdef DEBUG
++	struct dentry		*debug_dir;
++	struct dentry		*debug_async;
++	struct dentry		*debug_periodic;
++	struct dentry		*debug_registers;
++#endif
+ };
+ 
+ /* convert between an HCD pointer and the corresponding EHCI_HCD */
+@@ -140,9 +148,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
+ }
+ 
+ 
++static inline void
++iaa_watchdog_start(struct ehci_hcd *ehci)
++{
++	WARN_ON(timer_pending(&ehci->iaa_watchdog));
++	mod_timer(&ehci->iaa_watchdog,
++			jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
++}
++
++static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
++{
++	del_timer(&ehci->iaa_watchdog);
++}
++
+ enum ehci_timer_action {
+ 	TIMER_IO_WATCHDOG,
+-	TIMER_IAA_WATCHDOG,
+ 	TIMER_ASYNC_SHRINK,
+ 	TIMER_ASYNC_OFF,
+ };
+@@ -160,9 +180,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
+ 		unsigned long t;
+ 
+ 		switch (action) {
+-		case TIMER_IAA_WATCHDOG:
+-			t = EHCI_IAA_JIFFIES;
+-			break;
+ 		case TIMER_IO_WATCHDOG:
+ 			t = EHCI_IO_JIFFIES;
+ 			break;
+@@ -179,8 +196,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
+ 		// async queue SHRINK often precedes IAA.  while it's ready
+ 		// to go OFF neither can matter, and afterwards the IO
+ 		// watchdog stops unless there's still periodic traffic.
+-		if (action != TIMER_IAA_WATCHDOG
+-				&& t > ehci->watchdog.expires
++		if (time_before_eq(t, ehci->watchdog.expires)
+ 				&& timer_pending (&ehci->watchdog))
+ 			return;
+ 		mod_timer (&ehci->watchdog, t);
+@@ -534,8 +550,8 @@ struct ehci_iso_stream {
+ 	 * trusting urb->interval == f(epdesc->bInterval) and
+ 	 * including the extra info for hw_bufp[0..2]
+ 	 */
+-	u8			interval;
+ 	u8			usecs, c_usecs;
++	u16			interval;
+ 	u16			tt_usecs;
+ 	u16			maxp;
+ 	u16			raw_mask;
+@@ -586,7 +602,6 @@ struct ehci_itd {
+ 	unsigned		frame;		/* where scheduled */
+ 	unsigned		pg;
+ 	unsigned		index[8];	/* in urb->iso_frame_desc */
+-	u8			usecs[8];
+ } __attribute__ ((aligned (32)));
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -725,11 +740,16 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+  * definition below can die once the 4xx support is
+  * finally ported over.
+  */
+-#if defined(CONFIG_PPC)
++#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
+ #define readl_be(addr)		in_be32((__force unsigned *)addr)
+ #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
+ #endif
+ 
++#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
++#define readl_be(addr)		__raw_readl((__force unsigned *)addr)
++#define writel_be(val, addr)	__raw_writel(val, (__force unsigned *)addr)
++#endif
++
+ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
+ 		__u32 __iomem * regs)
+ {
+diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
+index c27417f..0130fd8 100644
+--- a/drivers/usb/host/isp116x-hcd.c
++++ b/drivers/usb/host/isp116x-hcd.c
+@@ -918,7 +918,6 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
+ 			      | RH_PS_OCIC | RH_PS_PRSC)) {
+ 			changed = 1;
+ 			buf[0] |= 1 << (i + 1);
+-			continue;
+ 		}
+ 	}
+ 	spin_unlock_irqrestore(&isp116x->lock, flags);
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index d849c80..126fcbd 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -17,6 +17,8 @@
+ 
+ #include <asm/mach-types.h>
+ #include <asm/hardware.h>
++#include <asm/gpio.h>
++
+ #include <asm/arch/board.h>
+ #include <asm/arch/cpu.h>
+ 
+@@ -271,12 +273,41 @@ static const struct hc_driver ohci_at91_hc_driver = {
+ 
+ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
+ {
++	struct at91_usbh_data	*pdata = pdev->dev.platform_data;
++	int			i;
++
++	if (pdata) {
++		/* REVISIT make the driver support per-port power switching,
++		 * and also overcurrent detection.  Here we assume the ports
++		 * are always powered while this driver is active, and use
++		 * active-low power switches.
++		 */
++		for (i = 0; i < pdata->ports; i++) {
++			if (pdata->vbus_pin[i] <= 0)
++				continue;
++			gpio_request(pdata->vbus_pin[i], "ohci_vbus");
++			gpio_direction_output(pdata->vbus_pin[i], 0);
++		}
++	}
++
+ 	device_init_wakeup(&pdev->dev, 1);
+ 	return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
+ }
+ 
+ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
+ {
++	struct at91_usbh_data	*pdata = pdev->dev.platform_data;
++	int			i;
++
++	if (pdata) {
++		for (i = 0; i < pdata->ports; i++) {
++			if (pdata->vbus_pin[i] <= 0)
++				continue;
++			gpio_direction_output(pdata->vbus_pin[i], 1);
++			gpio_free(pdata->vbus_pin[i]);
++		}
++	}
++
+ 	device_init_wakeup(&pdev->dev, 0);
+ 	return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
+ }
+diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
+index ebab5ce..a22c30a 100644
+--- a/drivers/usb/host/ohci-dbg.c
++++ b/drivers/usb/host/ohci-dbg.c
+@@ -401,6 +401,42 @@ static inline void remove_debug_files (struct ohci_hcd *bus) { }
+ 
+ #else
+ 
++static int debug_async_open(struct inode *, struct file *);
++static int debug_periodic_open(struct inode *, struct file *);
++static int debug_registers_open(struct inode *, struct file *);
++static int debug_async_open(struct inode *, struct file *);
++static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
++static int debug_close(struct inode *, struct file *);
++
++static const struct file_operations debug_async_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_async_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++static const struct file_operations debug_periodic_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_periodic_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++static const struct file_operations debug_registers_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_registers_open,
++	.read		= debug_output,
++	.release	= debug_close,
++};
++
++static struct dentry *ohci_debug_root;
++
++struct debug_buffer {
++	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
++	struct device *dev;
++	struct mutex mutex;	/* protect filling of buffer */
++	size_t count;		/* number of characters filled into buffer */
++	char *page;
++};
++
+ static ssize_t
+ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+ {
+@@ -467,8 +503,7 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+ 	return count - size;
+ }
+ 
+-static ssize_t
+-show_async (struct class_device *class_dev, char *buf)
++static ssize_t fill_async_buffer(struct debug_buffer *buf)
+ {
+ 	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+@@ -476,25 +511,23 @@ show_async (struct class_device *class_dev, char *buf)
+ 	size_t			temp;
+ 	unsigned long		flags;
+ 
+-	bus = class_get_devdata(class_dev);
++	bus = dev_get_drvdata(buf->dev);
+ 	hcd = bus_to_hcd(bus);
+ 	ohci = hcd_to_ohci(hcd);
+ 
+ 	/* display control and bulk lists together, for simplicity */
+ 	spin_lock_irqsave (&ohci->lock, flags);
+-	temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);
+-	temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);
++	temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
++	temp += show_list(ohci, buf->page + temp, buf->count - temp,
++			  ohci->ed_bulktail);
+ 	spin_unlock_irqrestore (&ohci->lock, flags);
+ 
+ 	return temp;
+ }
+-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+-
+ 
+ #define DBG_SCHED_LIMIT 64
+ 
+-static ssize_t
+-show_periodic (struct class_device *class_dev, char *buf)
++static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+ {
+ 	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+@@ -509,10 +542,10 @@ show_periodic (struct class_device *class_dev, char *buf)
+ 		return 0;
+ 	seen_count = 0;
+ 
+-	bus = class_get_devdata(class_dev);
++	bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
+ 	hcd = bus_to_hcd(bus);
+ 	ohci = hcd_to_ohci(hcd);
+-	next = buf;
++	next = buf->page;
+ 	size = PAGE_SIZE;
+ 
+ 	temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
+@@ -589,13 +622,9 @@ show_periodic (struct class_device *class_dev, char *buf)
+ 
+ 	return PAGE_SIZE - size;
+ }
+-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+-
+-
+ #undef DBG_SCHED_LIMIT
+ 
+-static ssize_t
+-show_registers (struct class_device *class_dev, char *buf)
++static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+ {
+ 	struct usb_bus		*bus;
+ 	struct usb_hcd		*hcd;
+@@ -606,11 +635,11 @@ show_registers (struct class_device *class_dev, char *buf)
+ 	char			*next;
+ 	u32			rdata;
+ 
+-	bus = class_get_devdata(class_dev);
++	bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
+ 	hcd = bus_to_hcd(bus);
+ 	ohci = hcd_to_ohci(hcd);
+ 	regs = ohci->regs;
+-	next = buf;
++	next = buf->page;
+ 	size = PAGE_SIZE;
+ 
+ 	spin_lock_irqsave (&ohci->lock, flags);
+@@ -677,29 +706,155 @@ show_registers (struct class_device *class_dev, char *buf)
+ 
+ done:
+ 	spin_unlock_irqrestore (&ohci->lock, flags);
++
+ 	return PAGE_SIZE - size;
+ }
+-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+ 
++static struct debug_buffer *alloc_buffer(struct device *dev,
++				ssize_t (*fill_func)(struct debug_buffer *))
++{
++	struct debug_buffer *buf;
++
++	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+ 
++	if (buf) {
++		buf->dev = dev;
++		buf->fill_func = fill_func;
++		mutex_init(&buf->mutex);
++	}
++
++	return buf;
++}
++
++static int fill_buffer(struct debug_buffer *buf)
++{
++	int ret = 0;
++
++	if (!buf->page)
++		buf->page = (char *)get_zeroed_page(GFP_KERNEL);
++
++	if (!buf->page) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = buf->fill_func(buf);
++
++	if (ret >= 0) {
++		buf->count = ret;
++		ret = 0;
++	}
++
++out:
++	return ret;
++}
++
++static ssize_t debug_output(struct file *file, char __user *user_buf,
++			size_t len, loff_t *offset)
++{
++	struct debug_buffer *buf = file->private_data;
++	int ret = 0;
++
++	mutex_lock(&buf->mutex);
++	if (buf->count == 0) {
++		ret = fill_buffer(buf);
++		if (ret != 0) {
++			mutex_unlock(&buf->mutex);
++			goto out;
++		}
++	}
++	mutex_unlock(&buf->mutex);
++
++	ret = simple_read_from_buffer(user_buf, len, offset,
++				      buf->page, buf->count);
++
++out:
++	return ret;
++
++}
++
++static int debug_close(struct inode *inode, struct file *file)
++{
++	struct debug_buffer *buf = file->private_data;
++
++	if (buf) {
++		if (buf->page)
++			free_page((unsigned long)buf->page);
++		kfree(buf);
++	}
++
++	return 0;
++}
++static int debug_async_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static int debug_periodic_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private,
++					  fill_periodic_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static int debug_registers_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private,
++					  fill_registers_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
+ static inline void create_debug_files (struct ohci_hcd *ohci)
+ {
+-	struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
+-	int retval;
++	struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
++	struct device *dev = bus->dev;
++
++	ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
++	if (!ohci->debug_dir)
++		goto dir_error;
++
++	ohci->debug_async = debugfs_create_file("async", S_IRUGO,
++						ohci->debug_dir, dev,
++						&debug_async_fops);
++	if (!ohci->debug_async)
++		goto async_error;
++
++	ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
++						   ohci->debug_dir, dev,
++						   &debug_periodic_fops);
++	if (!ohci->debug_periodic)
++		goto periodic_error;
++
++	ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
++						    ohci->debug_dir, dev,
++						    &debug_registers_fops);
++	if (!ohci->debug_registers)
++		goto registers_error;
+ 
+-	retval = class_device_create_file(cldev, &class_device_attr_async);
+-	retval = class_device_create_file(cldev, &class_device_attr_periodic);
+-	retval = class_device_create_file(cldev, &class_device_attr_registers);
+ 	ohci_dbg (ohci, "created debug files\n");
++	return;
++
++registers_error:
++	debugfs_remove(ohci->debug_periodic);
++periodic_error:
++	debugfs_remove(ohci->debug_async);
++async_error:
++	debugfs_remove(ohci->debug_dir);
++dir_error:
++	ohci->debug_periodic = NULL;
++	ohci->debug_async = NULL;
++	ohci->debug_dir = NULL;
+ }
+ 
+ static inline void remove_debug_files (struct ohci_hcd *ohci)
+ {
+-	struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
+-
+-	class_device_remove_file(cldev, &class_device_attr_async);
+-	class_device_remove_file(cldev, &class_device_attr_periodic);
+-	class_device_remove_file(cldev, &class_device_attr_registers);
++	debugfs_remove(ohci->debug_registers);
++	debugfs_remove(ohci->debug_periodic);
++	debugfs_remove(ohci->debug_async);
++	debugfs_remove(ohci->debug_dir);
+ }
+ 
+ #endif
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index ecfe800..dd4798e 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -36,6 +36,7 @@
+ #include <linux/dmapool.h>
+ #include <linux/reboot.h>
+ #include <linux/workqueue.h>
++#include <linux/debugfs.h>
+ 
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -809,13 +810,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
+ 	}
+ 
+ 	if (ints & OHCI_INTR_WDH) {
+-		if (HC_IS_RUNNING(hcd->state))
+-			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
+ 		spin_lock (&ohci->lock);
+ 		dl_done_list (ohci);
+ 		spin_unlock (&ohci->lock);
+-		if (HC_IS_RUNNING(hcd->state))
+-			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
+ 	}
+ 
+ 	if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+@@ -997,7 +994,7 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
+ #endif
+ 
+-#ifdef CONFIG_PXA27x
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ #include "ohci-pxa27x.c"
+ #define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
+ #endif
+@@ -1032,6 +1029,13 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
+ #endif
+ 
++#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
++    defined(CONFIG_CPU_SUBTYPE_SH7763)
++#include "ohci-sh.c"
++#define PLATFORM_DRIVER		ohci_hcd_sh_driver
++#endif
++
+ 
+ #ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+ #include "ohci-ppc-of.c"
+@@ -1048,6 +1052,11 @@ MODULE_LICENSE ("GPL");
+ #define SSB_OHCI_DRIVER		ssb_ohci_driver
+ #endif
+ 
++#ifdef CONFIG_MFD_SM501
++#include "ohci-sm501.c"
++#define PLATFORM_DRIVER		ohci_hcd_sm501_driver
++#endif
++
+ #if	!defined(PCI_DRIVER) &&		\
+ 	!defined(PLATFORM_DRIVER) &&	\
+ 	!defined(OF_PLATFORM_DRIVER) &&	\
+@@ -1068,6 +1077,14 @@ static int __init ohci_hcd_mod_init(void)
+ 	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+ 		sizeof (struct ed), sizeof (struct td));
+ 
++#ifdef DEBUG
++	ohci_debug_root = debugfs_create_dir("ohci", NULL);
++	if (!ohci_debug_root) {
++		retval = -ENOENT;
++		goto error_debug;
++	}
++#endif
++
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ 	if (retval < 0)
+@@ -1130,6 +1147,12 @@ static int __init ohci_hcd_mod_init(void)
+ 	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+  error_ps3:
+ #endif
++#ifdef DEBUG
++	debugfs_remove(ohci_debug_root);
++	ohci_debug_root = NULL;
++ error_debug:
++#endif
++
+ 	return retval;
+ }
+ module_init(ohci_hcd_mod_init);
+@@ -1154,6 +1177,9 @@ static void __exit ohci_hcd_mod_exit(void)
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ #endif
++#ifdef DEBUG
++	debugfs_remove(ohci_debug_root);
++#endif
+ }
+ module_exit(ohci_hcd_mod_exit);
+ 
+diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
+index 5cfa3d1..74e1f4b 100644
+--- a/drivers/usb/host/ohci-omap.c
++++ b/drivers/usb/host/ohci-omap.c
+@@ -47,7 +47,7 @@
+ #endif
+ 
+ #ifdef CONFIG_TPS65010
+-#include <asm/arch/tps65010.h>
++#include <linux/i2c/tps65010.h>
+ #else
+ 
+ #define LOW	0
+diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
+index ca2a6ab..6c52c66 100644
+--- a/drivers/usb/host/ohci-pnx4008.c
++++ b/drivers/usb/host/ohci-pnx4008.c
+@@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client);
+ static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ 			   void *arg);
+ 
+-static unsigned short normal_i2c[] =
++static const unsigned short normal_i2c[] =
+     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+-static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
++static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+ 
+ static struct i2c_client_address_data addr_data = {
+ 	.normal_i2c = normal_i2c,
+@@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = {
+ };
+ 
+ struct i2c_driver isp1301_driver = {
+-	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
+ 	.class = I2C_CLASS_HWMON,
+ 	.attach_adapter = isp1301_probe,
+ 	.detach_client = isp1301_detach,
+diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
+index 0c3e6b7..a672527 100644
+--- a/drivers/usb/host/ohci-ppc-of.c
++++ b/drivers/usb/host/ohci-ppc-of.c
+@@ -136,6 +136,8 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+ 	ohci = hcd_to_ohci(hcd);
+ 	if (is_bigendian) {
+ 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
++		if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
++			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ 		if (of_device_is_compatible(dn, "mpc5200-ohci"))
+ 			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ 	}
+diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
+index 23d2fe5..ff9a798 100644
+--- a/drivers/usb/host/ohci-pxa27x.c
++++ b/drivers/usb/host/ohci-pxa27x.c
+@@ -22,6 +22,7 @@
+ #include <linux/device.h>
+ #include <linux/signal.h>
+ #include <linux/platform_device.h>
++#include <linux/clk.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/hardware.h>
+@@ -32,6 +33,8 @@
+ 
+ #define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
+ 
++static struct clk *usb_clk;
++
+ /*
+   PMM_NPS_MODE -- PMM Non-power switching mode
+       Ports are powered continuously.
+@@ -80,7 +83,7 @@ static int pxa27x_start_hc(struct device *dev)
+ 
+ 	inf = dev->platform_data;
+ 
+-	pxa_set_cken(CKEN_USBHOST, 1);
++	clk_enable(usb_clk);
+ 
+ 	UHCHR |= UHCHR_FHR;
+ 	udelay(11);
+@@ -123,7 +126,7 @@ static void pxa27x_stop_hc(struct device *dev)
+ 	UHCCOMS |= 1;
+ 	udelay(10);
+ 
+-	pxa_set_cken(CKEN_USBHOST, 0);
++	clk_disable(usb_clk);
+ }
+ 
+ 
+@@ -158,6 +161,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
+ 		return -ENOMEM;
+ 	}
+ 
++	usb_clk = clk_get(&pdev->dev, "USBCLK");
++	if (IS_ERR(usb_clk))
++		return PTR_ERR(usb_clk);
++
+ 	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
+ 	if (!hcd)
+ 		return -ENOMEM;
+@@ -201,6 +208,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+  err1:
+ 	usb_put_hcd(hcd);
++	clk_put(usb_clk);
+ 	return retval;
+ }
+ 
+@@ -225,6 +233,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+ 	iounmap(hcd->regs);
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ 	usb_put_hcd(hcd);
++	clk_put(usb_clk);
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
+new file mode 100644
+index 0000000..5309ac0
+--- /dev/null
++++ b/drivers/usb/host/ohci-sh.c
+@@ -0,0 +1,143 @@
++/*
++ * OHCI HCD (Host Controller Driver) for USB.
++ *
++ * Copyright (C) 2008 Renesas Solutions Corp.
++ *
++ * Author : Yoshihiro Shimoda <shimoda.yoshihiro at renesas.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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ *
++ */
++
++#include <linux/platform_device.h>
++
++static int ohci_sh_start(struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
++
++	ohci_hcd_init(ohci);
++	ohci_init(ohci);
++	ohci_run(ohci);
++	hcd->state = HC_STATE_RUNNING;
++	return 0;
++}
++
++static const struct hc_driver ohci_sh_hc_driver = {
++	.description =		hcd_name,
++	.product_desc =		"SuperH OHCI",
++	.hcd_priv_size =	sizeof(struct ohci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ohci_irq,
++	.flags =		HCD_USB11 | HCD_MEMORY,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.start =		ohci_sh_start,
++	.stop =			ohci_stop,
++	.shutdown =		ohci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ohci_urb_enqueue,
++	.urb_dequeue =		ohci_urb_dequeue,
++	.endpoint_disable =	ohci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ohci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ohci_hub_status_data,
++	.hub_control =		ohci_hub_control,
++	.hub_irq_enable =	ohci_rhsc_enable,
++#ifdef	CONFIG_PM
++	.bus_suspend =		ohci_bus_suspend,
++	.bus_resume =		ohci_bus_resume,
++#endif
++	.start_port_reset =	ohci_start_port_reset,
++};
++
++/*-------------------------------------------------------------------------*/
++
++#define resource_len(r) (((r)->end - (r)->start) + 1)
++static int ohci_hcd_sh_probe(struct platform_device *pdev)
++{
++	struct resource *res = NULL;
++	struct usb_hcd *hcd = NULL;
++	int irq = -1;
++	int ret;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		err("platform_get_resource error.");
++		return -ENODEV;
++	}
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		err("platform_get_irq error.");
++		return -ENODEV;
++	}
++
++	/* initialize hcd */
++	hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
++	if (!hcd) {
++		err("Failed to create hcd");
++		return -ENOMEM;
++	}
++
++	hcd->regs = (void __iomem *)res->start;
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = resource_len(res);
++	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++	if (ret != 0) {
++		err("Failed to add hcd");
++		usb_put_hcd(hcd);
++		return ret;
++	}
++
++	return ret;
++}
++
++static int ohci_hcd_sh_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++	usb_remove_hcd(hcd);
++	usb_put_hcd(hcd);
++
++	return 0;
++}
++
++static struct platform_driver ohci_hcd_sh_driver = {
++	.probe		= ohci_hcd_sh_probe,
++	.remove		= ohci_hcd_sh_remove,
++	.shutdown	= usb_hcd_platform_shutdown,
++	.driver		= {
++		.name	= "sh_ohci",
++		.owner	= THIS_MODULE,
++	},
++};
++
+diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
+new file mode 100644
+index 0000000..a970701
+--- /dev/null
++++ b/drivers/usb/host/ohci-sm501.c
+@@ -0,0 +1,264 @@
++/*
++ * OHCI HCD (Host Controller Driver) for USB.
++ *
++ * (C) Copyright 1999 Roman Weissgaerber <weissg at vienna.at>
++ * (C) Copyright 2000-2005 David Brownell
++ * (C) Copyright 2002 Hewlett-Packard Company
++ * (C) Copyright 2008 Magnus Damm
++ *
++ * SM501 Bus Glue - based on ohci-omap.c
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/sm501.h>
++#include <linux/sm501-regs.h>
++
++static int ohci_sm501_init(struct usb_hcd *hcd)
++{
++	return ohci_init(hcd_to_ohci(hcd));
++}
++
++static int ohci_sm501_start(struct usb_hcd *hcd)
++{
++	struct device *dev = hcd->self.controller;
++	int ret;
++
++	ret = ohci_run(hcd_to_ohci(hcd));
++	if (ret < 0) {
++		dev_err(dev, "can't start %s", hcd->self.bus_name);
++		ohci_stop(hcd);
++	}
++
++	return ret;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static const struct hc_driver ohci_sm501_hc_driver = {
++	.description =		hcd_name,
++	.product_desc =		"SM501 OHCI",
++	.hcd_priv_size =	sizeof(struct ohci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ohci_irq,
++	.flags =		HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset =		ohci_sm501_init,
++	.start =		ohci_sm501_start,
++	.stop =			ohci_stop,
++	.shutdown =		ohci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ohci_urb_enqueue,
++	.urb_dequeue =		ohci_urb_dequeue,
++	.endpoint_disable =	ohci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ohci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ohci_hub_status_data,
++	.hub_control =		ohci_hub_control,
++	.hub_irq_enable =	ohci_rhsc_enable,
++#ifdef	CONFIG_PM
++	.bus_suspend =		ohci_bus_suspend,
++	.bus_resume =		ohci_bus_resume,
++#endif
++	.start_port_reset =	ohci_start_port_reset,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
++{
++	const struct hc_driver *driver = &ohci_sm501_hc_driver;
++	struct device *dev = &pdev->dev;
++	struct resource	*res, *mem;
++	int retval, irq;
++	struct usb_hcd *hcd = 0;
++
++	irq = retval = platform_get_irq(pdev, 0);
++	if (retval < 0)
++		goto err0;
++
++	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	if (mem == NULL) {
++		dev_err(dev, "no resource definition for memory\n");
++		retval = -ENOENT;
++		goto err0;
++	}
++
++	if (!request_mem_region(mem->start, mem->end - mem->start + 1,
++				pdev->name)) {
++		dev_err(dev, "request_mem_region failed\n");
++		retval = -EBUSY;
++		goto err0;
++	}
++
++	/* The sm501 chip is equipped with local memory that may be used
++	 * by on-chip devices such as the video controller and the usb host.
++	 * This driver uses dma_declare_coherent_memory() to make sure
++	 * usb allocations with dma_alloc_coherent() allocate from
++	 * this local memory. The dma_handle returned by dma_alloc_coherent()
++	 * will be an offset starting from 0 for the first local memory byte.
++	 *
++	 * So as long as data is allocated using dma_alloc_coherent() all is
++	 * fine. This is however not always the case - buffers may be allocated
++	 * using kmalloc() - so the usb core needs to be told that it must copy
++	 * data into our local memory if the buffers happen to be placed in
++	 * regular memory. The HCD_LOCAL_MEM flag does just that.
++	 */
++
++	if (!dma_declare_coherent_memory(dev, mem->start,
++					 mem->start - mem->parent->start,
++					 (mem->end - mem->start) + 1,
++					 DMA_MEMORY_MAP |
++					 DMA_MEMORY_EXCLUSIVE)) {
++		dev_err(dev, "cannot declare coherent memory\n");
++		retval = -ENXIO;
++		goto err1;
++	}
++
++	/* allocate, reserve and remap resources for registers */
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (res == NULL) {
++		dev_err(dev, "no resource definition for registers\n");
++		retval = -ENOENT;
++		goto err2;
++	}
++
++	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
++	if (!hcd) {
++		retval = -ENOMEM;
++		goto err2;
++	}
++
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = res->end - res->start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,	pdev->name)) {
++		dev_err(dev, "request_mem_region failed\n");
++		retval = -EBUSY;
++		goto err3;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (hcd->regs == NULL) {
++		dev_err(dev, "cannot remap registers\n");
++		retval = -ENXIO;
++		goto err4;
++	}
++
++	ohci_hcd_init(hcd_to_ohci(hcd));
++
++	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++	if (retval)
++		goto err4;
++
++	/* enable power and unmask interrupts */
++
++	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
++	sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
++
++	return 0;
++err4:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err3:
++	usb_put_hcd(hcd);
++err2:
++	dma_release_declared_memory(dev);
++err1:
++	release_mem_region(mem->start, mem->end - mem->start + 1);
++err0:
++	return retval;
++}
++
++static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++	struct resource	*mem;
++
++	usb_remove_hcd(hcd);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++	dma_release_declared_memory(&pdev->dev);
++	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	release_mem_region(mem->start, mem->end - mem->start + 1);
++
++	/* mask interrupts and disable power */
++
++	sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
++	sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
++
++	platform_set_drvdata(pdev, NULL);
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_PM
++static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
++{
++	struct device *dev = &pdev->dev;
++	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(pdev));
++
++	if (time_before(jiffies, ohci->next_statechange))
++		msleep(5);
++	ohci->next_statechange = jiffies;
++
++	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
++	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
++	dev->power.power_state = PMSG_SUSPEND;
++	return 0;
++}
++
++static int ohci_sm501_resume(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(pdev));
++
++	if (time_before(jiffies, ohci->next_statechange))
++		msleep(5);
++	ohci->next_statechange = jiffies;
++
++	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
++	dev->power.power_state = PMSG_ON;
++	usb_hcd_resume_root_hub(platform_get_drvdata(pdev));
++	return 0;
++}
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * Driver definition to register with the SM501 bus
++ */
++static struct platform_driver ohci_hcd_sm501_driver = {
++	.probe		= ohci_hcd_sm501_drv_probe,
++	.remove		= ohci_hcd_sm501_drv_remove,
++	.shutdown	= usb_hcd_platform_shutdown,
++#ifdef	CONFIG_PM
++	.suspend	= ohci_sm501_suspend,
++	.resume		= ohci_sm501_resume,
++#endif
++	.driver		= {
++		.owner	= THIS_MODULE,
++		.name	= "sm501-usb",
++	},
++};
+diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
+index 47c5c66..dc544dd 100644
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -408,6 +408,13 @@ struct ohci_hcd {
+ 	unsigned		eds_scheduled;
+ 	struct ed		*ed_to_check;
+ 	unsigned		zf_delay;
++
++#ifdef DEBUG
++	struct dentry		*debug_dir;
++	struct dentry		*debug_async;
++	struct dentry		*debug_periodic;
++	struct dentry		*debug_registers;
++#endif
+ };
+ 
+ #ifdef CONFIG_PCI
+diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
+index c225159..0ee694f 100644
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -190,9 +190,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
+ 			msleep(10);
+ 		}
+ 		if (wait_time <= 0)
+-			printk(KERN_WARNING "%s %s: BIOS handoff "
+-					"failed (BIOS bug ?) %08x\n",
+-					pdev->dev.bus_id, "OHCI",
++			dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
++					" (BIOS bug?) %08x\n",
+ 					readl(base + OHCI_CONTROL));
+ 
+ 		/* reset controller, preserving RWC */
+@@ -243,8 +242,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+ 		switch (cap & 0xff) {
+ 		case 1:			/* BIOS/SMM/... handoff support */
+ 			if ((cap & EHCI_USBLEGSUP_BIOS)) {
+-				pr_debug("%s %s: BIOS handoff\n",
+-						pdev->dev.bus_id, "EHCI");
++				dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
+ 
+ #if 0
+ /* aleksey_gorelov at phoenix.com reports that some systems need SMI forced on,
+@@ -285,9 +283,8 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+ 				/* well, possibly buggy BIOS... try to shut
+ 				 * it down, and hope nothing goes too wrong
+ 				 */
+-				printk(KERN_WARNING "%s %s: BIOS handoff "
+-						"failed (BIOS bug ?) %08x\n",
+-					pdev->dev.bus_id, "EHCI", cap);
++				dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
++						" (BIOS bug?) %08x\n", cap);
+ 				pci_write_config_byte(pdev, offset + 2, 0);
+ 			}
+ 
+@@ -306,17 +303,14 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+ 			cap = 0;
+ 			/* FALLTHROUGH */
+ 		default:
+-			printk(KERN_WARNING "%s %s: unrecognized "
+-					"capability %02x\n",
+-					pdev->dev.bus_id, "EHCI",
+-					cap & 0xff);
++			dev_warn(&pdev->dev, "EHCI: unrecognized capability "
++					"%02x\n", cap & 0xff);
+ 			break;
+ 		}
+ 		offset = (cap >> 8) & 0xff;
+ 	}
+ 	if (!count)
+-		printk(KERN_DEBUG "%s %s: capability loop?\n",
+-				pdev->dev.bus_id, "EHCI");
++		dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n");
+ 
+ 	/*
+ 	 * halt EHCI & disable its interrupts in any case
+diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
+index fe9ceb0..5738825 100644
+--- a/drivers/usb/host/r8a66597.h
++++ b/drivers/usb/host/r8a66597.h
+@@ -405,7 +405,7 @@
+ 
+ struct r8a66597_pipe_info {
+ 	u16 pipenum;
+-	u16 address;	/* R8A66597 HCD usb addres */
++	u16 address;	/* R8A66597 HCD usb address */
+ 	u16 epnum;
+ 	u16 maxpacket;
+ 	u16 type;
+diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
+index d1131a8..0fb114c 100644
+--- a/drivers/usb/image/mdc800.c
++++ b/drivers/usb/image/mdc800.c
+@@ -478,8 +478,6 @@ static int mdc800_usb_probe (struct usb_interface *intf,
+ 				{
+ 					irq_interval=intf_desc->endpoint [j].desc.bInterval;
+ 				}
+-
+-				continue;
+ 			}
+ 		}
+ 		if (mdc800->endpoint[i] == -1)
+diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
+index d721380..9379404 100644
+--- a/drivers/usb/misc/cypress_cy7c63.c
++++ b/drivers/usb/misc/cypress_cy7c63.c
+@@ -1,7 +1,7 @@
+ /*
+ * cypress_cy7c63.c
+ *
+-* Copyright (c) 2006 Oliver Bock (o.bock at fh-wolfenbuettel.de)
++* Copyright (c) 2006-2007 Oliver Bock (bock at tfh-berlin.de)
+ *
+ *	This driver is based on the Cypress USB Driver by Marcus Maul
+ *	(cyport) and the 2.0 version of Greg Kroah-Hartman's
+@@ -21,6 +21,9 @@
+ *	Supported functions:	Read/Write Ports
+ *
+ *
++*	For up-to-date information please visit:
++*	http://www.obock.de/kernel/cypress
++*
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+@@ -31,7 +34,7 @@
+ #include <linux/kernel.h>
+ #include <linux/usb.h>
+ 
+-#define DRIVER_AUTHOR		"Oliver Bock (o.bock at fh-wolfenbuettel.de)"
++#define DRIVER_AUTHOR		"Oliver Bock (bock at tfh-berlin.de)"
+ #define DRIVER_DESC		"Cypress CY7C63xxx USB driver"
+ 
+ #define CYPRESS_VENDOR_ID	0xa2c
+diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
+index 764696f..8010705 100644
+--- a/drivers/usb/misc/iowarrior.c
++++ b/drivers/usb/misc/iowarrior.c
+@@ -715,7 +715,7 @@ static unsigned iowarrior_poll(struct file *file, poll_table * wait)
+  * would use "struct net_driver" instead, and a serial
+  * device would use "struct tty_driver".
+  */
+-static struct file_operations iowarrior_fops = {
++static const struct file_operations iowarrior_fops = {
+ 	.owner = THIS_MODULE,
+ 	.write = iowarrior_write,
+ 	.read = iowarrior_read,
+diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
+index aab3200..6664043 100644
+--- a/drivers/usb/misc/legousbtower.c
++++ b/drivers/usb/misc/legousbtower.c
+@@ -205,7 +205,7 @@ static DEFINE_MUTEX(open_disc_mutex);
+ 
+ /* Structure to hold all of our device specific stuff */
+ struct lego_usb_tower {
+-	struct semaphore	sem;		/* locks this structure */
++	struct mutex		lock;		/* locks this structure */
+ 	struct usb_device*	udev;		/* save off the usb device pointer */
+ 	unsigned char		minor;		/* the starting minor number for this device */
+ 
+@@ -361,7 +361,7 @@ static int tower_open (struct inode *inode, struct file *file)
+ 	}
+ 
+ 	/* lock this device */
+-	if (down_interruptible (&dev->sem)) {
++	if (mutex_lock_interruptible(&dev->lock)) {
+ 		mutex_unlock(&open_disc_mutex);
+ 	        retval = -ERESTARTSYS;
+ 		goto exit;
+@@ -421,7 +421,7 @@ static int tower_open (struct inode *inode, struct file *file)
+ 	file->private_data = dev;
+ 
+ unlock_exit:
+-	up (&dev->sem);
++	mutex_unlock(&dev->lock);
+ 
+ exit:
+ 	dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
+@@ -448,7 +448,7 @@ static int tower_release (struct inode *inode, struct file *file)
+ 	}
+ 
+ 	mutex_lock(&open_disc_mutex);
+-	if (down_interruptible (&dev->sem)) {
++	if (mutex_lock_interruptible(&dev->lock)) {
+ 	        retval = -ERESTARTSYS;
+ 		goto exit;
+ 	}
+@@ -460,7 +460,9 @@ static int tower_release (struct inode *inode, struct file *file)
+ 	}
+ 	if (dev->udev == NULL) {
+ 		/* the device was unplugged before the file was released */
+-		up (&dev->sem);	/* unlock here as tower_delete frees dev */
++
++		/* unlock here as tower_delete frees dev */
++		mutex_unlock(&dev->lock);
+ 		tower_delete (dev);
+ 		goto exit;
+ 	}
+@@ -473,7 +475,7 @@ static int tower_release (struct inode *inode, struct file *file)
+ 	dev->open_count = 0;
+ 
+ unlock_exit:
+-	up (&dev->sem);
++	mutex_unlock(&dev->lock);
+ 
+ exit:
+ 	mutex_unlock(&open_disc_mutex);
+@@ -586,7 +588,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
+ 	dev = (struct lego_usb_tower *)file->private_data;
+ 
+ 	/* lock this object */
+-	if (down_interruptible (&dev->sem)) {
++	if (mutex_lock_interruptible(&dev->lock)) {
+ 		retval = -ERESTARTSYS;
+ 		goto exit;
+ 	}
+@@ -653,7 +655,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
+ 
+ unlock_exit:
+ 	/* unlock the device */
+-	up (&dev->sem);
++	mutex_unlock(&dev->lock);
+ 
+ exit:
+ 	dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+@@ -675,7 +677,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
+ 	dev = (struct lego_usb_tower *)file->private_data;
+ 
+ 	/* lock this object */
+-	if (down_interruptible (&dev->sem)) {
++	if (mutex_lock_interruptible(&dev->lock)) {
+ 		retval = -ERESTARTSYS;
+ 		goto exit;
+ 	}
+@@ -737,7 +739,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
+ 
+ unlock_exit:
+ 	/* unlock the device */
+-	up (&dev->sem);
++	mutex_unlock(&dev->lock);
+ 
+ exit:
+ 	dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
+@@ -862,7 +864,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
+ 		goto exit;
+ 	}
+ 
+-	init_MUTEX (&dev->sem);
++	mutex_init(&dev->lock);
+ 
+ 	dev->udev = udev;
+ 	dev->open_count = 0;
+@@ -1007,16 +1009,16 @@ static void tower_disconnect (struct usb_interface *interface)
+ 	/* give back our minor */
+ 	usb_deregister_dev (interface, &tower_class);
+ 
+-	down (&dev->sem);
++	mutex_lock(&dev->lock);
+ 	mutex_unlock(&open_disc_mutex);
+ 
+ 	/* if the device is not opened, then we clean up right now */
+ 	if (!dev->open_count) {
+-		up (&dev->sem);
++		mutex_unlock(&dev->lock);
+ 		tower_delete (dev);
+ 	} else {
+ 		dev->udev = NULL;
+-		up (&dev->sem);
++		mutex_unlock(&dev->lock);
+ 	}
+ 
+ 	info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
+diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
+index 9244d06..cb7fa0e 100644
+--- a/drivers/usb/misc/sisusbvga/sisusb.c
++++ b/drivers/usb/misc/sisusbvga/sisusb.c
+@@ -323,7 +323,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
+ 			usb_kill_urb(urb);
+ 			retval = -ETIMEDOUT;
+ 		} else {
+-			/* URB completed within timout */
++			/* URB completed within timeout */
+ 			retval = urb->status;
+ 			readbytes = urb->actual_length;
+ 		}
+@@ -3195,20 +3195,6 @@ static int sisusb_probe(struct usb_interface *intf,
+ 
+ 	sisusb->present = 1;
+ 
+-#ifdef SISUSB_OLD_CONFIG_COMPAT
+-	{
+-	int ret;
+-	/* Our ioctls are all "32/64bit compatible" */
+-	ret =  register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
+-	ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
+-	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
+-	if (ret)
+-		dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
+-	else
+-		sisusb->ioctl32registered = 1;
+-	}
+-#endif
+-
+ 	if (dev->speed == USB_SPEED_HIGH) {
+ 		int initscreen = 1;
+ #ifdef INCL_SISUSB_CON
+@@ -3271,19 +3257,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
+ 
+ 	usb_set_intfdata(intf, NULL);
+ 
+-#ifdef SISUSB_OLD_CONFIG_COMPAT
+-	if (sisusb->ioctl32registered) {
+-		int ret;
+-		sisusb->ioctl32registered = 0;
+-		ret =  unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
+-		ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
+-		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
+-		if (ret) {
+-			dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
+-		}
+-	}
+-#endif
+-
+ 	sisusb->present = 0;
+ 	sisusb->ready = 0;
+ 
+diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
+index d2d7872..cf0b4a5 100644
+--- a/drivers/usb/misc/sisusbvga/sisusb.h
++++ b/drivers/usb/misc/sisusbvga/sisusb.h
+@@ -120,9 +120,6 @@ struct sisusb_usb_data {
+ 	int isopen;		/* !=0 if open */
+ 	int present;		/* !=0 if device is present on the bus */
+ 	int ready;		/* !=0 if device is ready for userland */
+-#ifdef SISUSB_OLD_CONFIG_COMPAT
+-	int ioctl32registered;
+-#endif
+ 	int numobufs;		/* number of obufs = number of out urbs */
+ 	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
+ 	int obufsize, ibufsize;
+diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
+index ea31621..da922df 100644
+--- a/drivers/usb/misc/usbtest.c
++++ b/drivers/usb/misc/usbtest.c
+@@ -6,6 +6,7 @@
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/scatterlist.h>
++#include <linux/mutex.h>
+ 
+ #include <linux/usb.h>
+ 
+@@ -64,7 +65,7 @@ struct usbtest_dev {
+ 	int			in_iso_pipe;
+ 	int			out_iso_pipe;
+ 	struct usb_endpoint_descriptor	*iso_in, *iso_out;
+-	struct semaphore	sem;
++	struct mutex		lock;
+ 
+ #define TBUF_SIZE	256
+ 	u8			*buf;
+@@ -1151,6 +1152,7 @@ static int verify_halted (int ep, struct urb *urb)
+ 		dbg ("ep %02x couldn't get halt status, %d", ep, retval);
+ 		return retval;
+ 	}
++	le16_to_cpus(&status);
+ 	if (status != 1) {
+ 		dbg ("ep %02x bogus status: %04x != 1", ep, status);
+ 		return -EINVAL;
+@@ -1310,7 +1312,7 @@ static int ctrl_out (struct usbtest_dev *dev,
+ 		len += vary;
+ 
+ 		/* [real world] the "zero bytes IN" case isn't really used.
+-		 * hardware can easily trip up in this wierd case, since its
++		 * hardware can easily trip up in this weird case, since its
+ 		 * status stage is IN, not OUT like other ep0in transfers.
+ 		 */
+ 		if (len > length)
+@@ -1558,11 +1560,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
+ 			|| param->sglen < 0 || param->vary < 0)
+ 		return -EINVAL;
+ 
+-	if (down_interruptible (&dev->sem))
++	if (mutex_lock_interruptible(&dev->lock))
+ 		return -ERESTARTSYS;
+ 
+ 	if (intf->dev.power.power_state.event != PM_EVENT_ON) {
+-		up (&dev->sem);
++		mutex_unlock(&dev->lock);
+ 		return -EHOSTUNREACH;
+ 	}
+ 
+@@ -1574,7 +1576,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
+ 	    	int	res;
+ 
+ 		if (intf->altsetting->desc.bInterfaceNumber) {
+-			up (&dev->sem);
++			mutex_unlock(&dev->lock);
+ 			return -ENODEV;
+ 		}
+ 		res = set_altsetting (dev, dev->info->alt);
+@@ -1582,7 +1584,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
+ 			dev_err (&intf->dev,
+ 					"set altsetting to %d failed, %d\n",
+ 					dev->info->alt, res);
+-			up (&dev->sem);
++			mutex_unlock(&dev->lock);
+ 			return res;
+ 		}
+ 	}
+@@ -1855,7 +1857,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
+ 		param->duration.tv_usec += 1000 * 1000;
+ 		param->duration.tv_sec -= 1;
+ 	}
+-	up (&dev->sem);
++	mutex_unlock(&dev->lock);
+ 	return retval;
+ }
+ 
+@@ -1905,7 +1907,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
+ 		return -ENOMEM;
+ 	info = (struct usbtest_info *) id->driver_info;
+ 	dev->info = info;
+-	init_MUTEX (&dev->sem);
++	mutex_init(&dev->lock);
+ 
+ 	dev->intf = intf;
+ 
+@@ -1990,8 +1992,6 @@ static void usbtest_disconnect (struct usb_interface *intf)
+ {
+ 	struct usbtest_dev	*dev = usb_get_intfdata (intf);
+ 
+-	down (&dev->sem);
+-
+ 	usb_set_intfdata (intf, NULL);
+ 	dev_dbg (&intf->dev, "disconnect\n");
+ 	kfree (dev);
+diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
+index f06e4e2..1774ba5 100644
+--- a/drivers/usb/mon/mon_bin.c
++++ b/drivers/usb/mon/mon_bin.c
+@@ -1026,6 +1026,8 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+ 	return mask;
+ }
+ 
++#if 0
++
+ /*
+  * open and close: just keep track of how many times the device is
+  * mapped, to use the proper memory allocation function.
+@@ -1045,33 +1047,31 @@ static void mon_bin_vma_close(struct vm_area_struct *vma)
+ /*
+  * Map ring pages to user space.
+  */
+-struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+-                                unsigned long address, int *type)
++static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+ {
+ 	struct mon_reader_bin *rp = vma->vm_private_data;
+ 	unsigned long offset, chunk_idx;
+ 	struct page *pageptr;
+ 
+-	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
++	offset = vmf->pgoff << PAGE_SHIFT;
+ 	if (offset >= rp->b_size)
+-		return NOPAGE_SIGBUS;
++		return VM_FAULT_SIGBUS;
+ 	chunk_idx = offset / CHUNK_SIZE;
+ 	pageptr = rp->b_vec[chunk_idx].pg;
+ 	get_page(pageptr);
+-	if (type)
+-		*type = VM_FAULT_MINOR;
+-	return pageptr;
++	vmf->page = pageptr;
++	return 0;
+ }
+ 
+ struct vm_operations_struct mon_bin_vm_ops = {
+ 	.open =     mon_bin_vma_open,
+ 	.close =    mon_bin_vma_close,
+-	.nopage =   mon_bin_vma_nopage,
++	.fault =    mon_bin_vma_fault,
+ };
+ 
+ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+ {
+-	/* don't do anything here: "nopage" will set up page table entries */
++	/* don't do anything here: "fault" will set up page table entries */
+ 	vma->vm_ops = &mon_bin_vm_ops;
+ 	vma->vm_flags |= VM_RESERVED;
+ 	vma->vm_private_data = filp->private_data;
+@@ -1079,7 +1079,9 @@ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+ 	return 0;
+ }
+ 
+-struct file_operations mon_fops_binary = {
++#endif  /*  0  */
++
++static const struct file_operations mon_fops_binary = {
+ 	.owner =	THIS_MODULE,
+ 	.open =		mon_bin_open,
+ 	.llseek =	no_llseek,
+diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
+index 4a86696..c1e65df 100644
+--- a/drivers/usb/serial/Kconfig
++++ b/drivers/usb/serial/Kconfig
+@@ -2,10 +2,7 @@
+ # USB Serial device configuration
+ #
+ 
+-menu "USB Serial Converter support"
+-	depends on USB!=n
+-
+-config USB_SERIAL
++menuconfig USB_SERIAL
+ 	tristate "USB Serial Converter support"
+ 	depends on USB
+ 	---help---
+@@ -20,6 +17,8 @@ config USB_SERIAL
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called usbserial.
+ 
++if USB_SERIAL
++
+ config USB_SERIAL_CONSOLE
+ 	bool "USB Serial Console device support (EXPERIMENTAL)"
+ 	depends on USB_SERIAL=y && EXPERIMENTAL
+@@ -43,6 +42,12 @@ config USB_SERIAL_CONSOLE
+ 
+ 	  If unsure, say N.
+ 
++config USB_EZUSB
++	bool "Functions for loading firmware on EZUSB chips"
++	depends on USB_SERIAL
++	help
++	    Say Y here if you need EZUSB device support.
++
+ config USB_SERIAL_GENERIC
+ 	bool "USB Generic Serial Driver"
+ 	depends on USB_SERIAL
+@@ -105,6 +110,7 @@ config USB_SERIAL_CH341
+ config USB_SERIAL_WHITEHEAT
+ 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
+ 	depends on USB_SERIAL
++	select USB_EZUSB
+ 	help
+ 	  Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
+ 	  USB to serial converter device.
+@@ -282,9 +288,21 @@ config USB_SERIAL_IPW
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ipw.
+ 
++config USB_SERIAL_IUU
++	tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
++	depends on USB_SERIAL && EXPERIMENTAL
++	help
++	  Say Y here if you want to use a IUU in phoenix mode and get
++	  an extra ttyUSBx device. More information available on
++	  http://eczema.ecze.com/iuu_phoenix.html
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called iuu_phoenix.o
++
+ config USB_SERIAL_KEYSPAN_PDA
+ 	tristate "USB Keyspan PDA Single Port Serial Driver"
+ 	depends on USB_SERIAL
++	select USB_EZUSB
+ 	help
+ 	  Say Y here if you want to use a Keyspan PDA single port USB to
+ 	  serial converter device.  This driver makes use of firmware
+@@ -538,6 +557,7 @@ config USB_SERIAL_CYBERJACK
+ config USB_SERIAL_XIRCOM
+ 	tristate "USB Xircom / Entregra Single Port Serial Driver"
+ 	depends on USB_SERIAL
++	select USB_EZUSB
+ 	help
+ 	  Say Y here if you want to use a Xircom or Entregra single port USB to
+ 	  serial converter device.  This driver makes use of firmware
+@@ -585,11 +605,4 @@ config USB_SERIAL_DEBUG
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called usb-debug.
+ 
+-config USB_EZUSB
+-	bool
+-	depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
+-	default y
+-
+-
+-endmenu
+-
++endif # USB_SERIAL
+diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
+index d6fb384..0db109a 100644
+--- a/drivers/usb/serial/Makefile
++++ b/drivers/usb/serial/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN)			+= garmin_gps.o
+ obj-$(CONFIG_USB_SERIAL_HP4X)			+= hp4x.o
+ obj-$(CONFIG_USB_SERIAL_IPAQ)			+= ipaq.o
+ obj-$(CONFIG_USB_SERIAL_IPW)			+= ipw.o
++obj-$(CONFIG_USB_SERIAL_IUU)			+= iuu_phoenix.o
+ obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
+ obj-$(CONFIG_USB_SERIAL_KEYSPAN)		+= keyspan.o
+ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)		+= keyspan_pda.o
+diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
+index 77bb893..f156dba 100644
+--- a/drivers/usb/serial/airprime.c
++++ b/drivers/usb/serial/airprime.c
+@@ -217,7 +217,10 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
+ 	priv->rts_state = 0;
+ 	priv->dtr_state = 0;
+ 
+-	airprime_send_setup(port);
++	mutex_lock(&port->serial->disc_mutex);
++	if (!port->serial->disconnected)
++		airprime_send_setup(port);
++	mutex_lock(&port->serial->disc_mutex);
+ 
+ 	for (i = 0; i < NUM_READ_URBS; ++i) {
+ 		usb_kill_urb (priv->read_urbp[i]);
+diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
+index ddfee91..fe2bfd6 100644
+--- a/drivers/usb/serial/ark3116.c
++++ b/drivers/usb/serial/ark3116.c
+@@ -151,8 +151,10 @@ static int ark3116_attach(struct usb_serial *serial)
+ 	return 0;
+ 
+ cleanup:
+-	for (--i; i >= 0; --i)
++	for (--i; i >= 0; --i) {
++		kfree(usb_get_serial_port_data(serial->port[i]));
+ 		usb_set_serial_port_data(serial->port[i], NULL);
++	}
+ 	return -ENOMEM;
+ }
+ 
+diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
+index 86724e8..df0a2b3 100644
+--- a/drivers/usb/serial/belkin_sa.c
++++ b/drivers/usb/serial/belkin_sa.c
+@@ -350,14 +350,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
+ 	unsigned long control_state;
+ 	int bad_flow_control;
+ 	speed_t baud;
++	struct ktermios *termios = port->tty->termios;
+ 	
+-	if ((!port->tty) || (!port->tty->termios)) {
+-		dbg ("%s - no tty or termios structure", __FUNCTION__);
+-		return;
+-	}
++	iflag = termios->c_iflag;
++	cflag = termios->c_cflag;
+ 
+-	iflag = port->tty->termios->c_iflag;
+-	cflag = port->tty->termios->c_cflag;
++	termios->c_cflag &= ~CMSPAR;
+ 
+ 	/* get a local copy of the current port settings */
+ 	spin_lock_irqsave(&priv->lock, flags);
+@@ -369,33 +367,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
+ 	old_cflag = old_termios->c_cflag;
+ 
+ 	/* Set the baud rate */
+-	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
++	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
+ 		/* reassert DTR and (maybe) RTS on transition from B0 */
+ 		if( (old_cflag&CBAUD) == B0 ) {
+ 			control_state |= (TIOCM_DTR|TIOCM_RTS);
+ 			if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
+ 				err("Set DTR error");
+ 			/* don't set RTS if using hardware flow control */
+-			if (!(old_cflag&CRTSCTS) )
++			if (!(old_cflag & CRTSCTS))
+ 				if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
+ 					err("Set RTS error");
+ 		}
+ 	}
+ 
+ 	baud = tty_get_baud_rate(port->tty);
+-	if (baud == 0) {
+-		dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
+-		return;
+-	}
+-	urb_value = BELKIN_SA_BAUD(baud);
+-	/* Clip to maximum speed */
+-	if (urb_value == 0)
+-		urb_value = 1;
+-	/* Turn it back into a resulting real baud rate */
+-	baud = BELKIN_SA_BAUD(urb_value);
+-	/* FIXME: Once the tty updates are done then push this back to the tty */
+-
+-	if ((cflag & CBAUD) != B0 ) {
++	if (baud) {
++		urb_value = BELKIN_SA_BAUD(baud);
++		/* Clip to maximum speed */
++		if (urb_value == 0)
++			urb_value = 1;
++		/* Turn it back into a resulting real baud rate */
++		baud = BELKIN_SA_BAUD(urb_value);
++
++		/* Report the actual baud rate back to the caller */
++		tty_encode_baud_rate(port->tty, baud, baud);
+ 		if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+ 			err("Set baudrate error");
+ 	} else {
+diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
+index 0362654..66ce30c 100644
+--- a/drivers/usb/serial/console.c
++++ b/drivers/usb/serial/console.c
+@@ -64,8 +64,8 @@ static int usb_console_setup(struct console *co, char *options)
+ 	struct usb_serial *serial;
+ 	struct usb_serial_port *port;
+ 	int retval = 0;
+-	struct tty_struct *tty;
+-	struct ktermios *termios;
++	struct tty_struct *tty = NULL;
++	struct ktermios *termios = NULL, dummy;
+ 
+ 	dbg ("%s", __FUNCTION__);
+ 
+@@ -133,11 +133,14 @@ static int usb_console_setup(struct console *co, char *options)
+ 	}
+ 	co->cflag = cflag;
+ 
+-	/* grab the first serial port that happens to be connected */
+-	serial = usb_serial_get_by_index(0);
++	/*
++	 * no need to check the index here: if the index is wrong, console
++	 * code won't call us
++	 */
++	serial = usb_serial_get_by_index(co->index);
+ 	if (serial == NULL) {
+ 		/* no device is connected yet, sorry :( */
+-		err ("No USB device connected to ttyUSB0");
++		err ("No USB device connected to ttyUSB%i", co->index);
+ 		return -ENODEV;
+ 	}
+ 
+@@ -148,49 +151,64 @@ static int usb_console_setup(struct console *co, char *options)
+ 	 
+ 	++port->open_count;
+ 	if (port->open_count == 1) {
++		if (serial->type->set_termios) {
++			/*
++			 * allocate a fake tty so the driver can initialize
++			 * the termios structure, then later call set_termios to
++			 * configure according to command line arguments
++			 */
++			tty = kzalloc(sizeof(*tty), GFP_KERNEL);
++			if (!tty) {
++				retval = -ENOMEM;
++				err("no more memory");
++				goto reset_open_count;
++			}
++			termios = kzalloc(sizeof(*termios), GFP_KERNEL);
++			if (!termios) {
++				retval = -ENOMEM;
++				err("no more memory");
++				goto free_tty;
++			}
++			memset(&dummy, 0, sizeof(struct ktermios));
++			tty->termios = termios;
++			port->tty = tty;
++		}
++
+ 		/* only call the device specific open if this 
+ 		 * is the first time the port is opened */
+ 		if (serial->type->open)
+ 			retval = serial->type->open(port, NULL);
+ 		else
+ 			retval = usb_serial_generic_open(port, NULL);
+-		if (retval)
+-			port->open_count = 0;
+-	}
+ 
+-	if (retval) {
+-		err ("could not open USB console port");
+-		return retval;
+-	}
+-
+-	if (serial->type->set_termios) {
+-		struct ktermios dummy;
+-		/* build up a fake tty structure so that the open call has something
+-		 * to look at to get the cflag value */
+-		tty = kzalloc(sizeof(*tty), GFP_KERNEL);
+-		if (!tty) {
+-			err ("no more memory");
+-			return -ENOMEM;
++		if (retval) {
++			err("could not open USB console port");
++			goto free_termios;
+ 		}
+-		termios = kzalloc(sizeof(*termios), GFP_KERNEL);
+-		if (!termios) {
+-			err ("no more memory");
+-			kfree (tty);
+-			return -ENOMEM;
+-		}
+-		memset(&dummy, 0, sizeof(struct ktermios));
+-		termios->c_cflag = cflag;
+-		tty->termios = termios;
+-		port->tty = tty;
+ 
+-		/* set up the initial termios settings */
+-		serial->type->set_termios(port, &dummy);
+-		port->tty = NULL;
+-		kfree (termios);
+-		kfree (tty);
++		if (serial->type->set_termios) {
++			termios->c_cflag = cflag;
++			serial->type->set_termios(port, &dummy);
++
++			port->tty = NULL;
++			kfree(termios);
++			kfree(tty);
++		}
+ 	}
+ 
++	port->console = 1;
++	retval = 0;
++
++out:
+ 	return retval;
++free_termios:
++	kfree(termios);
++	port->tty = NULL;
++free_tty:
++	kfree(tty);
++reset_open_count:
++	port->open_count = 0;
++goto out;
+ }
+ 
+ static void usb_console_write(struct console *co, const char *buf, unsigned count)
+diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
+index 2283358..f3ca660 100644
+--- a/drivers/usb/serial/cp2101.c
++++ b/drivers/usb/serial/cp2101.c
+@@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
+ 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
+ 	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
++	{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
+ 	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
+ 	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
+ 	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
+@@ -76,8 +77,13 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
+ 	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
+ 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
++	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
++	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
++	{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
++	{ USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
+ 	{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
+ 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
++	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
+ 	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+ 	{ } /* Terminating Entry */
+ };
+@@ -342,7 +348,10 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
+ 	usb_kill_urb(port->write_urb);
+ 	usb_kill_urb(port->read_urb);
+ 
+-	cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
++	mutex_lock(&port->serial->disc_mutex);
++	if (!port->serial->disconnected)
++		cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
++	mutex_unlock(&port->serial->disc_mutex);
+ }
+ 
+ /*
+diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
+index 4353df9..8d9b045 100644
+--- a/drivers/usb/serial/cyberjack.c
++++ b/drivers/usb/serial/cyberjack.c
+@@ -319,7 +319,6 @@ static void cyberjack_read_int_callback( struct urb *urb )
+ 	/* React only to interrupts signaling a bulk_in transfer */
+ 	if( (urb->actual_length==4) && (data[0]==0x01) ) {
+ 		short old_rdtodo;
+-		int result;
+ 
+ 		/* This is a announcement of coming bulk_ins. */
+ 		unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
+diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
+index 1633863..08c65c1 100644
+--- a/drivers/usb/serial/cypress_m8.c
++++ b/drivers/usb/serial/cypress_m8.c
+@@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
+ {
+ 	struct cypress_private *priv = usb_get_serial_port_data(port);
+ 	unsigned int c_cflag;
+-	unsigned long flags;
+ 	int bps;
+ 	long timeout;
+ 	wait_queue_t wait;
+@@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 
+ 	/* wait for data to drain from buffer */
+-	spin_lock_irqsave(&priv->lock, flags);
++	spin_lock_irq(&priv->lock);
+ 	timeout = CYPRESS_CLOSING_WAIT;
+ 	init_waitqueue_entry(&wait, current);
+ 	add_wait_queue(&port->tty->write_wait, &wait);
+@@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
+ 		set_current_state(TASK_INTERRUPTIBLE);
+ 		if (cypress_buf_data_avail(priv->buf) == 0
+ 		|| timeout == 0 || signal_pending(current)
+-		|| !usb_get_intfdata(port->serial->interface))
++		/* without mutex, allowed due to harmless failure mode */
++		|| port->serial->disconnected)
+ 			break;
+-		spin_unlock_irqrestore(&priv->lock, flags);
++		spin_unlock_irq(&priv->lock);
+ 		timeout = schedule_timeout(timeout);
+-		spin_lock_irqsave(&priv->lock, flags);
++		spin_lock_irq(&priv->lock);
+ 	}
+ 	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&port->tty->write_wait, &wait);
+ 	/* clear out any remaining data in the buffer */
+ 	cypress_buf_clear(priv->buf);
+-	spin_unlock_irqrestore(&priv->lock, flags);
+-	
++	spin_unlock_irq(&priv->lock);
++
++	/* writing is potentially harmful, lock must be taken */
++	mutex_lock(&port->serial->disc_mutex);
++	if (port->serial->disconnected) {
++		mutex_unlock(&port->serial->disc_mutex);
++		return;
++	}
+ 	/* wait for characters to drain from device */
+ 	bps = tty_get_baud_rate(port->tty);
+ 	if (bps > 1200)
+@@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
+ 		if (c_cflag & HUPCL) {
+ 			/* drop dtr and rts */
+ 			priv = usb_get_serial_port_data(port);
+-			spin_lock_irqsave(&priv->lock, flags);
++			spin_lock_irq(&priv->lock);
+ 			priv->line_control = 0;
+ 			priv->cmd_ctrl = 1;
+-			spin_unlock_irqrestore(&priv->lock, flags);
++			spin_unlock_irq(&priv->lock);
+ 			cypress_write(port, NULL, 0);
+ 		}
+ 	}
+@@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
+ 	if (stats)
+ 		dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
+ 		          priv->bytes_in, priv->bytes_out, priv->cmd_count);
++	mutex_unlock(&port->serial->disc_mutex);
+ } /* cypress_close */
+ 
+ 
+diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
+index ae410c4..5f9c6e4 100644
+--- a/drivers/usb/serial/digi_acceleport.c
++++ b/drivers/usb/serial/digi_acceleport.c
+@@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
+ 	unsigned char buf[32];
+ 	struct tty_struct *tty = port->tty;
+ 	struct digi_port *priv = usb_get_serial_port_data(port);
+-	unsigned long flags = 0;
+ 
+ 	dbg("digi_close: TOP: port=%d, open_count=%d",
+ 		priv->dp_port_num, port->open_count);
+ 
++	mutex_lock(&port->serial->disc_mutex);
+ 	/* if disconnected, just clear flags */
+-	if (!usb_get_intfdata(port->serial->interface))
++	if (port->serial->disconnected)
+ 		goto exit;
+ 
+ 	/* do cleanup only after final close on this port */
+-	spin_lock_irqsave(&priv->dp_port_lock, flags);
++	spin_lock_irq(&priv->dp_port_lock);
+ 	priv->dp_in_close = 1;
+-	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
++	spin_unlock_irq(&priv->dp_port_lock);
+ 
+ 	/* tell line discipline to process only XON/XOFF */
+ 	tty->closing = 1;
+@@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
+ 	}
+ 	tty->closing = 0;
+ exit:
+-	spin_lock_irqsave(&priv->dp_port_lock, flags);
++	spin_lock_irq(&priv->dp_port_lock);
+ 	priv->dp_write_urb_in_use = 0;
+ 	priv->dp_in_close = 0;
+ 	wake_up_interruptible(&priv->dp_close_wait);
+-	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
++	spin_unlock_irq(&priv->dp_port_lock);
++	mutex_unlock(&port->serial->disc_mutex);
+ 	dbg("digi_close: done");
+ }
+ 
+diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
+index 97ee718..3f698ba 100644
+--- a/drivers/usb/serial/ezusb.c
++++ b/drivers/usb/serial/ezusb.c
+@@ -53,6 +53,6 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+ }
+ 
+ 
+-EXPORT_SYMBOL(ezusb_writememory);
+-EXPORT_SYMBOL(ezusb_set_reset);
++EXPORT_SYMBOL_GPL(ezusb_writememory);
++EXPORT_SYMBOL_GPL(ezusb_set_reset);
+ 
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index c40e77d..90dcc62 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -17,226 +17,8 @@
+  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
+  *	and extra documentation
+  *
+- * (21/Jul/2004) Ian Abbott
+- *      Incorporated Steven Turner's code to add support for the FT2232C chip.
+- *      The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff.  I have
+- *      fixed a couple of things.
+- *
+- * (27/May/2004) Ian Abbott
+- *      Improved throttling code, mostly stolen from the WhiteHEAT driver.
+- *
+- * (26/Mar/2004) Jan Capek
+- *      Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
+- *
+- * (09/Feb/2004) Ian Abbott
+- *      Changed full name of USB-UIRT device to avoid "/" character.
+- *      Added FTDI's alternate PID (0x6006) for FT232/245 devices.
+- *      Added PID for "ELV USB Module UO100" from Stefan Frings.
+- *
+- * (21/Oct/2003) Ian Abbott
+- *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
+- *      devices.  Removed Matrix Orbital and Perle Systems devices from the
+- *      8U232AM device table, but left them in the FT232BM table, as they are
+- *      known to use only FT232BM.
+- *
+- * (17/Oct/2003) Scott Allen
+- *      Added vid/pid for Perle Systems UltraPort USB serial converters
+- *
+- * (21/Sep/2003) Ian Abbott
+- *      Added VID/PID for Omnidirectional Control Technology US101 USB to
+- *      RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
+- *      VID/PID supplied by Donald Gordon.
+- *
+- * (19/Aug/2003) Ian Abbott
+- *      Freed urb's transfer buffer in write bulk callback.
+- *      Omitted some paranoid checks in write bulk callback that don't matter.
+- *      Scheduled work in write bulk callback regardless of port's open count.
+- *
+- * (05/Aug/2003) Ian Abbott
+- *      Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
+- *      VID/PID provided by Steve Briggs.
+- *
+- * (23/Jul/2003) Ian Abbott
+- *      Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
+- *      Wayne Wylupski.
+- *
+- * (10/Jul/2003) David Glance
+- *      Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
+- *
+- * (27/Jun/2003) Ian Abbott
+- *	Reworked the urb handling logic.  We have no more pool, but dynamically
+- *	allocate the urb and the transfer buffer on the fly.  In testing this
+- *	does not incure any measurable overhead.  This also relies on the fact
+- *	that we have proper reference counting logic for urbs.  I nicked this
+- *	from Greg KH's Visor driver.
+- *
+- * (23/Jun/2003) Ian Abbott
+- *      Reduced flip buffer pushes and corrected a data length test in
+- *      ftdi_read_bulk_callback.
+- *      Defererence pointers after any paranoid checks, not before.
+- *
+- * (21/Jun/2003) Erik Nygren
+- *      Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
+- *      See <http://www.home-electro.com/tira1.htm>.  Only operates properly
+- *      at 100000 and RTS-CTS, so set custom divisor mode on startup.
+- *      Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
+- *
+- * (18/Jun/2003) Ian Abbott
+- *      Added Device ID of the USB relais from Rudolf Gugler (backported from
+- *      Philipp Gühring's patch for 2.5.x kernel).
+- *      Moved read transfer buffer reallocation into startup function.
+- *      Free existing write urb and transfer buffer in startup function.
+- *      Only use urbs in write urb pool that were successfully allocated.
+- *      Moved some constant macros out of functions.
+- *      Minor whitespace and comment changes.
+- *
+- * (12/Jun/2003) David Norwood
+- *      Added support for USB-UIRT IR transceiver using 8U232AM chip.
+- *      See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>.  Only
+- *      operates properly at 312500, so set custom divisor mode on startup.
+- *
+- * (12/Jun/2003) Ian Abbott
+- *      Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang
+- *      - I've eliminated some that don't seem to exist!
+- *      Added Home Electronics Tira-1 IR transceiver pid from Chris Horn
+- *      Some whitespace/coding-style cleanups
+- *
+- * (11/Jun/2003) Ian Abbott
+- *      Fixed unsafe spinlock usage in ftdi_write
+- *
+- * (24/Feb/2003) Richard Shooter
+- *      Increase read buffer size to improve read speeds at higher baud rates
+- *      (specifically tested with up to 1Mb/sec at 1.5M baud)
+- *
+- * (23/Feb/2003) John Wilkins
+- *      Added Xon/xoff flow control (activating support in the ftdi device)
+- *      Added vid/pid for Videonetworks/Homechoice (UK ISP)
+- *
+- * (23/Feb/2003) Bill Ryder
+- *      Added matrix orb device vid/pids from Wayne Wylupski
+- *
+- * (19/Feb/2003) Ian Abbott
+- *      For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
+- *      changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
+- *      ASYNC_SPD_SHI or ASYNC_SPD_WARP.  Also, unless ASYNC_SPD_CUST is in
+- *      force, don't bother changing baud rate when custom_divisor has changed.
+- *
+- * (18/Feb/2003) Ian Abbott
+- *      Fixed TIOCMGET handling to include state of DTR and RTS, the state
+- *      of which are now saved by set_dtr() and set_rts().
+- *      Fixed improper storage class for buf in set_dtr() and set_rts().
+- *      Added FT232BM chip type and support for its extra baud rates (compared
+- *      to FT8U232AM).
+- *      Took account of special case divisor values for highest baud rates of
+- *      FT8U232AM and FT232BM.
+- *      For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
+- *      as previous alt_speed setting is now stale.
+- *      Moved startup code common between the startup routines for the
+- *      different chip types into a common subroutine.
+- *
+- * (17/Feb/2003) Bill Ryder
+- *      Added write urb buffer pool on a per device basis
+- *      Added more checking for open file on callbacks (fixed OOPS)
+- *      Added CrystalFontz 632 and 634 PIDs
+- *         (thanx to CrystalFontz for the sample devices - they flushed out
+- *           some driver bugs)
+- *      Minor debugging message changes
+- *      Added throttle, unthrottle and chars_in_buffer functions
+- *      Fixed FTDI_SIO (the original device) bug
+- *      Fixed some shutdown handling
+- *
+- *
+- *
+- *
+- * (07/Jun/2002) Kuba Ober
+- *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+- *	function. It was getting too complex.
+- *	Fix the divisor calculation logic which was setting divisor of 0.125
+- *	instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+- *	Also make it bump up the divisor to next integer in case of 7/8 - it's
+- *	a better approximation.
+- *
+- * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
+- *      Not tested by me but it doesn't break anything I use.
+- *
+- * (04/Jan/2002) Kuba Ober
+- *	Implemented 38400 baudrate kludge, where it can be substituted with other
+- *	  values. That's the only way to set custom baudrates.
+- *	Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
+- *	FIXME: both baudrate things should eventually go to usbserial.c as other
+- *	  devices may need that functionality too. Actually, it can probably be
+- *	  merged in serial.c somehow - too many drivers repeat this code over
+- *	  and over.
+- *	Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
+- *	Divisors for baudrates are calculated by a macro.
+- *	Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
+- *
+- * (04/Nov/2001) Bill Ryder
+- *	Fixed bug in read_bulk_callback where incorrect urb buffer was used.
+- *	Cleaned up write offset calculation
+- *	Added write_room since default values can be incorrect for sio
+- *	Changed write_bulk_callback to use same queue_task as other drivers
+- *        (the previous version caused panics)
+- *	Removed port iteration code since the device only has one I/O port and it
+- *	  was wrong anyway.
+- *
+- * (31/May/2001) gkh
+- *	Switched from using spinlock to a semaphore, which fixes lots of problems.
+- *
+- * (23/May/2001)   Bill Ryder
+- *	Added runtime debug patch (thanx Tyson D Sawyer).
+- *	Cleaned up comments for 8U232
+- *	Added parity, framing and overrun error handling
+- *	Added receive break handling.
+- *
+- * (04/08/2001) gb
+- *	Identify version on module load.
+- *
+- * (18/March/2001) Bill Ryder
+- *	(Not released)
+- *	Added send break handling. (requires kernel patch too)
+- *	Fixed 8U232AM hardware RTS/CTS etc status reporting.
+- *	Added flipbuf fix copied from generic device
+- *
+- * (12/3/2000) Bill Ryder
+- *	Added support for 8U232AM device.
+- *	Moved PID and VIDs into header file only.
+- *	Turned on low-latency for the tty (device will do high baudrates)
+- *	Added shutdown routine to close files when device removed.
+- *	More debug and error message cleanups.
+- *
+- * (11/13/2000) Bill Ryder
+- *	Added spinlock protected open code and close code.
+- *	Multiple opens work (sort of - see webpage mentioned above).
+- *	Cleaned up comments. Removed multiple PID/VID definitions.
+- *	Factorised cts/dtr code
+- *	Made use of __FUNCTION__ in dbg's
+- *
+- * (11/01/2000) Adam J. Richter
+- *	usb_device_id table support
+- *
+- * (10/05/2000) gkh
+- *	Fixed bug with urb->dev not being set properly, now that the usb
+- *	core needs it.
+- *
+- * (09/11/2000) gkh
+- *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
+- *
+- * (07/19/2000) gkh
+- *	Added module_init and module_exit functions to handle the fact that this
+- *	driver is a loadable module now.
+- *
+- * (04/04/2000) Bill Ryder
+- *	Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
+- *        handled elsewhere in the tty io driver chain).
+- *
+- * (03/30/2000) Bill Ryder
+- *	Implemented lots of ioctls
+- *	Fixed a race condition in write
+- *	Changed some dbg's to errs
+- *
+- * (03/26/2000) gkh
+- *	Split driver up into device specific pieces.
++ * Change entries from 2004 and earlier can be found in versions of this
++ * file in kernel versions prior to the 2.6.24 release.
+  *
+  */
+ 
+@@ -309,12 +91,12 @@ struct ftdi_sio_quirk {
+ 	void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
+ };
+ 
+-static int   ftdi_olimex_probe		(struct usb_serial *serial);
++static int   ftdi_jtag_probe		(struct usb_serial *serial);
+ static void  ftdi_USB_UIRT_setup	(struct ftdi_private *priv);
+ static void  ftdi_HE_TIRA1_setup	(struct ftdi_private *priv);
+ 
+-static struct ftdi_sio_quirk ftdi_olimex_quirk = {
+-	.probe	= ftdi_olimex_probe,
++static struct ftdi_sio_quirk ftdi_jtag_quirk = {
++	.probe	= ftdi_jtag_probe,
+ };
+ 
+ static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
+@@ -471,30 +253,28 @@ static struct usb_device_id id_table_combined [] = {
+ 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
+ 	/*
+-	 * These will probably use user-space drivers.  Uncomment them if
+-	 * you need them or use the user-specified vendor/product module
+-	 * parameters (see ftdi_sio.h for the numbers).  Make a fuss if
+-	 * you think the driver should recognize any of them by default.
++	 * Due to many user requests for multiple ELV devices we enable
++	 * them by default.
+ 	 */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
+-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
+ 	{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+ 	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+ 	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+@@ -545,6 +325,7 @@ static struct usb_device_id id_table_combined [] = {
+ 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
+ 	{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
+ 	{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
+ 	{ USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
+@@ -569,8 +350,13 @@ static struct usb_device_id id_table_combined [] = {
+ 	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
+ 	{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
++	{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
+ 	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
+-		.driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
++		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ 	{ },					/* Optional parameter entry */
+ 	{ }					/* Terminating entry */
+ };
+@@ -1283,10 +1069,11 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
+ } /* ftdi_HE_TIRA1_setup */
+ 
+ /*
+- * First port on Olimex arm-usb-ocd is reserved for JTAG interface
+- * and can be accessed from userspace using openocd.
++ * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
++ * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
++ * userspace using openocd.
+  */
+-static int ftdi_olimex_probe(struct usb_serial *serial)
++static int ftdi_jtag_probe(struct usb_serial *serial)
+ {
+ 	struct usb_device *udev = serial->dev;
+ 	struct usb_interface *interface = serial->interface;
+@@ -1294,7 +1081,7 @@ static int ftdi_olimex_probe(struct usb_serial *serial)
+ 	dbg("%s",__FUNCTION__);
+ 
+ 	if (interface == udev->actconfig->interface[0]) {
+-		info("Ignoring reserved serial port on Olimex arm-usb-ocd\n");
++		info("Ignoring serial port reserved for JTAG");
+ 		return -ENODEV;
+ 	}
+ 
+@@ -1411,7 +1198,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
+ 
+ 	dbg("%s", __FUNCTION__);
+ 
+-	if (c_cflag & HUPCL){
++	mutex_lock(&port->serial->disc_mutex);
++	if (c_cflag & HUPCL && !port->serial->disconnected){
+ 		/* Disable flow control */
+ 		if (usb_control_msg(port->serial->dev,
+ 				    usb_sndctrlpipe(port->serial->dev, 0),
+@@ -1425,6 +1213,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
+ 		/* drop RTS and DTR */
+ 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ 	} /* Note change no line if hupcl is off */
++	mutex_unlock(&port->serial->disc_mutex);
+ 
+ 	/* cancel any scheduled reading */
+ 	cancel_delayed_work(&priv->rx_work);
+diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
+index b51cbb0..6eee2ab 100644
+--- a/drivers/usb/serial/ftdi_sio.h
++++ b/drivers/usb/serial/ftdi_sio.h
+@@ -98,6 +98,10 @@
+ #define FTDI_MTXORB_5_PID      0xFA05  /* Matrix Orbital Product Id */
+ #define FTDI_MTXORB_6_PID      0xFA06  /* Matrix Orbital Product Id */
+ 
++/* OOCDlink by Joern Kaipf <joernk at web.de>
++ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
++#define FTDI_OOCDLINK_PID	0xbaf8	/* Amontec JTAGkey */
++
+ /* Interbiometrics USB I/O Board */
+ /* Developed for Interbiometrics by Rudolf Gugler */
+ #define INTERBIOMETRICS_VID              0x1209
+@@ -245,6 +249,7 @@
+ #define FTDI_ELV_WS300PC_PID	0xE0F6	/* PC-Wetterstation (WS 300 PC) */
+ #define FTDI_ELV_FHZ1300PC_PID	0xE0E8	/* FHZ 1300 PC */
+ #define FTDI_ELV_WS500_PID	0xE0E9	/* PC-Wetterstation (WS 500) */
++#define FTDI_ELV_EM1010PC_PID	0xE0EF	/* Engery monitor EM 1010 PC */
+ 
+ /*
+  * Definitions for ID TECH (www.idt-net.com) devices
+@@ -278,6 +283,7 @@
+ #define FTDI_ATIK_ATK16C_PID	0xDF32	/* ATIK ATK-16C Colour Camera */
+ #define FTDI_ATIK_ATK16HR_PID	0xDF31	/* ATIK ATK-16HR Grayscale Camera */
+ #define FTDI_ATIK_ATK16HRC_PID	0xDF33	/* ATIK ATK-16HRC Colour Camera */
++#define FTDI_ATIK_ATK16IC_PID   0xDF35  /* ATIK ATK-16IC Grayscale Camera */
+ 
+ /*
+  * Protego product ids
+@@ -534,6 +540,8 @@
+ #define OLIMEX_VID			0x15BA
+ #define OLIMEX_ARM_USB_OCD_PID		0x0003
+ 
++/* www.elsterelectricity.com Elster Unicom III Optical Probe */
++#define FTDI_ELSTER_UNICOM_PID		0xE700 /* Product Id */
+ 
+ /*
+  * The Mobility Lab (TML)
+@@ -556,6 +564,13 @@
+ 
+ 
+ /*
++ * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
++ * Submitted by Harald Welte <laforge at openmoko.org>
++ */
++#define	FIC_VID			0x1457
++#define	FIC_NEO1973_DEBUG_PID	0x5118
++
++/*
+  *   BmRequestType:  1100 0000b
+  *   bRequest:       FTDI_E2_READ
+  *   wValue:         0
+diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
+index f1c90cf..d74e43d 100644
+--- a/drivers/usb/serial/garmin_gps.c
++++ b/drivers/usb/serial/garmin_gps.c
+@@ -1020,19 +1020,26 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
+ 	if (!serial)
+ 		return;
+ 
+-	garmin_clear(garmin_data_p);
++	mutex_lock(&port->serial->disc_mutex);
++	if (!port->serial->disconnected)
++		garmin_clear(garmin_data_p);
+ 
+ 	/* shutdown our urbs */
+ 	usb_kill_urb (port->read_urb);
+ 	usb_kill_urb (port->write_urb);
+ 
+-	if (noResponseFromAppLayer(garmin_data_p) ||
+-	    ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
+-		process_resetdev_request(port);
+-		garmin_data_p->state = STATE_RESET;
++	if (!port->serial->disconnected) {
++		if (noResponseFromAppLayer(garmin_data_p) ||
++		    ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
++			process_resetdev_request(port);
++			garmin_data_p->state = STATE_RESET;
++		} else {
++			garmin_data_p->state = STATE_DISCONNECTED;
++		}
+ 	} else {
+ 		garmin_data_p->state = STATE_DISCONNECTED;
+ 	}
++	mutex_unlock(&port->serial->disc_mutex);
+ }
+ 
+ 
+diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
+index d415311..97fa3c4 100644
+--- a/drivers/usb/serial/generic.c
++++ b/drivers/usb/serial/generic.c
+@@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb_serial *serial)
+ 	struct usb_serial_port *port;
+ 	int i, c = 0, r;
+ 
++#ifdef CONFIG_PM
++	/*
++	 * If this is an autoresume, don't submit URBs.
++	 * They will be submitted in the open function instead.
++	 */
++	if (serial->dev->auto_pm)
++		return 0;
++#endif
+ 	for (i = 0; i < serial->num_ports; i++) {
+ 		port = serial->port[i];
+ 		if (port->open_count && port->read_urb) {
+diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
+index a5d2e11..3428ccc 100644
+--- a/drivers/usb/serial/io_edgeport.c
++++ b/drivers/usb/serial/io_edgeport.c
+@@ -959,7 +959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+  *
+  *	This function will block the close until one of the following:
+  *		1. Response to our Chase comes from Edgeport
+- *		2. A timout of 10 seconds without activity has expired
++ *		2. A timeout of 10 seconds without activity has expired
+  *		   (1K of Edgeport data @ 2400 baud ==> 4 sec to empty)
+  *
+  ************************************************************************/
+@@ -999,7 +999,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
+ 				return;
+ 			}
+ 		} else {
+-			// Reset timout value back to 10 seconds
++			// Reset timeout value back to 10 seconds
+ 			dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
+ 			loop = 10;
+ 		}
+@@ -1014,7 +1014,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
+  *	This function will block the close until one of the following:
+  *		1. TX count are 0
+  *		2. The edgeport has stopped
+- *		3. A timout of 3 seconds without activity has expired
++ *		3. A timeout of 3 seconds without activity has expired
+  *
+  ************************************************************************/
+ static void block_until_tx_empty (struct edgeport_port *edge_port)
+@@ -1050,7 +1050,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
+ 				return;
+ 			}
+ 		} else {
+-			// Reset timout value back to seconds
++			// Reset timeout value back to seconds
+ 			loop = 30;
+ 		}
+ 	}
+diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
+index b867090..cd34059 100644
+--- a/drivers/usb/serial/io_ti.c
++++ b/drivers/usb/serial/io_ti.c
+@@ -34,6 +34,7 @@
+ #include <linux/tty_flip.h>
+ #include <linux/module.h>
+ #include <linux/spinlock.h>
++#include <linux/mutex.h>
+ #include <linux/serial.h>
+ #include <linux/ioctl.h>
+ #include <asm/uaccess.h>
+@@ -133,7 +134,7 @@ struct edgeport_serial {
+ 	struct product_info product_info;
+ 	u8 TI_I2C_Type;			// Type of I2C in UMP
+ 	u8 TiReadI2C;			// Set to TRUE if we have read the I2c in Boot Mode
+-	struct semaphore es_sem;
++	struct mutex es_lock;
+ 	int num_ports_open;
+ 	struct usb_serial *serial;
+ };
+@@ -1978,7 +1979,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+ 	}
+ 	
+ 	/* set up the port settings */
+-	edge_set_termios (port, NULL);
++	edge_set_termios (port, port->tty->termios);
+ 
+ 	/* open up the port */
+ 
+@@ -2044,7 +2045,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+ 	dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
+ 
+ 	edge_serial = edge_port->edge_serial;
+-	if (down_interruptible(&edge_serial->es_sem))
++	if (mutex_lock_interruptible(&edge_serial->es_lock))
+ 		return -ERESTARTSYS;
+ 	if (edge_serial->num_ports_open == 0) {
+ 		/* we are the first port to be opened, let's post the interrupt urb */
+@@ -2052,7 +2053,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+ 		if (!urb) {
+ 			dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
+ 			status = -EINVAL;
+-			goto up_es_sem;
++			goto release_es_lock;
+ 		}
+ 		urb->complete = edge_interrupt_callback;
+ 		urb->context = edge_serial;
+@@ -2060,7 +2061,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+ 		status = usb_submit_urb (urb, GFP_KERNEL);
+ 		if (status) {
+ 			dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
+-			goto up_es_sem;
++			goto release_es_lock;
+ 		}
+ 	}
+ 
+@@ -2092,13 +2093,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
+ 
+ 	dbg("%s - exited", __FUNCTION__);
+ 
+-	goto up_es_sem;
++	goto release_es_lock;
+ 
+ unlink_int_urb:
+ 	if (edge_port->edge_serial->num_ports_open == 0)
+ 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+-up_es_sem:
+-	up(&edge_serial->es_sem);
++release_es_lock:
++	mutex_unlock(&edge_serial->es_lock);
+ 	return status;
+ }
+ 
+@@ -2137,14 +2138,14 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
+ 				     0,
+ 				     NULL,
+ 				     0);
+-	down(&edge_serial->es_sem);
++	mutex_lock(&edge_serial->es_lock);
+ 	--edge_port->edge_serial->num_ports_open;
+ 	if (edge_port->edge_serial->num_ports_open <= 0) {
+ 		/* last port is now closed, let's shut down our interrupt urb */
+ 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+ 		edge_port->edge_serial->num_ports_open = 0;
+ 	}
+-	up(&edge_serial->es_sem);
++	mutex_unlock(&edge_serial->es_lock);
+ 	edge_port->close_pending = 0;
+ 
+ 	dbg("%s - exited", __FUNCTION__);
+@@ -2393,11 +2394,6 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
+ 	dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
+ 
+ 	tty = edge_port->port->tty;
+-	if ((!tty) ||
+-	    (!tty->termios)) {
+-		dbg("%s - no tty structures", __FUNCTION__);
+-		return;
+-	}
+ 
+ 	config = kmalloc (sizeof (*config), GFP_KERNEL);
+ 	if (!config) {
+@@ -2492,15 +2488,21 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
+ 		}
+ 	}
+ 
++	tty->termios->c_cflag &= ~CMSPAR;
++
+ 	/* Round the baud rate */
+ 	baud = tty_get_baud_rate(tty);
+ 	if (!baud) {
+ 		/* pick a default, any default... */
+ 		baud = 9600;
+-	}
++	} else
++		tty_encode_baud_rate(tty, baud, baud);
++
+ 	edge_port->baud_rate = baud;
+ 	config->wBaudRate = (__u16)((461550L + baud/2) / baud);
+ 
++	/* FIXME: Recompute actual baud from divisor here */
++
+ 	dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
+ 
+ 	dbg ("wBaudRate:   %d", (int)(461550L / config->wBaudRate));
+@@ -2538,19 +2540,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
+ 	struct tty_struct *tty = port->tty;
+ 	unsigned int cflag;
+ 
+-	if (!port->tty || !port->tty->termios) {
+-		dbg ("%s - no tty or termios", __FUNCTION__);
+-		return;
+-	}
+-
+ 	cflag = tty->termios->c_cflag;
+ 
+ 	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
+ 	    tty->termios->c_cflag, tty->termios->c_iflag);
+-	if (old_termios) {
+-		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+-		    old_termios->c_cflag, old_termios->c_iflag);
+-	}
++	dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
++	    old_termios->c_cflag, old_termios->c_iflag);
+ 
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 
+@@ -2743,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial)
+ 		dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+ 		return -ENOMEM;
+ 	}
+-	sema_init(&edge_serial->es_sem, 1);
++	mutex_init(&edge_serial->es_lock);
+ 	edge_serial->serial = serial;
+ 	usb_set_serial_data(serial, edge_serial);
+ 
+diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
+new file mode 100644
+index 0000000..fde188e
+--- /dev/null
++++ b/drivers/usb/serial/iuu_phoenix.c
+@@ -0,0 +1,1217 @@
++/*
++ * Infinity Unlimited USB Phoenix driver
++ *
++ * Copyright (C) 2007 Alain Degreffe (eczema at ecze.com)
++ *
++ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
++ *
++ *	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.
++ *
++ *  And tested with help of WB Electronics
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/spinlock.h>
++#include <linux/uaccess.h>
++#include <linux/usb.h>
++#include <linux/usb/serial.h>
++#include "iuu_phoenix.h"
++#include <linux/random.h>
++
++
++#ifdef CONFIG_USB_SERIAL_DEBUG
++static int debug = 1;
++#else
++static int debug;
++#endif
++
++/*
++ * Version Information
++ */
++#define DRIVER_VERSION "v0.5"
++#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
++
++static struct usb_device_id id_table[] = {
++	{USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
++	{}			/* Terminating entry */
++};
++MODULE_DEVICE_TABLE(usb, id_table);
++
++static struct usb_driver iuu_driver = {
++	.name = "iuu_phoenix",
++	.probe = usb_serial_probe,
++	.disconnect = usb_serial_disconnect,
++	.id_table = id_table,
++	.no_dynamic_id = 1,
++};
++
++/* turbo parameter */
++static int boost = 100;
++static int clockmode = 1;
++static int cdmode = 1;
++static int iuu_cardin;
++static int iuu_cardout;
++static int xmas;
++
++static void read_rxcmd_callback(struct urb *urb);
++
++struct iuu_private {
++	spinlock_t lock;	/* store irq state */
++	wait_queue_head_t delta_msr_wait;
++	u8 line_control;
++	u8 line_status;
++	u8 termios_initialized;
++	int tiostatus;		/* store IUART SIGNAL for tiocmget call */
++	u8 reset;		/* if 1 reset is needed */
++	int poll;		/* number of poll */
++	u8 *writebuf;		/* buffer for writing to device */
++	int writelen;		/* num of byte to write to device */
++	u8 *buf;		/* used for initialize speed */
++	u8 *dbgbuf;		/* debug buffer */
++	u8 len;
++};
++
++
++static void iuu_free_buf(struct iuu_private *priv)
++{
++	kfree(priv->buf);
++	kfree(priv->dbgbuf);
++	kfree(priv->writebuf);
++}
++
++static int iuu_alloc_buf(struct iuu_private *priv)
++{
++	priv->buf = kzalloc(256, GFP_KERNEL);
++	priv->dbgbuf = kzalloc(256, GFP_KERNEL);
++	priv->writebuf = kzalloc(256, GFP_KERNEL);
++	if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
++		iuu_free_buf(priv);
++		dbg("%s problem allocation buffer", __FUNCTION__);
++		return -ENOMEM;
++	}
++	dbg("%s - Privates buffers allocation success", __FUNCTION__);
++	return 0;
++}
++
++static int iuu_startup(struct usb_serial *serial)
++{
++	struct iuu_private *priv;
++	priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
++	dbg("%s- priv allocation success", __FUNCTION__);
++	if (!priv)
++		return -ENOMEM;
++	if (iuu_alloc_buf(priv)) {
++		kfree(priv);
++		return -ENOMEM;
++	}
++	spin_lock_init(&priv->lock);
++	init_waitqueue_head(&priv->delta_msr_wait);
++	usb_set_serial_port_data(serial->port[0], priv);
++	return 0;
++}
++
++/* Shutdown function */
++static void iuu_shutdown(struct usb_serial *serial)
++{
++	struct usb_serial_port *port = serial->port[0];
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	if (!port)
++		return;
++
++	dbg("%s", __FUNCTION__);
++
++	if (priv) {
++		iuu_free_buf(priv);
++		dbg("%s - I will free all", __FUNCTION__);
++		usb_set_serial_port_data(port, NULL);
++
++		dbg("%s - priv is not anymore in port structure", __FUNCTION__);
++		kfree(priv);
++
++		dbg("%s priv is now kfree", __FUNCTION__);
++	}
++}
++
++static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
++			unsigned int set, unsigned int clear)
++{
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	struct tty_struct *tty;
++	tty = port->tty;
++
++	dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
++	    port->number, set, clear);
++	if (set & TIOCM_RTS)
++		priv->tiostatus = TIOCM_RTS;
++
++	if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
++		dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
++		priv->reset = 1;
++		return 0;
++	}
++
++	return 0;
++}
++
++/* This is used to provide a carrier detect mechanism
++ * When a card is present, the response is 0x00
++ * When no card , the reader respond with TIOCM_CD
++ * This is known as CD autodetect mechanism
++ */
++static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
++{
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	return priv->tiostatus;
++}
++
++static void iuu_rxcmd(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	int result;
++	dbg("%s - enter", __FUNCTION__);
++
++	if (urb->status) {
++		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++		/* error stop all */
++		return;
++	}
++
++
++	memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 1,
++			  read_rxcmd_callback, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++}
++
++static int iuu_reset(struct usb_serial_port *port, u8 wt)
++{
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	int result;
++	char *buf_ptr = port->write_urb->transfer_buffer;
++	dbg("%s - enter", __FUNCTION__);
++
++	/* Prepare the reset sequence */
++
++	*buf_ptr++ = IUU_RST_SET;
++	*buf_ptr++ = IUU_DELAY_MS;
++	*buf_ptr++ = wt;
++	*buf_ptr = IUU_RST_CLEAR;
++
++	/* send the sequence */
++
++	usb_fill_bulk_urb(port->write_urb,
++			  port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++	priv->reset = 0;
++	return result;
++}
++
++/* Status Function
++ * Return value is
++ * 0x00 = no card
++ * 0x01 = smartcard
++ * 0x02 = sim card
++ */
++static void iuu_update_status_callback(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	u8 *st;
++	dbg("%s - enter", __FUNCTION__);
++
++	if (urb->status) {
++		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++		/* error stop all */
++		return;
++	}
++
++	st = urb->transfer_buffer;
++	dbg("%s - enter", __FUNCTION__);
++	if (urb->actual_length == 1) {
++		switch (st[0]) {
++		case 0x1:
++			priv->tiostatus = iuu_cardout;
++			break;
++		case 0x0:
++			priv->tiostatus = iuu_cardin;
++			break;
++		default:
++			priv->tiostatus = iuu_cardin;
++		}
++	}
++	iuu_rxcmd(urb);
++}
++
++static void iuu_status_callback(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	int result;
++	dbg("%s - enter", __FUNCTION__);
++
++	dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++			  usb_rcvbulkpipe(port->serial->dev,
++					  port->bulk_in_endpointAddress),
++			  port->read_urb->transfer_buffer, 256,
++			  iuu_update_status_callback, port);
++	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++}
++
++static int iuu_status(struct usb_serial_port *port)
++{
++	int result;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 1,
++			  iuu_status_callback, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++	return result;
++
++}
++
++static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
++{
++	int status;
++	struct usb_serial *serial = port->serial;
++	int actual = 0;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	/* send the data out the bulk port */
++
++	status =
++	    usb_bulk_msg(serial->dev,
++			 usb_sndbulkpipe(serial->dev,
++					 port->bulk_out_endpointAddress), buf,
++			 count, &actual, HZ * 1);
++
++	if (status != IUU_OPERATION_OK) {
++		dbg("%s - error = %2x", __FUNCTION__, status);
++	} else {
++		dbg("%s - write OK !", __FUNCTION__);
++	}
++	return status;
++}
++
++static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
++{
++	int status;
++	struct usb_serial *serial = port->serial;
++	int actual = 0;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	/* send the data out the bulk port */
++
++	status =
++	    usb_bulk_msg(serial->dev,
++			 usb_rcvbulkpipe(serial->dev,
++					 port->bulk_in_endpointAddress), buf,
++			 count, &actual, HZ * 1);
++
++	if (status != IUU_OPERATION_OK) {
++		dbg("%s - error = %2x", __FUNCTION__, status);
++	} else {
++		dbg("%s - read OK !", __FUNCTION__);
++	}
++
++	return status;
++}
++
++static int iuu_led(struct usb_serial_port *port, unsigned int R,
++		   unsigned int G, unsigned int B, u8 f)
++{
++	int status;
++	u8 *buf;
++	buf = kmalloc(8, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	buf[0] = IUU_SET_LED;
++	buf[1] = R & 0xFF;
++	buf[2] = (R >> 8) & 0xFF;
++	buf[3] = G & 0xFF;
++	buf[4] = (G >> 8) & 0xFF;
++	buf[5] = B & 0xFF;
++	buf[6] = (B >> 8) & 0xFF;
++	buf[7] = f;
++	status = bulk_immediate(port, buf, 8);
++	kfree(buf);
++	if (status != IUU_OPERATION_OK)
++		dbg("%s - led error status = %2x", __FUNCTION__, status);
++	else
++		dbg("%s - led OK !", __FUNCTION__);
++	return IUU_OPERATION_OK;
++}
++
++static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
++				 u8 b2, u8 freq)
++{
++	*buf++ = IUU_SET_LED;
++	*buf++ = r1;
++	*buf++ = r2;
++	*buf++ = g1;
++	*buf++ = g2;
++	*buf++ = b1;
++	*buf++ = b2;
++	*buf = freq;
++}
++
++static void iuu_led_activity_on(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	int result;
++	char *buf_ptr = port->write_urb->transfer_buffer;
++	*buf_ptr++ = IUU_SET_LED;
++	if (xmas == 1) {
++		get_random_bytes(buf_ptr, 6);
++		*(buf_ptr+7) = 1;
++	} else {
++		iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
++	}
++
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 8 ,
++			  iuu_rxcmd, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++}
++
++static void iuu_led_activity_off(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	int result;
++	char *buf_ptr = port->write_urb->transfer_buffer;
++	if (xmas == 1) {
++		iuu_rxcmd(urb);
++		return;
++	} else {
++		*buf_ptr++ = IUU_SET_LED;
++		iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
++	}
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 8 ,
++			  iuu_rxcmd, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++}
++
++
++
++static int iuu_clk(struct usb_serial_port *port, int dwFrq)
++{
++	int status;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	int Count = 0;
++	u8 FrqGenAdr = 0x69;
++	u8 DIV = 0;		/* 8bit */
++	u8 XDRV = 0;		/* 8bit */
++	u8 PUMP = 0;		/* 3bit */
++	u8 PBmsb = 0;		/* 2bit */
++	u8 PBlsb = 0;		/* 8bit */
++	u8 PO = 0;		/* 1bit */
++	u8 Q = 0;		/* 7bit */
++	/* 24bit = 3bytes */
++	unsigned int P = 0;
++	unsigned int P2 = 0;
++	int frq = (int)dwFrq;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	if (frq == 0) {
++		priv->buf[Count++] = IUU_UART_WRITE_I2C;
++		priv->buf[Count++] = FrqGenAdr << 1;
++		priv->buf[Count++] = 0x09;
++		priv->buf[Count++] = 0x00;
++
++		status = bulk_immediate(port, (u8 *) priv->buf, Count);
++		if (status != 0) {
++			dbg("%s - write error ", __FUNCTION__);
++			return status;
++		}
++	} else if (frq == 3579000) {
++		DIV = 100;
++		P = 1193;
++		Q = 40;
++		XDRV = 0;
++	} else if (frq == 3680000) {
++		DIV = 105;
++		P = 161;
++		Q = 5;
++		XDRV = 0;
++	} else if (frq == 6000000) {
++		DIV = 66;
++		P = 66;
++		Q = 2;
++		XDRV = 0x28;
++	} else {
++		unsigned int result = 0;
++		unsigned int tmp = 0;
++		unsigned int check;
++		unsigned int check2;
++		char found = 0x00;
++		unsigned int lQ = 2;
++		unsigned int lP = 2055;
++		unsigned int lDiv = 4;
++
++		for (lQ = 2; lQ <= 47 && !found; lQ++)
++			for (lP = 2055; lP >= 8 && !found; lP--)
++				for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
++					tmp = (12000000 / lDiv) * (lP / lQ);
++					if (abs((int)(tmp - frq)) <
++					    abs((int)(frq - result))) {
++						check2 = (12000000 / lQ);
++						if (check2 < 250000)
++							continue;
++						check = (12000000 / lQ) * lP;
++						if (check > 400000000)
++							continue;
++						if (check < 100000000)
++							continue;
++						if (lDiv < 4 || lDiv > 127)
++							continue;
++						result = tmp;
++						P = lP;
++						DIV = lDiv;
++						Q = lQ;
++						if (result == frq)
++							found = 0x01;
++					}
++				}
++	}
++	P2 = ((P - PO) / 2) - 4;
++	DIV = DIV;
++	PUMP = 0x04;
++	PBmsb = (P2 >> 8 & 0x03);
++	PBlsb = P2 & 0xFF;
++	PO = (P >> 10) & 0x01;
++	Q = Q - 2;
++
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/* 0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x09;
++	priv->buf[Count++] = 0x20;	/* Adr = 0x09 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/* 0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x0C;
++	priv->buf[Count++] = DIV;	/* Adr = 0x0C */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/* 0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x12;
++	priv->buf[Count++] = XDRV;	/* Adr = 0x12 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x13;
++	priv->buf[Count++] = 0x6B;	/* Adr = 0x13 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x40;
++	priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
++			     (PBmsb & 0x03);	/* Adr = 0x40 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x41;
++	priv->buf[Count++] = PBlsb;	/* Adr = 0x41 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x42;
++	priv->buf[Count++] = Q | (((PO & 0x01) << 7));	/* Adr = 0x42 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x44;
++	priv->buf[Count++] = (char)0xFF;	/* Adr = 0x44 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x45;
++	priv->buf[Count++] = (char)0xFE;	/* Adr = 0x45 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x46;
++	priv->buf[Count++] = 0x7F;	/* Adr = 0x46 */
++	priv->buf[Count++] = IUU_UART_WRITE_I2C;	/*  0x4C */
++	priv->buf[Count++] = FrqGenAdr << 1;
++	priv->buf[Count++] = 0x47;
++	priv->buf[Count++] = (char)0x84;	/* Adr = 0x47 */
++
++	status = bulk_immediate(port, (u8 *) priv->buf, Count);
++	if (status != IUU_OPERATION_OK)
++		dbg("%s - write error ", __FUNCTION__);
++	return status;
++}
++
++static int iuu_uart_flush(struct usb_serial_port *port)
++{
++	int i;
++	int status;
++	u8 rxcmd = IUU_UART_RX;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++
++	dbg("%s - enter", __FUNCTION__);
++
++	if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
++		return -EIO;
++
++	for (i = 0; i < 2; i++) {
++		status = bulk_immediate(port, &rxcmd, 1);
++		if (status != IUU_OPERATION_OK) {
++			dbg("%s - uart_flush_write error", __FUNCTION__);
++			return status;
++		}
++
++		status = read_immediate(port, &priv->len, 1);
++		if (status != IUU_OPERATION_OK) {
++			dbg("%s - uart_flush_read error", __FUNCTION__);
++			return status;
++		}
++
++		if (priv->len > 0) {
++			dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
++			    priv->len);
++			status = read_immediate(port, priv->buf, priv->len);
++			if (status != IUU_OPERATION_OK) {
++				dbg("%s - uart_flush_read error", __FUNCTION__);
++				return status;
++			}
++		}
++	}
++	dbg("%s - uart_flush_read OK!", __FUNCTION__);
++	iuu_led(port, 0, 0xF000, 0, 0xFF);
++	return status;
++}
++
++static void read_buf_callback(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	unsigned char *data = urb->transfer_buffer;
++	struct tty_struct *tty;
++	dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++
++	if (urb->status) {
++		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++		if (urb->status == -EPROTO) {
++			/* reschedule needed */
++		}
++		return;
++	}
++
++	dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
++	tty = port->tty;
++	if (data == NULL)
++		dbg("%s - data is NULL !!!", __FUNCTION__);
++	if (tty && urb->actual_length && data) {
++		tty_insert_flip_string(tty, data, urb->actual_length);
++		tty_flip_buffer_push(tty);
++	}
++	iuu_led_activity_on(urb);
++}
++
++static int iuu_bulk_write(struct usb_serial_port *port)
++{
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	unsigned int flags;
++	int result;
++	int i;
++	char *buf_ptr = port->write_urb->transfer_buffer;
++	dbg("%s - enter", __FUNCTION__);
++
++	*buf_ptr++ = IUU_UART_ESC;
++	*buf_ptr++ = IUU_UART_TX;
++	*buf_ptr++ = priv->writelen;
++
++	memcpy(buf_ptr, priv->writebuf,
++	       priv->writelen);
++	if (debug == 1) {
++		for (i = 0; i < priv->writelen; i++)
++			sprintf(priv->dbgbuf + i*2 ,
++				"%02X", priv->writebuf[i]);
++		priv->dbgbuf[priv->writelen+i*2] = 0;
++		dbg("%s - writing %i chars : %s", __FUNCTION__,
++		    priv->writelen, priv->dbgbuf);
++	}
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, priv->writelen + 3,
++			  iuu_rxcmd, port);
++	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
++	spin_lock_irqsave(&priv->lock, flags);
++	priv->writelen = 0;
++	spin_unlock_irqrestore(&priv->lock, flags);
++	usb_serial_port_softint(port);
++	return result;
++}
++
++static int iuu_read_buf(struct usb_serial_port *port, int len)
++{
++	int result;
++	dbg("%s - enter", __FUNCTION__);
++
++	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++			  usb_rcvbulkpipe(port->serial->dev,
++					  port->bulk_in_endpointAddress),
++			  port->read_urb->transfer_buffer, len,
++			  read_buf_callback, port);
++	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++	return result;
++}
++
++static void iuu_uart_read_callback(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	unsigned int flags;
++	int status;
++	int error = 0;
++	int len = 0;
++	unsigned char *data = urb->transfer_buffer;
++	priv->poll++;
++
++	dbg("%s - enter", __FUNCTION__);
++
++	if (urb->status) {
++		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++		/* error stop all */
++		return;
++	}
++	if (data == NULL)
++		dbg("%s - data is NULL !!!", __FUNCTION__);
++
++	if (urb->actual_length == 1  && data != NULL)
++		len = (int) data[0];
++
++	if (urb->actual_length > 1) {
++		dbg("%s - urb->actual_length = %i", __FUNCTION__,
++		    urb->actual_length);
++		error = 1;
++		return;
++	}
++	/* if len > 0 call readbuf */
++
++	if (len > 0 && error == 0) {
++		dbg("%s - call read buf - len to read is %i ",
++			__FUNCTION__, len);
++		status = iuu_read_buf(port, len);
++		return;
++	}
++	/* need to update status  ? */
++	if (priv->poll > 99) {
++		status = iuu_status(port);
++		priv->poll = 0;
++		return;
++	}
++
++	/* reset waiting ? */
++
++	if (priv->reset == 1) {
++		status = iuu_reset(port, 0xC);
++		return;
++	}
++	/* Writebuf is waiting */
++	spin_lock_irqsave(&priv->lock, flags);
++	if (priv->writelen > 0) {
++		spin_unlock_irqrestore(&priv->lock, flags);
++		status = iuu_bulk_write(port);
++		return;
++	}
++	spin_unlock_irqrestore(&priv->lock, flags);
++	/* if nothing to write call again rxcmd */
++	dbg("%s - rxcmd recall", __FUNCTION__);
++	iuu_led_activity_off(urb);
++	return;
++}
++
++static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
++			  int count)
++{
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	unsigned int flags;
++	dbg("%s - enter", __FUNCTION__);
++
++	if (count > 256)
++		return -ENOMEM;
++
++	spin_lock_irqsave(&priv->lock, flags);
++	if (priv->writelen > 0) {
++		/* buffer already filled but not commited */
++		spin_unlock_irqrestore(&priv->lock, flags);
++		return (0);
++	}
++	/* fill the buffer */
++	memcpy(priv->writebuf, buf, count);
++	priv->writelen = count;
++	spin_unlock_irqrestore(&priv->lock, flags);
++
++	return (count);
++}
++
++static void read_rxcmd_callback(struct urb *urb)
++{
++	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	int result;
++	dbg("%s - enter", __FUNCTION__);
++
++	dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++
++	if (urb->status) {
++		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
++		/* error stop all */
++		return;
++	}
++
++	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++			  usb_rcvbulkpipe(port->serial->dev,
++					  port->bulk_in_endpointAddress),
++			  port->read_urb->transfer_buffer, 256,
++			  iuu_uart_read_callback, port);
++	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
++	dbg("%s - submit result = %d", __FUNCTION__, result);
++	return;
++}
++
++static int iuu_uart_on(struct usb_serial_port *port)
++{
++	int status;
++	u8 *buf;
++
++	buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
++
++	if (!buf)
++		return -ENOMEM;
++
++	buf[0] = IUU_UART_ENABLE;
++	buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
++	buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
++	buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
++
++	status = bulk_immediate(port, buf, 4);
++	if (status != IUU_OPERATION_OK) {
++		dbg("%s - uart_on error", __FUNCTION__);
++		goto uart_enable_failed;
++	}
++	/*  iuu_reset() the card after iuu_uart_on() */
++	status = iuu_uart_flush(port);
++	if (status != IUU_OPERATION_OK)
++		dbg("%s - uart_flush error", __FUNCTION__);
++uart_enable_failed:
++	kfree(buf);
++	return status;
++}
++
++/*  Diables the IUU UART (a.k.a. the Phoenix voiderface) */
++static int iuu_uart_off(struct usb_serial_port *port)
++{
++	int status;
++	u8 *buf;
++	buf = kmalloc(1, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++	buf[0] = IUU_UART_DISABLE;
++
++	status = bulk_immediate(port, buf, 1);
++	if (status != IUU_OPERATION_OK)
++		dbg("%s - uart_off error", __FUNCTION__);
++
++	kfree(buf);
++	return status;
++}
++
++static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
++			 u32 *actual, u8 parity)
++{
++	int status;
++	u8 *dataout;
++	u8 DataCount = 0;
++	u8 T1Frekvens = 0;
++	u8 T1reload = 0;
++	unsigned int T1FrekvensHZ = 0;
++
++	dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
++
++	if (!dataout)
++		return -ENOMEM;
++
++	if (baud < 1200 || baud > 230400) {
++		kfree(dataout);
++		return IUU_INVALID_PARAMETER;
++	}
++	if (baud > 977) {
++		T1Frekvens = 3;
++		T1FrekvensHZ = 500000;
++	}
++
++	if (baud > 3906) {
++		T1Frekvens = 2;
++		T1FrekvensHZ = 2000000;
++	}
++
++	if (baud > 11718) {
++		T1Frekvens = 1;
++		T1FrekvensHZ = 6000000;
++	}
++
++	if (baud > 46875) {
++		T1Frekvens = 0;
++		T1FrekvensHZ = 24000000;
++	}
++
++	T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
++
++	/*  magic number here:  ENTER_FIRMWARE_UPDATE; */
++	dataout[DataCount++] = IUU_UART_ESC;
++	/*  magic number here:  CHANGE_BAUD; */
++	dataout[DataCount++] = IUU_UART_CHANGE;
++	dataout[DataCount++] = T1Frekvens;
++	dataout[DataCount++] = T1reload;
++
++	*actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
++
++	switch (parity & 0x0F) {
++	case IUU_PARITY_NONE:
++		dataout[DataCount++] = 0x00;
++		break;
++	case IUU_PARITY_EVEN:
++		dataout[DataCount++] = 0x01;
++		break;
++	case IUU_PARITY_ODD:
++		dataout[DataCount++] = 0x02;
++		break;
++	case IUU_PARITY_MARK:
++		dataout[DataCount++] = 0x03;
++		break;
++	case IUU_PARITY_SPACE:
++		dataout[DataCount++] = 0x04;
++		break;
++	default:
++		kfree(dataout);
++		return IUU_INVALID_PARAMETER;
++		break;
++	}
++
++	switch (parity & 0xF0) {
++	case IUU_ONE_STOP_BIT:
++		dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
++		break;
++
++	case IUU_TWO_STOP_BITS:
++		dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
++		break;
++	default:
++		kfree(dataout);
++		return IUU_INVALID_PARAMETER;
++		break;
++	}
++
++	status = bulk_immediate(port, dataout, DataCount);
++	if (status != IUU_OPERATION_OK)
++		dbg("%s - uart_off error", __FUNCTION__);
++	kfree(dataout);
++	return status;
++}
++
++static int set_control_lines(struct usb_device *dev, u8 value)
++{
++	return 0;
++}
++
++static void iuu_close(struct usb_serial_port *port, struct file *filp)
++{
++	/* iuu_led (port,255,0,0,0); */
++	struct usb_serial *serial;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++	unsigned long flags;
++	unsigned int c_cflag;
++
++	serial = port->serial;
++	if (!serial)
++		return;
++
++	dbg("%s - port %d", __FUNCTION__, port->number);
++
++	iuu_uart_off(port);
++	if (serial->dev) {
++		if (port->tty) {
++			c_cflag = port->tty->termios->c_cflag;
++			if (c_cflag & HUPCL) {
++				/* drop DTR and RTS */
++				priv = usb_get_serial_port_data(port);
++				spin_lock_irqsave(&priv->lock, flags);
++				priv->line_control = 0;
++				spin_unlock_irqrestore(&priv->lock, flags);
++				set_control_lines(port->serial->dev, 0);
++			}
++		}
++		/* free writebuf */
++		/* shutdown our urbs */
++		dbg("%s - shutting down urbs", __FUNCTION__);
++		usb_kill_urb(port->write_urb);
++		usb_kill_urb(port->read_urb);
++		usb_kill_urb(port->interrupt_in_urb);
++		msleep(1000);
++		/* wait one second to free all buffers */
++		iuu_led(port, 0, 0, 0xF000, 0xFF);
++		msleep(1000);
++		usb_reset_device(port->serial->dev);
++	}
++}
++
++static int iuu_open(struct usb_serial_port *port, struct file *filp)
++{
++	struct usb_serial *serial = port->serial;
++	u8 *buf;
++	int result;
++	u32 actual;
++	unsigned long flags;
++	struct iuu_private *priv = usb_get_serial_port_data(port);
++
++	dbg("%s -  port %d", __FUNCTION__, port->number);
++	usb_clear_halt(serial->dev, port->write_urb->pipe);
++	usb_clear_halt(serial->dev, port->read_urb->pipe);
++
++	buf = kmalloc(10, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	/* fixup the endpoint buffer size */
++	kfree(port->bulk_out_buffer);
++	port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
++	port->bulk_out_size = 512;
++	kfree(port->bulk_in_buffer);
++	port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
++	port->bulk_in_size = 512;
++
++	if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
++		kfree(port->bulk_out_buffer);
++		kfree(port->bulk_in_buffer);
++		kfree(buf);
++		return -ENOMEM;
++	}
++
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->bulk_out_buffer, 512,
++			  NULL, NULL);
++
++
++	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
++			  usb_rcvbulkpipe(port->serial->dev,
++					  port->bulk_in_endpointAddress),
++			  port->bulk_in_buffer, 512,
++			  NULL, NULL);
++
++	/* set the termios structure */
++	spin_lock_irqsave(&priv->lock, flags);
++	if (!priv->termios_initialized) {
++		*(port->tty->termios) = tty_std_termios;
++		port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
++						| TIOCM_CTS | CSTOPB | PARENB;
++		port->tty->termios->c_lflag = 0;
++		port->tty->termios->c_oflag = 0;
++		port->tty->termios->c_iflag = 0;
++		priv->termios_initialized = 1;
++		port->tty->low_latency = 1;
++		priv->poll = 0;
++	 }
++	spin_unlock_irqrestore(&priv->lock, flags);
++
++	/* initialize writebuf */
++#define FISH(a, b, c, d) do { \
++	result = usb_control_msg(port->serial->dev,	\
++				usb_rcvctrlpipe(port->serial->dev, 0),	\
++				b, a, c, d, buf, 1, 1000); \
++	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", a, b, c, d, result, \
++				buf[0]); } while (0);
++
++#define SOUP(a, b, c, d)  do { \
++	result = usb_control_msg(port->serial->dev,	\
++				usb_sndctrlpipe(port->serial->dev, 0),	\
++				b, a, c, d, NULL, 0, 1000); \
++	dbg("0x%x:0x%x:0x%x:0x%x  %d", a, b, c, d, result); } while (0)
++
++	/*  This is not UART related but IUU USB driver related or something */
++	/*  like that. Basically no IUU will accept any commands from the USB */
++	/*  host unless it has received the following message */
++	/* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
++
++	SOUP(0x03, 0x02, 0x02, 0x0);
++	kfree(buf);
++	iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
++	iuu_uart_on(port);
++	if (boost < 100)
++		boost = 100;
++	switch (clockmode) {
++	case 2:		/*  3.680 Mhz */
++		iuu_clk(port, IUU_CLK_3680000 * boost / 100);
++		result =
++		    iuu_uart_baud(port, 9600 * boost / 100, &actual,
++				  IUU_PARITY_EVEN);
++		break;
++	case 3:		/*  6.00 Mhz */
++		iuu_clk(port, IUU_CLK_6000000 * boost / 100);
++		result =
++		    iuu_uart_baud(port, 16457 * boost / 100, &actual,
++				  IUU_PARITY_EVEN);
++		break;
++	default:		/*  3.579 Mhz */
++		iuu_clk(port, IUU_CLK_3579000 * boost / 100);
++		result =
++		    iuu_uart_baud(port, 9600 * boost / 100, &actual,
++				  IUU_PARITY_EVEN);
++	}
++
++	/* set the cardin cardout signals */
++	switch (cdmode) {
++	case 0:
++		iuu_cardin = 0;
++		iuu_cardout = 0;
++		break;
++	case 1:
++		iuu_cardin = TIOCM_CD;
++		iuu_cardout =  0;
++		break;
++	case 2:
++		iuu_cardin = 0;
++		iuu_cardout = TIOCM_CD;
++		break;
++	case 3:
++		iuu_cardin = TIOCM_DSR;
++		iuu_cardout = 0;
++		break;
++	case 4:
++		iuu_cardin = 0;
++		iuu_cardout = TIOCM_DSR;
++		break;
++	case 5:
++		iuu_cardin = TIOCM_CTS;
++		iuu_cardout = 0;
++		break;
++	case 6:
++		iuu_cardin = 0;
++		iuu_cardout = TIOCM_CTS;
++		break;
++	case 7:
++		iuu_cardin = TIOCM_RNG;
++		iuu_cardout = 0;
++		break;
++	case 8:
++		iuu_cardin = 0;
++		iuu_cardout = TIOCM_RNG;
++	}
++
++	iuu_uart_flush(port);
++
++	dbg("%s - initialization done", __FUNCTION__);
++
++	memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
++	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
++			  usb_sndbulkpipe(port->serial->dev,
++					  port->bulk_out_endpointAddress),
++			  port->write_urb->transfer_buffer, 1,
++			  read_rxcmd_callback, port);
++	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
++
++	if (result) {
++		dev_err(&port->dev, "%s - failed submitting read urb,"
++			" error %d\n", __FUNCTION__, result);
++		iuu_close(port, NULL);
++		return -EPROTO;
++	} else {
++		dbg("%s - rxcmd OK", __FUNCTION__);
++	}
++	return result;
++}
++
++static struct usb_serial_driver iuu_device = {
++	.driver = {
++		   .owner = THIS_MODULE,
++		   .name = "iuu_phoenix",
++		   },
++	.id_table = id_table,
++	.num_interrupt_in = NUM_DONT_CARE,
++	.num_bulk_in = 1,
++	.num_bulk_out = 1,
++	.num_ports = 1,
++	.open = iuu_open,
++	.close = iuu_close,
++	.write = iuu_uart_write,
++	.read_bulk_callback = iuu_uart_read_callback,
++	.tiocmget = iuu_tiocmget,
++	.tiocmset = iuu_tiocmset,
++	.attach = iuu_startup,
++	.shutdown = iuu_shutdown,
++};
++
++static int __init iuu_init(void)
++{
++	int retval;
++	retval = usb_serial_register(&iuu_device);
++	if (retval)
++		goto failed_usb_serial_register;
++	retval = usb_register(&iuu_driver);
++	if (retval)
++		goto failed_usb_register;
++	info(DRIVER_DESC " " DRIVER_VERSION);
++	return 0;
++failed_usb_register:
++	usb_serial_deregister(&iuu_device);
++failed_usb_serial_register:
++	return retval;
++}
++
++static void __exit iuu_exit(void)
++{
++	usb_deregister(&iuu_driver);
++	usb_serial_deregister(&iuu_device);
++}
++
++module_init(iuu_init);
++module_exit(iuu_exit);
++
++MODULE_AUTHOR("Alain Degreffe eczema at ecze.com");
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++MODULE_VERSION(DRIVER_VERSION);
++module_param(debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(debug, "Debug enabled or not");
++
++module_param(xmas, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(xmas, "xmas color enabled or not");
++
++module_param(boost, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500");
++
++module_param(clockmode, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
++
++module_param(cdmode, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, "
++		 "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING");
+diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
+new file mode 100644
+index 0000000..b82630a
+--- /dev/null
++++ b/drivers/usb/serial/iuu_phoenix.h
+@@ -0,0 +1,122 @@
++/*
++ * Infinity Unlimited USB Phoenix driver
++ *
++ * Copyright (C) 2007 Alain Degreffe (eczema at ecze.com)
++ *
++ *
++ * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás )
++ *
++ *	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.
++ *
++ *  And tested with help of WB Electronics
++ *
++ */
++
++#define   IUU_USB_VENDOR_ID  0x104f
++#define   IUU_USB_PRODUCT_ID  0x0004
++#define   IUU_USB_OP_TIMEOUT  0x0200
++
++/* Programmer commands */
++
++#define IUU_NO_OPERATION   0x00
++#define IUU_GET_FIRMWARE_VERSION   0x01
++#define IUU_GET_PRODUCT_NAME   0x02
++#define IUU_GET_STATE_REGISTER   0x03
++#define IUU_SET_LED   0x04
++#define IUU_WAIT_MUS   0x05
++#define IUU_WAIT_MS   0x06
++#define IUU_GET_LOADER_VERSION   0x50
++#define IUU_RST_SET   0x52
++#define IUU_RST_CLEAR   0x53
++#define IUU_SET_VCC   0x59
++#define IUU_UART_ENABLE   0x49
++#define IUU_UART_DISABLE   0x4A
++#define IUU_UART_WRITE_I2C   0x4C
++#define IUU_UART_ESC   0x5E
++#define IUU_UART_TRAP   0x54
++#define IUU_UART_TRAP_BREAK   0x5B
++#define IUU_UART_RX   0x56
++#define IUU_AVR_ON   0x21
++#define IUU_AVR_OFF   0x22
++#define IUU_AVR_1CLK   0x23
++#define IUU_AVR_RESET   0x24
++#define IUU_AVR_RESET_PC   0x25
++#define IUU_AVR_INC_PC   0x26
++#define IUU_AVR_INCN_PC   0x27
++#define IUU_AVR_PREAD   0x29
++#define IUU_AVR_PREADN   0x2A
++#define IUU_AVR_PWRITE   0x28
++#define IUU_AVR_DREAD   0x2C
++#define IUU_AVR_DREADN   0x2D
++#define IUU_AVR_DWRITE   0x2B
++#define IUU_AVR_PWRITEN   0x2E
++#define IUU_EEPROM_ON   0x37
++#define IUU_EEPROM_OFF   0x38
++#define IUU_EEPROM_WRITE   0x39
++#define IUU_EEPROM_WRITEX   0x3A
++#define IUU_EEPROM_WRITE8   0x3B
++#define IUU_EEPROM_WRITE16   0x3C
++#define IUU_EEPROM_WRITEX32   0x3D
++#define IUU_EEPROM_WRITEX64   0x3E
++#define IUU_EEPROM_READ   0x3F
++#define IUU_EEPROM_READX   0x40
++#define IUU_EEPROM_BREAD   0x41
++#define IUU_EEPROM_BREADX   0x42
++#define IUU_PIC_CMD   0x0A
++#define IUU_PIC_CMD_LOAD   0x0B
++#define IUU_PIC_CMD_READ   0x0C
++#define IUU_PIC_ON   0x0D
++#define IUU_PIC_OFF   0x0E
++#define IUU_PIC_RESET   0x16
++#define IUU_PIC_INC_PC   0x0F
++#define IUU_PIC_INCN_PC   0x10
++#define IUU_PIC_PWRITE   0x11
++#define IUU_PIC_PREAD   0x12
++#define IUU_PIC_PREADN   0x13
++#define IUU_PIC_DWRITE   0x14
++#define IUU_PIC_DREAD   0x15
++#define IUU_UART_NOP   0x00
++#define IUU_UART_CHANGE   0x02
++#define IUU_UART_TX   0x04
++#define IUU_DELAY_MS   0x06
++
++#define IUU_OPERATION_OK   0x00
++#define IUU_DEVICE_NOT_FOUND   0x01
++#define IUU_INVALID_HANDLE   0x02
++#define IUU_INVALID_PARAMETER   0x03
++#define IUU_INVALID_voidERFACE   0x04
++#define IUU_INVALID_REQUEST_LENGTH   0x05
++#define IUU_UART_NOT_ENABLED   0x06
++#define IUU_WRITE_ERROR   0x07
++#define IUU_READ_ERROR   0x08
++#define IUU_TX_ERROR   0x09
++#define IUU_RX_ERROR   0x0A
++
++#define IUU_PARITY_NONE   0x00
++#define IUU_PARITY_EVEN   0x01
++#define IUU_PARITY_ODD   0x02
++#define IUU_PARITY_MARK   0x03
++#define IUU_PARITY_SPACE   0x04
++#define IUU_SC_INSERTED   0x01
++#define IUU_VERIFY_ERROR   0x02
++#define IUU_SIM_INSERTED   0x04
++#define IUU_TWO_STOP_BITS   0x00
++#define IUU_ONE_STOP_BIT   0x20
++#define IUU_BAUD_2400   0x0398
++#define IUU_BAUD_9600   0x0298
++#define IUU_BAUD_19200   0x0164
++#define IUU_BAUD_28800   0x0198
++#define IUU_BAUD_38400   0x01B2
++#define IUU_BAUD_57600   0x0030
++#define IUU_BAUD_115200   0x0098
++#define IUU_CLK_3579000   3579000
++#define IUU_CLK_3680000   3680000
++#define IUU_CLK_6000000   6000000
++#define IUU_FULLCARD_IN   0x01
++#define IUU_DEV_ERROR   0x02
++#define IUU_MINICARD_IN   0x04
++#define IUU_VCC_5V   0x00
++#define IUU_VCC_3V   0x01
+diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
+index 7c069a0..ea7bba6 100644
+--- a/drivers/usb/serial/keyspan.c
++++ b/drivers/usb/serial/keyspan.c
+@@ -838,7 +838,7 @@ static void	usa49_indat_callback(struct urb *urb)
+ 
+ 	port = (struct usb_serial_port *) urb->context;
+ 	tty = port->tty;
+-	if (urb->actual_length) {
++	if (tty && urb->actual_length) {
+ 		/* 0x80 bit is error flag */
+ 		if ((data[0] & 0x80) == 0) {
+ 			/* no error on any byte */
+diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
+index be9ac20..b1fa5a3 100644
+--- a/drivers/usb/serial/keyspan_pda.c
++++ b/drivers/usb/serial/keyspan_pda.c
+@@ -303,7 +303,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
+ }
+ 
  
--	if (drv_data->ioaddr == SSP1_VIRT)
--		clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
--	else if (drv_data->ioaddr == SSP2_VIRT)
--		clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
--	else if (drv_data->ioaddr == SSP3_VIRT)
--		clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
--	else
--	{
--		dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
--			drv_data->ioaddr);
--		return -ENODEV;
--	}
-+	clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
- 	chip->speed_hz = spi->max_speed_hz;
+-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
++static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud)
+ {
+ 	int rc;
+ 	int bindex;
+@@ -319,7 +319,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+ 		case 38400: bindex = 7; break;
+ 		case 57600: bindex = 8; break;
+ 		case 115200: bindex = 9; break;
+-		default: return -EINVAL;
++		default:
++			bindex = 5;	/* Default to 9600 */
++			baud = 9600;
+ 	}
  
- 	chip->cr0 = clk_div
-@@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi)
+ 	/* rather than figure out how to sleep while waiting for this
+@@ -334,7 +336,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+ 			     NULL, /* &data */
+ 			     0, /* size */
+ 			     2000); /* timeout */
+-	return(rc);
++	if (rc < 0)
++		return 0;
++	return baud;
+ }
  
- 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
- 	if (drv_data->ssp_type != PXA25x_SSP)
--		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
-+		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
- 				spi->bits_per_word,
--				(CLOCK_SPEED_HZ)
-+				clk_get_rate(ssp->clk)
- 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- 				spi->mode & 0x3);
- 	else
--		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
-+		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
- 				spi->bits_per_word,
--				(CLOCK_SPEED_HZ/2)
-+				clk_get_rate(ssp->clk)
- 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- 				spi->mode & 0x3);
  
-@@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
- 	struct pxa2xx_spi_master *platform_info;
- 	struct spi_master *master;
- 	struct driver_data *drv_data = 0;
--	struct resource *memory_resource;
--	int irq;
-+	struct ssp_device *ssp;
- 	int status = 0;
+@@ -366,7 +370,7 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
+ 				     struct ktermios *old_termios)
+ {
+ 	struct usb_serial *serial = port->serial;
+-	unsigned int cflag = port->tty->termios->c_cflag;
++	speed_t speed;
+ 
+ 	/* cflag specifies lots of stuff: number of stop bits, parity, number
+ 	   of data bits, baud. What can the device actually handle?:
+@@ -388,22 +392,18 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
+ 
+ 	   For now, just do baud. */
+ 
+-	switch (cflag & CBAUD) {
+-		/* we could support more values here, just need to calculate
+-		   the necessary divisors in the firmware. <asm/termbits.h>
+-		   has the Bnnn constants. */
+-		case B110: keyspan_pda_setbaud(serial, 110); break;
+-		case B300: keyspan_pda_setbaud(serial, 300); break;
+-		case B1200: keyspan_pda_setbaud(serial, 1200); break;
+-		case B2400: keyspan_pda_setbaud(serial, 2400); break;
+-		case B4800: keyspan_pda_setbaud(serial, 4800); break;
+-		case B9600: keyspan_pda_setbaud(serial, 9600); break;
+-		case B19200: keyspan_pda_setbaud(serial, 19200); break;
+-		case B38400: keyspan_pda_setbaud(serial, 38400); break;
+-		case B57600: keyspan_pda_setbaud(serial, 57600); break;
+-		case B115200: keyspan_pda_setbaud(serial, 115200); break;
+-		default: dbg("can't handle requested baud rate"); break;
++	speed = tty_get_baud_rate(port->tty);
++	speed = keyspan_pda_setbaud(serial, speed);
++
++	if (speed == 0) {
++		dbg("can't handle requested baud rate");
++		/* It hasn't changed so.. */
++		speed = tty_termios_baud_rate(old_termios);
+ 	}
++	/* Only speed can change so copy the old h/w parameters
++	   then encode the new speed */
++	tty_termios_copy_hw(port->tty->termios, old_termios);
++	tty_encode_baud_rate(port->tty, speed, speed);
+ }
+ 
+ 
+diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
+index 90e3216..55736df 100644
+--- a/drivers/usb/serial/kl5kusb105.c
++++ b/drivers/usb/serial/kl5kusb105.c
+@@ -461,17 +461,21 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
+ 
+ 	dbg("%s port %d", __FUNCTION__, port->number);
+ 
+-	/* send READ_OFF */
+-	rc = usb_control_msg (port->serial->dev,
+-			      usb_sndctrlpipe(port->serial->dev, 0),
+-			      KL5KUSB105A_SIO_CONFIGURE,
+-			      USB_TYPE_VENDOR | USB_DIR_OUT,
+-			      KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+-			      0, /* index */
+-			      NULL, 0,
+-			      KLSI_TIMEOUT);
+-	if (rc < 0)
+-		    err("Disabling read failed (error = %d)", rc);
++	mutex_lock(&port->serial->disc_mutex);
++	if (!port->serial->disconnected) {
++		/* send READ_OFF */
++		rc = usb_control_msg (port->serial->dev,
++				      usb_sndctrlpipe(port->serial->dev, 0),
++				      KL5KUSB105A_SIO_CONFIGURE,
++				      USB_TYPE_VENDOR | USB_DIR_OUT,
++				      KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
++				      0, /* index */
++				      NULL, 0,
++				      KLSI_TIMEOUT);
++		if (rc < 0)
++			err("Disabling read failed (error = %d)", rc);
++	}
++	mutex_unlock(&port->serial->disc_mutex);
  
- 	platform_info = dev->platform_data;
+ 	/* shutdown our bulk reads and writes */
+ 	usb_kill_urb(port->write_urb);
+diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
+index aee4502..17b3bae 100644
+--- a/drivers/usb/serial/kobil_sct.c
++++ b/drivers/usb/serial/kobil_sct.c
+@@ -114,6 +114,7 @@ static struct usb_serial_driver kobil_device = {
+ 	.usb_driver = 		&kobil_driver,
+ 	.id_table =		id_table,
+ 	.num_interrupt_in =	NUM_DONT_CARE,
++	.num_interrupt_out = 	NUM_DONT_CARE,
+ 	.num_bulk_in =		0,
+ 	.num_bulk_out =		0,
+ 	.num_ports =		1,
+diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
+index 0dc99f7..fc1cea4 100644
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -182,10 +182,11 @@ struct mct_u232_private {
+ /*
+  * Later day 2.6.0-test kernels have new baud rates like B230400 which
+  * we do not know how to support. We ignore them for the moment.
+- * XXX Rate-limit the error message, it's user triggerable.
+  */
+-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
++static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result)
+ {
++	*result = value;
++
+ 	if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
+ 	  || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
+ 		switch (value) {
+@@ -200,11 +201,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
+ 		case  57600: return 0x0b;
+ 		case 115200: return 0x0c;
+ 		default:
+-			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+-			    " using default of B9600", value);
++			*result = 9600;
+ 			return 0x08;
+ 		}
+ 	} else {
++		/* FIXME: Can we use any divider - should we do
++		   divider = 115200/value;
++		   real baud = 115200/divider */
+ 		switch (value) {
+ 		case 300: break;
+ 		case 600: break;
+@@ -217,9 +220,8 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
+ 		case 57600: break;
+ 		case 115200: break;
+ 		default:
+-			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+-			    " using default of B9600", value);
+ 			value = 9600;
++			*result = 9600;
+ 		}
+ 		return 115200/value;
+ 	}
+@@ -232,16 +234,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_p
+         int rc;
+         unsigned char zero_byte = 0;
+         unsigned char cts_enable_byte = 0;
++        speed_t speed;
+ 
+-	divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
++	divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed));
+ 
+         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                              MCT_U232_SET_BAUD_RATE_REQUEST,
+ 			     MCT_U232_SET_REQUEST_TYPE,
+                              0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
+ 			     WDR_TIMEOUT);
+-	if (rc < 0)
++	if (rc < 0)	/*FIXME: What value speed results */
+ 		err("Set BAUD RATE %d failed (error = %d)", value, rc);
++	else
++		tty_encode_baud_rate(port->tty, speed, speed);
+ 	dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
  
--	if (platform_info->ssp_type == SSP_UNDEFINED) {
--		dev_err(&pdev->dev, "undefined SSP\n");
-+	ssp = ssp_request(pdev->id, pdev->name);
-+	if (ssp == NULL) {
-+		dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
- 		return -ENODEV;
+ 	/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
+@@ -482,21 +487,22 @@ error:
+ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
+ {
+ 	unsigned int c_cflag;
+-	unsigned long flags;
+ 	unsigned int control_state;
+ 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
+ 	dbg("%s port %d", __FUNCTION__, port->number);
+ 
+    	if (port->tty) {
+ 		c_cflag = port->tty->termios->c_cflag;
+-		if (c_cflag & HUPCL) {
+-		   /* drop DTR and RTS */
+-		   spin_lock_irqsave(&priv->lock, flags);
+-		   priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+-		   control_state = priv->control_state;
+-		   spin_unlock_irqrestore(&priv->lock, flags);
+-		   mct_u232_set_modem_ctrl(port->serial, control_state);
++		mutex_lock(&port->serial->disc_mutex);
++		if (c_cflag & HUPCL && !port->serial->disconnected) {
++			/* drop DTR and RTS */
++			spin_lock_irq(&priv->lock);
++			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
++			control_state = priv->control_state;
++			spin_unlock_irq(&priv->lock);
++			mct_u232_set_modem_ctrl(port->serial, control_state);
+ 		}
++		mutex_unlock(&port->serial->disc_mutex);
  	}
  
-@@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
- 	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
- 	if (!master) {
- 		dev_err(&pdev->dev, "can not alloc spi_master\n");
-+		ssp_free(ssp);
- 		return -ENOMEM;
+ 
+@@ -608,7 +614,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
+ {
+ 	struct usb_serial *serial = port->serial;
+ 	struct mct_u232_private *priv = usb_get_serial_port_data(port);
+-	unsigned int cflag = port->tty->termios->c_cflag;
++	struct ktermios *termios = port->tty->termios;
++	unsigned int cflag = termios->c_cflag;
+ 	unsigned int old_cflag = old_termios->c_cflag;
+ 	unsigned long flags;
+ 	unsigned int control_state;
+@@ -670,6 +677,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
+ 		break;
  	}
- 	drv_data = spi_master_get_devdata(master);
- 	drv_data->master = master;
- 	drv_data->master_info = platform_info;
- 	drv_data->pdev = pdev;
-+	drv_data->ssp = ssp;
  
- 	master->bus_num = pdev->id;
- 	master->num_chipselect = platform_info->num_chipselect;
-@@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
- 	master->setup = setup;
- 	master->transfer = transfer;
++	termios->c_cflag &= ~CMSPAR;
++
+ 	/* set the number of stop bits */
+ 	last_lcr |= (cflag & CSTOPB) ?
+ 		MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
+index aae10c8..07b6bec 100644
+--- a/drivers/usb/serial/mct_u232.h
++++ b/drivers/usb/serial/mct_u232.h
+@@ -79,7 +79,7 @@
+  * and "Intel solution". They are the regular MCT and "Sitecom" for us.
+  * This is pointless to document in the header, see the code for the bits.
+  */
+-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
++static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result);
+ 
+ /*
+  * Line Control Register (LCR)
+diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
+index e02c198..40f3a01 100644
+--- a/drivers/usb/serial/mos7720.c
++++ b/drivers/usb/serial/mos7720.c
+@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
+ 	}
+ 
+ 	/* While closing port, shutdown all bulk read, write  *
+-	 * and interrupt read if they exists                  */
+-	if (serial->dev) {
+-		dbg("Shutdown bulk write");
+-		usb_kill_urb(port->write_urb);
+-		dbg("Shutdown bulk read");
+-		usb_kill_urb(port->read_urb);
++	 * and interrupt read if they exists, otherwise nop   */
++	dbg("Shutdown bulk write");
++	usb_kill_urb(port->write_urb);
++	dbg("Shutdown bulk read");
++	usb_kill_urb(port->read_urb);
++
++	mutex_lock(&serial->disc_mutex);
++	/* these commands must not be issued if the device has
++	 * been disconnected */
++	if (!serial->disconnected) {
++		data = 0x00;
++		send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
++			     0x04, &data);
++
++		data = 0x00;
++		send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
++			     0x01, &data);
+ 	}
+-
+-	data = 0x00;
+-	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+-		     0x04, &data);
+-
+-	data = 0x00;
+-	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+-		     0x01, &data);
+-
++	mutex_unlock(&serial->disc_mutex);
+ 	mos7720_port->open = 0;
  
--	drv_data->ssp_type = platform_info->ssp_type;
-+	drv_data->ssp_type = ssp->type;
- 	drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
- 						sizeof(struct driver_data)), 8);
+ 	dbg("Leaving %s", __FUNCTION__);
+@@ -1040,11 +1043,6 @@ static void change_port_settings(struct moschip_port *mos7720_port,
  
--	/* Setup register addresses */
--	memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--	if (!memory_resource) {
--		dev_err(&pdev->dev, "memory resources not defined\n");
--		status = -ENODEV;
--		goto out_error_master_alloc;
+ 	tty = mos7720_port->port->tty;
+ 
+-	if ((!tty) || (!tty->termios)) {
+-		dbg("%s - no tty structures", __FUNCTION__);
+-		return;
 -	}
 -
--	drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
--	drv_data->ssdr_physical = memory_resource->start + 0x00000010;
--	if (platform_info->ssp_type == PXA25x_SSP) {
-+	drv_data->ioaddr = ssp->mmio_base;
-+	drv_data->ssdr_physical = ssp->phys_base + SSDR;
-+	if (ssp->type == PXA25x_SSP) {
- 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
- 		drv_data->dma_cr1 = 0;
- 		drv_data->clear_sr = SSSR_ROR;
-@@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
- 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
- 	}
+ 	dbg("%s: Entering ..........", __FUNCTION__);
  
--	/* Attach to IRQ */
--	irq = platform_get_irq(pdev, 0);
--	if (irq < 0) {
--		dev_err(&pdev->dev, "irq resource not defined\n");
--		status = -ENODEV;
--		goto out_error_master_alloc;
+ 	lData = UART_LCR_WLEN8;
+@@ -1175,7 +1173,10 @@ static void change_port_settings(struct moschip_port *mos7720_port,
+ 
+ 	dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ 	status = send_cmd_write_baud_rate(mos7720_port, baud);
+-
++	/* FIXME: needs to write actual resulting baud back not just
++	   blindly do so */
++	if (cflag & CBAUD)
++		tty_encode_baud_rate(tty, baud, baud);
+ 	/* Enable Interrupts */
+ 	data = 0x0c;
+ 	send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+@@ -1214,10 +1215,6 @@ static void mos7720_set_termios(struct usb_serial_port *port,
+ 
+ 	tty = port->tty;
+ 
+-	if (!port->tty || !port->tty->termios) {
+-		dbg("%s - no tty or termios", __FUNCTION__);
+-		return;
+-	}
+ 
+ 	if (!mos7720_port->open) {
+ 		dbg("%s - port not opened", __FUNCTION__);
+@@ -1228,19 +1225,13 @@ static void mos7720_set_termios(struct usb_serial_port *port,
+ 
+ 	cflag = tty->termios->c_cflag;
+ 
+-	if (!cflag) {
+-		printk("%s %s\n",__FUNCTION__,"cflag is NULL");
+-		return;
 -	}
 -
--	status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
-+	status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
- 	if (status < 0) {
- 		dev_err(&pdev->dev, "can not get IRQ\n");
- 		goto out_error_master_alloc;
-@@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
- 			goto out_error_dma_alloc;
+-	dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
++	dbg("%s - cflag %08x iflag %08x", __FUNCTION__,
+ 	    tty->termios->c_cflag,
+ 	    RELEVANT_IFLAG(tty->termios->c_iflag));
+ 
+-	if (old_termios)
+-		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+-		    old_termios->c_cflag,
+-		    RELEVANT_IFLAG(old_termios->c_iflag));
++	dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__,
++	    old_termios->c_cflag,
++	    RELEVANT_IFLAG(old_termios->c_iflag));
+ 
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 
+diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
+index c29c912..869ecd3 100644
+--- a/drivers/usb/serial/mos7840.c
++++ b/drivers/usb/serial/mos7840.c
+@@ -1133,7 +1133,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
+  *	This function will block the close until one of the following:
+  *		1. TX count are 0
+  *		2. The mos7840 has stopped
+- *		3. A timout of 3 seconds without activity has expired
++ *		3. A timeout of 3 seconds without activity has expired
+  *
+  ************************************************************************/
+ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
+@@ -1161,7 +1161,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
+ 			dbg("%s - TIMEOUT", __FUNCTION__);
+ 			return;
+ 		} else {
+-			/* Reset timout value back to seconds */
++			/* Reset timeout value back to seconds */
+ 			wait = 30;
  		}
+ 	}
+@@ -1275,7 +1275,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
+  *
+  *	This function will block the close until one of the following:
+  *		1. Response to our Chase comes from mos7840
+- *		2. A timout of 10 seconds without activity has expired
++ *		2. A timeout of 10 seconds without activity has expired
+  *		   (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
+  *
+  ************************************************************************/
+@@ -1304,7 +1304,7 @@ static void mos7840_block_until_chase_response(struct moschip_port
+ 			dbg("%s - TIMEOUT", __FUNCTION__);
+ 			return;
+ 		} else {
+-			/* Reset timout value back to seconds */
++			/* Reset timeout value back to seconds */
+ 			wait = 10;
+ 		}
+ 	}
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index d1185f5..5e8bf1b 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -180,6 +180,7 @@ static struct usb_device_id option_ids[] = {
+ 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8117) },	/* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
+ 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) },	/* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
+ 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8128) },	/* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
++	{ USB_DEVICE(DELL_VENDOR_ID, 0x8136) },	/* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
+ 	{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) },	/* Dell Wireless HSDPA 5520 */
+ 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
+ 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
+@@ -640,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
+ 	portdata->dtr_state = 0;
+ 
+ 	if (serial->dev) {
+-		option_send_setup(port);
++		mutex_lock(&serial->disc_mutex);
++		if (!serial->disconnected)
++			option_send_setup(port);
++		mutex_unlock(&serial->disc_mutex);
+ 
+ 		/* Stop reading/writing urbs */
+ 		for (i = 0; i < N_IN_URB; i++)
+diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
+index eea226a..a3847d6 100644
+--- a/drivers/usb/serial/oti6858.c
++++ b/drivers/usb/serial/oti6858.c
+@@ -79,7 +79,7 @@ static int debug;
+ #define PL2303_BUF_SIZE		1024
+ #define PL2303_TMP_BUF_SIZE	1024
+ 
+-struct pl2303_buf {
++struct oti6858_buf {
+ 	unsigned int	buf_size;
+ 	char		*buf_buf;
+ 	char		*buf_get;
+@@ -161,14 +161,14 @@ static int oti6858_startup(struct usb_serial *serial);
+ static void oti6858_shutdown(struct usb_serial *serial);
+ 
+ /* functions operating on buffers */
+-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
+-static void pl2303_buf_free(struct pl2303_buf *pb);
+-static void pl2303_buf_clear(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
+-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
++static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
++static void oti6858_buf_free(struct oti6858_buf *pb);
++static void oti6858_buf_clear(struct oti6858_buf *pb);
++static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
++static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
++static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
+ 					unsigned int count);
+-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
++static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
+ 					unsigned int count);
  
--		if (drv_data->ioaddr == SSP1_VIRT) {
--				DRCMRRXSSDR = DRCMR_MAPVLD
--						| drv_data->rx_channel;
--				DRCMRTXSSDR = DRCMR_MAPVLD
--						| drv_data->tx_channel;
--		} else if (drv_data->ioaddr == SSP2_VIRT) {
--				DRCMRRXSS2DR = DRCMR_MAPVLD
--						| drv_data->rx_channel;
--				DRCMRTXSS2DR = DRCMR_MAPVLD
--						| drv_data->tx_channel;
--		} else if (drv_data->ioaddr == SSP3_VIRT) {
--				DRCMRRXSS3DR = DRCMR_MAPVLD
--						| drv_data->rx_channel;
--				DRCMRTXSS3DR = DRCMR_MAPVLD
--						| drv_data->tx_channel;
--		} else {
--			dev_err(dev, "bad SSP type\n");
--			goto out_error_dma_alloc;
--		}
-+		DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
-+		DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
+ 
+@@ -203,7 +203,7 @@ static struct usb_serial_driver oti6858_device = {
+ struct oti6858_private {
+ 	spinlock_t lock;
+ 
+-	struct pl2303_buf *buf;
++	struct oti6858_buf *buf;
+ 	struct oti6858_control_pkt status;
+ 
+ 	struct {
+@@ -316,7 +316,7 @@ void send_data(struct work_struct *work)
  	}
+ 	priv->flags.write_urb_in_use = 1;
  
- 	/* Enable SOC clock */
--	pxa_set_cken(platform_info->clock_enable, 1);
-+	clk_enable(ssp->clk);
+-	count = pl2303_buf_data_avail(priv->buf);
++	count = oti6858_buf_data_avail(priv->buf);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
+ 	if (count > port->bulk_out_size)
+ 		count = port->bulk_out_size;
+@@ -345,7 +345,7 @@ void send_data(struct work_struct *work)
+ 	}
  
- 	/* Load default SSP configuration */
- 	write_SSCR0(0, drv_data->ioaddr);
-@@ -1479,7 +1450,7 @@ out_error_queue_alloc:
- 	destroy_queue(drv_data);
+ 	spin_lock_irqsave(&priv->lock, flags);
+-	pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
++	oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- out_error_clock_enabled:
--	pxa_set_cken(platform_info->clock_enable, 0);
-+	clk_disable(ssp->clk);
+ 	port->write_urb->transfer_buffer_length = count;
+@@ -370,7 +370,7 @@ static int oti6858_startup(struct usb_serial *serial)
+ 		priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
+ 		if (!priv)
+ 			break;
+-		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
++		priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
+ 		if (priv->buf == NULL) {
+ 			kfree(priv);
+ 			break;
+@@ -391,7 +391,7 @@ static int oti6858_startup(struct usb_serial *serial)
  
- out_error_dma_alloc:
- 	if (drv_data->tx_channel != -1)
-@@ -1488,17 +1459,18 @@ out_error_dma_alloc:
- 		pxa_free_dma(drv_data->rx_channel);
+ 	for (--i; i >= 0; --i) {
+ 		priv = usb_get_serial_port_data(serial->port[i]);
+-		pl2303_buf_free(priv->buf);
++		oti6858_buf_free(priv->buf);
+ 		kfree(priv);
+ 		usb_set_serial_port_data(serial->port[i], NULL);
+ 	}
+@@ -410,7 +410,7 @@ static int oti6858_write(struct usb_serial_port *port,
+ 		return count;
  
- out_error_irq_alloc:
--	free_irq(irq, drv_data);
-+	free_irq(ssp->irq, drv_data);
+ 	spin_lock_irqsave(&priv->lock, flags);
+-	count = pl2303_buf_put(priv->buf, buf, count);
++	count = oti6858_buf_put(priv->buf, buf, count);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- out_error_master_alloc:
- 	spi_master_put(master);
-+	ssp_free(ssp);
- 	return status;
- }
+ 	return count;
+@@ -425,7 +425,7 @@ static int oti6858_write_room(struct usb_serial_port *port)
+ 	dbg("%s(port = %d)", __FUNCTION__, port->number);
  
- static int pxa2xx_spi_remove(struct platform_device *pdev)
- {
- 	struct driver_data *drv_data = platform_get_drvdata(pdev);
--	int irq;
-+	struct ssp_device *ssp = drv_data->ssp;
- 	int status = 0;
+ 	spin_lock_irqsave(&priv->lock, flags);
+-	room = pl2303_buf_space_avail(priv->buf);
++	room = oti6858_buf_space_avail(priv->buf);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- 	if (!drv_data)
-@@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
+ 	return room;
+@@ -440,7 +440,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port)
+ 	dbg("%s(port = %d)", __FUNCTION__, port->number);
  
- 	/* Disable the SSP at the peripheral and SOC level */
- 	write_SSCR0(0, drv_data->ioaddr);
--	pxa_set_cken(drv_data->master_info->clock_enable, 0);
-+	clk_disable(ssp->clk);
+ 	spin_lock_irqsave(&priv->lock, flags);
+-	chars = pl2303_buf_data_avail(priv->buf);
++	chars = oti6858_buf_data_avail(priv->buf);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- 	/* Release DMA */
- 	if (drv_data->master_info->enable_dma) {
--		if (drv_data->ioaddr == SSP1_VIRT) {
--			DRCMRRXSSDR = 0;
--			DRCMRTXSSDR = 0;
--		} else if (drv_data->ioaddr == SSP2_VIRT) {
--			DRCMRRXSS2DR = 0;
--			DRCMRTXSS2DR = 0;
--		} else if (drv_data->ioaddr == SSP3_VIRT) {
--			DRCMRRXSS3DR = 0;
--			DRCMRTXSS3DR = 0;
--		}
-+		DRCMR(ssp->drcmr_rx) = 0;
-+		DRCMR(ssp->drcmr_tx) = 0;
- 		pxa_free_dma(drv_data->tx_channel);
- 		pxa_free_dma(drv_data->rx_channel);
+ 	return chars;
+@@ -458,7 +458,7 @@ static void oti6858_set_termios(struct usb_serial_port *port,
+ 
+ 	dbg("%s(port = %d)", __FUNCTION__, port->number);
+ 
+-	if ((!port->tty) || (!port->tty->termios)) {
++	if (!port->tty || !port->tty->termios) {
+ 		dbg("%s(): no tty structures", __FUNCTION__);
+ 		return;
+ 	}
+@@ -468,6 +468,8 @@ static void oti6858_set_termios(struct usb_serial_port *port,
+ 		*(port->tty->termios) = tty_std_termios;
+ 		port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ 		priv->flags.termios_initialized = 1;
++		port->tty->termios->c_ispeed = 38400;
++		port->tty->termios->c_ospeed = 38400;
  	}
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- 	/* Release IRQ */
--	irq = platform_get_irq(pdev, 0);
--	if (irq >= 0)
--		free_irq(irq, drv_data);
-+	free_irq(ssp->irq, drv_data);
-+
-+	/* Release SSP */
-+	ssp_free(ssp);
+@@ -504,19 +506,14 @@ static void oti6858_set_termios(struct usb_serial_port *port,
+ 	br = tty_get_baud_rate(port->tty);
+ 	if (br == 0) {
+ 		divisor = 0;
+-	} else if (br <= OTI6858_MAX_BAUD_RATE) {
++	} else {
+ 		int real_br;
++		br = min(br, OTI6858_MAX_BAUD_RATE);
  
- 	/* Disconnect from the SPI framework */
- 	spi_unregister_master(drv_data->master);
-@@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message)
- static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
- {
- 	struct driver_data *drv_data = platform_get_drvdata(pdev);
-+	struct ssp_device *ssp = drv_data->ssp;
- 	int status = 0;
+ 		divisor = (96000000 + 8 * br) / (16 * br);
+ 		real_br = 96000000 / (16 * divisor);
+-		if ((((real_br - br) * 100 + br - 1) / br) > 2) {
+-			dbg("%s(): baud rate %d is invalid", __FUNCTION__, br);
+-			return;
+-		}
+ 		divisor = cpu_to_le16(divisor);
+-	} else {
+-		dbg("%s(): baud rate %d is too high", __FUNCTION__, br);
+-		return;
++		tty_encode_baud_rate(port->tty, real_br, real_br);
+ 	}
  
- 	/* Check all childern for current power state */
-@@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
- 	if (status != 0)
- 		return status;
- 	write_SSCR0(0, drv_data->ioaddr);
--	pxa_set_cken(drv_data->master_info->clock_enable, 0);
-+	clk_disable(ssp->clk);
+ 	frame_fmt &= ~FMT_STOP_BITS_MASK;
+@@ -650,9 +647,9 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
+ 	dbg("%s(): entering wait loop", __FUNCTION__);
+ 	for (;;) {
+ 		set_current_state(TASK_INTERRUPTIBLE);
+-		if (pl2303_buf_data_avail(priv->buf) == 0
++		if (oti6858_buf_data_avail(priv->buf) == 0
+ 		|| timeout == 0 || signal_pending(current)
+-		|| !usb_get_intfdata(port->serial->interface))	/* disconnect */
++		|| port->serial->disconnected)
+ 			break;
+ 		spin_unlock_irqrestore(&priv->lock, flags);
+ 		timeout = schedule_timeout(timeout);
+@@ -663,7 +660,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
+ 	dbg("%s(): after wait loop", __FUNCTION__);
+ 
+ 	/* clear out any remaining data in the buffer */
+-	pl2303_buf_clear(priv->buf);
++	oti6858_buf_clear(priv->buf);
+ 	spin_unlock_irqrestore(&priv->lock, flags);
  
- 	return 0;
- }
-@@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
- static int pxa2xx_spi_resume(struct platform_device *pdev)
- {
- 	struct driver_data *drv_data = platform_get_drvdata(pdev);
-+	struct ssp_device *ssp = drv_data->ssp;
- 	int status = 0;
+ 	/* wait for characters to drain from the device */
+@@ -831,21 +828,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
+ 				return -EFAULT;
+ 			return oti6858_tiocmset(port, NULL, 0, x);
  
- 	/* Enable the SSP clock */
--	pxa_set_cken(drv_data->master_info->clock_enable, 1);
-+	clk_disable(ssp->clk);
+-		case TIOCGSERIAL:
+-			if (copy_to_user(user_arg, port->tty->termios,
+-						sizeof(struct ktermios))) {
+-				return -EFAULT;
+-			}
+-                        return 0;
+-
+-		case TIOCSSERIAL:
+-			if (copy_from_user(port->tty->termios, user_arg,
+-						sizeof(struct ktermios))) {
+-				return -EFAULT;
+-			}
+-			oti6858_set_termios(port, NULL);
+-			return 0;
+-
+ 		case TIOCMIWAIT:
+ 			dbg("%s(): TIOCMIWAIT", __FUNCTION__);
+ 			return wait_modem_info(port, arg);
+@@ -887,7 +869,7 @@ static void oti6858_shutdown(struct usb_serial *serial)
+ 	for (i = 0; i < serial->num_ports; ++i) {
+ 		priv = usb_get_serial_port_data(serial->port[i]);
+ 		if (priv) {
+-			pl2303_buf_free(priv->buf);
++			oti6858_buf_free(priv->buf);
+ 			kfree(priv);
+ 			usb_set_serial_port_data(serial->port[i], NULL);
+ 		}
+@@ -987,7 +969,7 @@ static void oti6858_read_int_callback(struct urb *urb)
  
- 	/* Start the queue running */
- 	status = start_queue(drv_data);
-diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
-index 93e9de4..682a6a4 100644
---- a/drivers/spi/spi.c
-+++ b/drivers/spi/spi.c
-@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
- }
- EXPORT_SYMBOL_GPL(spi_unregister_master);
+ 		spin_lock_irqsave(&priv->lock, flags);
+ 		if (priv->flags.write_urb_in_use == 0
+-				&& pl2303_buf_data_avail(priv->buf) != 0) {
++				&& oti6858_buf_data_avail(priv->buf) != 0) {
+ 			schedule_delayed_work(&priv->delayed_write_work,0);
+ 			resubmit = 0;
+ 		}
+@@ -1015,9 +997,8 @@ static void oti6858_read_bulk_callback(struct urb *urb)
+ 	struct tty_struct *tty;
+ 	unsigned char *data = urb->transfer_buffer;
+ 	unsigned long flags;
+-	int i, result;
+ 	int status = urb->status;
+-	char tty_flag;
++	int result;
  
-+static int __spi_master_match(struct device *dev, void *data)
-+{
-+	struct spi_master *m;
-+	u16 *bus_num = data;
-+
-+	m = container_of(dev, struct spi_master, dev);
-+	return m->bus_num == *bus_num;
-+}
-+
- /**
-  * spi_busnum_to_master - look up master associated with bus_num
-  * @bus_num: the master's bus number
-@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
- {
- 	struct device		*dev;
- 	struct spi_master	*master = NULL;
--	struct spi_master	*m;
+ 	dbg("%s(port = %d, status = %d)",
+ 				__FUNCTION__, port->number, status);
+@@ -1045,27 +1026,9 @@ static void oti6858_read_bulk_callback(struct urb *urb)
+ 		return;
+ 	}
+ 
+-	// get tty_flag from status
+-	tty_flag = TTY_NORMAL;
 -
--	down(&spi_master_class.sem);
--	list_for_each_entry(dev, &spi_master_class.children, node) {
--		m = container_of(dev, struct spi_master, dev);
--		if (m->bus_num == bus_num) {
--			master = spi_master_get(m);
--			break;
--		}
--	}
--	up(&spi_master_class.sem);
-+
-+	dev = class_find_device(&spi_master_class, &bus_num,
-+				__spi_master_match);
-+	if (dev)
-+		master = container_of(dev, struct spi_master, dev);
-+	/* reference got in class_find_device */
- 	return master;
- }
- EXPORT_SYMBOL_GPL(spi_busnum_to_master);
-diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
-index 4580b9c..04f7cd9 100644
---- a/drivers/spi/spi_mpc83xx.c
-+++ b/drivers/spi/spi_mpc83xx.c
-@@ -436,11 +436,7 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
- 	mpc83xx_spi->qe_mode = pdata->qe_mode;
- 	mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
- 	mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+-/* FIXME: probably, errors will be signalled using interrupt pipe! */
+-/*
+-	// break takes precedence over parity,
+-	// which takes precedence over framing errors
+-	if (status & UART_BREAK_ERROR )
+-		tty_flag = TTY_BREAK;
+-	else if (status & UART_PARITY_ERROR)
+-		tty_flag = TTY_PARITY;
+-	else if (status & UART_FRAME_ERROR)
+-		tty_flag = TTY_FRAME;
+-	dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
+-*/
 -
--	if (mpc83xx_spi->qe_mode)
--		mpc83xx_spi->spibrg = pdata->sysclk / 2;
--	else
--		mpc83xx_spi->spibrg = pdata->sysclk;
-+	mpc83xx_spi->spibrg = pdata->sysclk;
+ 	tty = port->tty;
+ 	if (tty != NULL && urb->actual_length > 0) {
+-		tty_buffer_request_room(tty, urb->actual_length);
+-		for (i = 0; i < urb->actual_length; ++i)
+-			tty_insert_flip_char(tty, data[i], tty_flag);
++		tty_insert_flip_string(tty, data, urb->actual_length);
+ 		tty_flip_buffer_push(tty);
+ 	}
  
- 	mpc83xx_spi->rx_shift = 0;
- 	mpc83xx_spi->tx_shift = 0;
-diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
-index f145d8a..1a31f7a 100644
---- a/drivers/ssb/b43_pci_bridge.c
-+++ b/drivers/ssb/b43_pci_bridge.c
-@@ -27,6 +27,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
- 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
- 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
- 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
-+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
- 	{ 0, },
- };
- MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
-diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
-index 85a2054..9028ed5 100644
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -872,14 +872,22 @@ EXPORT_SYMBOL(ssb_clockspeed);
+@@ -1133,18 +1096,18 @@ static void oti6858_write_bulk_callback(struct urb *urb)
  
- static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
+ 
+ /*
+- * pl2303_buf_alloc
++ * oti6858_buf_alloc
+  *
+  * Allocate a circular buffer and all associated memory.
+  */
+-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
++static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
  {
-+	u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
-+
- 	/* The REJECT bit changed position in TMSLOW between
- 	 * Backplane revisions. */
--	switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
-+	switch (rev) {
- 	case SSB_IDLOW_SSBREV_22:
- 		return SSB_TMSLOW_REJECT_22;
- 	case SSB_IDLOW_SSBREV_23:
- 		return SSB_TMSLOW_REJECT_23;
-+	case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
-+	case SSB_IDLOW_SSBREV_25:     /* same here */
-+	case SSB_IDLOW_SSBREV_26:     /* same here */
-+	case SSB_IDLOW_SSBREV_27:     /* same here */
-+		return SSB_TMSLOW_REJECT_23;	/* this is a guess */
- 	default:
-+		printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
- 		WARN_ON(1);
- 	}
- 	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
-diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
-index 0ab095c..b434df7 100644
---- a/drivers/ssb/pci.c
-+++ b/drivers/ssb/pci.c
-@@ -212,29 +212,29 @@ static inline u8 ssb_crc8(u8 crc, u8 data)
- 	return t[crc ^ data];
+-	struct pl2303_buf *pb;
++	struct oti6858_buf *pb;
+ 
+ 	if (size == 0)
+ 		return NULL;
+ 
+-	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
++	pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
+ 	if (pb == NULL)
+ 		return NULL;
+ 
+@@ -1161,11 +1124,11 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
  }
  
--static u8 ssb_sprom_crc(const u16 *sprom)
-+static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
+ /*
+- * pl2303_buf_free
++ * oti6858_buf_free
+  *
+  * Free the buffer and all associated memory.
+  */
+-static void pl2303_buf_free(struct pl2303_buf *pb)
++static void oti6858_buf_free(struct oti6858_buf *pb)
  {
- 	int word;
- 	u8 crc = 0xFF;
+ 	if (pb) {
+ 		kfree(pb->buf_buf);
+@@ -1174,11 +1137,11 @@ static void pl2303_buf_free(struct pl2303_buf *pb)
+ }
  
--	for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
-+	for (word = 0; word < size - 1; word++) {
- 		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
- 		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
- 	}
--	crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
-+	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
- 	crc ^= 0xFF;
+ /*
+- * pl2303_buf_clear
++ * oti6858_buf_clear
+  *
+  * Clear out all data in the circular buffer.
+  */
+-static void pl2303_buf_clear(struct pl2303_buf *pb)
++static void oti6858_buf_clear(struct oti6858_buf *pb)
+ {
+ 	if (pb != NULL) {
+ 		/* equivalent to a get of all data available */
+@@ -1187,12 +1150,12 @@ static void pl2303_buf_clear(struct pl2303_buf *pb)
+ }
  
- 	return crc;
+ /*
+- * pl2303_buf_data_avail
++ * oti6858_buf_data_avail
+  *
+  * Return the number of bytes of data available in the circular
+  * buffer.
+  */
+-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
++static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
+ {
+ 	if (pb == NULL)
+ 		return 0;
+@@ -1200,12 +1163,12 @@ static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
  }
  
--static int sprom_check_crc(const u16 *sprom)
-+static int sprom_check_crc(const u16 *sprom, u16 size)
+ /*
+- * pl2303_buf_space_avail
++ * oti6858_buf_space_avail
+  *
+  * Return the number of bytes of space available in the circular
+  * buffer.
+  */
+-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
++static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
  {
- 	u8 crc;
- 	u8 expected_crc;
- 	u16 tmp;
+ 	if (pb == NULL)
+ 		return 0;
+@@ -1213,14 +1176,14 @@ static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+ }
  
--	crc = ssb_sprom_crc(sprom);
--	tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
-+	crc = ssb_sprom_crc(sprom, size);
-+	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
- 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
- 	if (crc != expected_crc)
- 		return -EPROTO;
-@@ -246,8 +246,8 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+ /*
+- * pl2303_buf_put
++ * oti6858_buf_put
+  *
+  * Copy data data from a user buffer and put it into the circular buffer.
+  * Restrict to the amount of space available.
+  *
+  * Return the number of bytes copied.
+  */
+-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
++static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
+ 					unsigned int count)
  {
- 	int i;
+ 	unsigned int len;
+@@ -1228,7 +1191,7 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ 	if (pb == NULL)
+ 		return 0;
  
--	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
--		sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
-+	for (i = 0; i < bus->sprom_size; i++)
-+		sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
+-	len  = pl2303_buf_space_avail(pb);
++	len  = oti6858_buf_space_avail(pb);
+ 	if (count > len)
+ 		count = len;
+ 
+@@ -1252,14 +1215,14 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
  }
  
- static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
-@@ -255,6 +255,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
- 	struct pci_dev *pdev = bus->host_pci;
- 	int i, err;
- 	u32 spromctl;
-+	u16 size = bus->sprom_size;
+ /*
+- * pl2303_buf_get
++ * oti6858_buf_get
+  *
+  * Get data from the circular buffer and copy to the given buffer.
+  * Restrict to the amount of data available.
+  *
+  * Return the number of bytes copied.
+  */
+-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
++static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
+ 					unsigned int count)
+ {
+ 	unsigned int len;
+@@ -1267,7 +1230,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ 	if (pb == NULL)
+ 		return 0;
  
- 	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
- 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
-@@ -266,12 +267,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
- 		goto err_ctlreg;
- 	ssb_printk(KERN_NOTICE PFX "[ 0%%");
- 	msleep(500);
--	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
--		if (i == SSB_SPROMSIZE_WORDS / 4)
-+	for (i = 0; i < size; i++) {
-+		if (i == size / 4)
- 			ssb_printk("25%%");
--		else if (i == SSB_SPROMSIZE_WORDS / 2)
-+		else if (i == size / 2)
- 			ssb_printk("50%%");
--		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
-+		else if (i == (size * 3) / 4)
- 			ssb_printk("75%%");
- 		else if (i % 2)
- 			ssb_printk(".");
-@@ -296,24 +297,53 @@ err_ctlreg:
- 	return err;
+-	len = pl2303_buf_data_avail(pb);
++	len = oti6858_buf_data_avail(pb);
+ 	if (count > len)
+ 		count = len;
+ 
+diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
+index 0da1df9..ae3ec1a 100644
+--- a/drivers/usb/serial/pl2303.c
++++ b/drivers/usb/serial/pl2303.c
+@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
+ 	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
+ 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
++	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+ 	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
+ 	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
+ 	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
+@@ -84,9 +85,10 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
+ 	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
+ 	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
+-	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
+ 	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
+ 	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
++	{ USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
++	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
+ 	{ }					/* Terminating entry */
+ };
+ 
+@@ -97,7 +99,10 @@ static struct usb_driver pl2303_driver = {
+ 	.probe =	usb_serial_probe,
+ 	.disconnect =	usb_serial_disconnect,
+ 	.id_table =	id_table,
++	.suspend =      usb_serial_suspend,
++	.resume =       usb_serial_resume,
+ 	.no_dynamic_id = 	1,
++	.supports_autosuspend =	1,
+ };
+ 
+ #define SET_LINE_REQUEST_TYPE		0x21
+@@ -310,12 +315,39 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ 	return count;
  }
  
--static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
-+static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
-+			       u16 mask, u16 shift)
++static int pl2303_vendor_read(__u16 value, __u16 index,
++		struct usb_serial *serial, unsigned char *buf)
 +{
-+	u16 v;
-+	u8 gain;
-+
-+	v = in[SPOFF(SSB_SPROM1_AGAIN)];
-+	gain = (v & mask) >> shift;
-+	if (gain == 0xFF)
-+		gain = 2; /* If unset use 2dBm */
-+	if (sprom_revision == 1) {
-+		/* Convert to Q5.2 */
-+		gain <<= 2;
-+	} else {
-+		/* Q5.2 Fractional part is stored in 0xC0 */
-+		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
-+	}
-+
-+	return (s8)gain;
++	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
++			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
++			value, index, buf, 1, 100);
++	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
++			VENDOR_READ_REQUEST, value, index, res, buf[0]);
++	return res;
 +}
 +
-+static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
- {
- 	int i;
- 	u16 v;
-+	s8 gain;
-+	u16 loc[3];
- 
--	SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
--	SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
--	SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
-+	if (out->revision == 3) {			/* rev 3 moved MAC */
-+		loc[0] = SSB_SPROM3_IL0MAC;
-+		loc[1] = SSB_SPROM3_ET0MAC;
-+		loc[2] = SSB_SPROM3_ET1MAC;
-+	} else {
-+		loc[0] = SSB_SPROM1_IL0MAC;
-+		loc[1] = SSB_SPROM1_ET0MAC;
-+		loc[2] = SSB_SPROM1_ET1MAC;
-+	}
- 	for (i = 0; i < 3; i++) {
--		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
-+		v = in[SPOFF(loc[0]) + i];
- 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
- 	}
- 	for (i = 0; i < 3; i++) {
--		v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
-+		v = in[SPOFF(loc[1]) + i];
- 		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
- 	}
- 	for (i = 0; i < 3; i++) {
--		v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
-+		v = in[SPOFF(loc[2]) + i];
- 		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
- 	}
- 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
-@@ -324,9 +354,9 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
- 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
- 	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
- 	     SSB_SPROM1_BINF_CCODE_SHIFT);
--	SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
-+	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
- 	     SSB_SPROM1_BINF_ANTA_SHIFT);
--	SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
-+	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
- 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
- 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
- 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
-@@ -347,100 +377,108 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
- 	     SSB_SPROM1_ITSSI_A_SHIFT);
- 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
- 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
--	SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
--	SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
--	     SSB_SPROM1_AGAIN_BG_SHIFT);
--	for (i = 0; i < 4; i++) {
--		v = in[SPOFF(SSB_SPROM1_OEM) + i];
--		*(((__le16 *)out->oem) + i) = cpu_to_le16(v);
--	}
-+	if (out->revision >= 2)
-+		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
++static int pl2303_vendor_write(__u16 value, __u16 index,
++		struct usb_serial *serial)
++{
++	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
++			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
++			value, index, NULL, 0, 100);
++	dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
++			VENDOR_WRITE_REQUEST, value, index, res);
++	return res;
++}
 +
-+	/* Extract the antenna gain values. */
-+	gain = r123_extract_antgain(out->revision, in,
-+				    SSB_SPROM1_AGAIN_BG,
-+				    SSB_SPROM1_AGAIN_BG_SHIFT);
-+	out->antenna_gain.ghz24.a0 = gain;
-+	out->antenna_gain.ghz24.a1 = gain;
-+	out->antenna_gain.ghz24.a2 = gain;
-+	out->antenna_gain.ghz24.a3 = gain;
-+	gain = r123_extract_antgain(out->revision, in,
-+				    SSB_SPROM1_AGAIN_A,
-+				    SSB_SPROM1_AGAIN_A_SHIFT);
-+	out->antenna_gain.ghz5.a0 = gain;
-+	out->antenna_gain.ghz5.a1 = gain;
-+	out->antenna_gain.ghz5.a2 = gain;
-+	out->antenna_gain.ghz5.a3 = gain;
- }
- 
--static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
-+static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
+ static int pl2303_startup(struct usb_serial *serial)
  {
+ 	struct pl2303_private *priv;
+ 	enum pl2303_type type = type_0;
++	unsigned char *buf;
  	int i;
- 	u16 v;
  
--	SPEX(boardflags_hi, SSB_SPROM2_BFLHI,  0xFFFF, 0);
--	SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
--	SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
--	     SSB_SPROM2_MAXP_A_LO_SHIFT);
--	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
--	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
--	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
--	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
--	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
--	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
--	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
--	for (i = 0; i < 4; i++) {
--		v = in[SPOFF(SSB_SPROM2_CCODE) + i];
--		*(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
-+	/* extract the equivalent of the r1 variables */
-+	for (i = 0; i < 3; i++) {
-+		v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
-+		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
- 	}
-+	for (i = 0; i < 3; i++) {
-+		v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
-+		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
-+	}
-+	for (i = 0; i < 3; i++) {
-+		v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
-+		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
-+	}
-+	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
-+	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
-+	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
-+	SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
-+	SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
-+	SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
-+	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
-+	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
-+	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
-+	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
-+	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
-+	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
-+	     SSB_SPROM4_ITSSI_BG_SHIFT);
-+	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
-+	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
-+	     SSB_SPROM4_ITSSI_A_SHIFT);
-+	SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
-+	SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
-+	     SSB_SPROM4_GPIOA_P1_SHIFT);
-+	SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
-+	SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
-+	     SSB_SPROM4_GPIOB_P3_SHIFT);
++	buf = kmalloc(10, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
 +
-+	/* Extract the antenna gain values. */
-+	SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
-+	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
-+	SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
-+	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
-+	SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
-+	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
-+	SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
-+	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
-+	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
-+	       sizeof(out->antenna_gain.ghz5));
+ 	if (serial->dev->descriptor.bDeviceClass == 0x02)
+ 		type = type_0;
+ 	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
+@@ -340,9 +372,27 @@ static int pl2303_startup(struct usb_serial *serial)
+ 		priv->type = type;
+ 		usb_set_serial_port_data(serial->port[i], priv);
+ 	}
++
++	pl2303_vendor_read(0x8484, 0, serial, buf);
++	pl2303_vendor_write(0x0404, 0, serial);
++	pl2303_vendor_read(0x8484, 0, serial, buf);
++	pl2303_vendor_read(0x8383, 0, serial, buf);
++	pl2303_vendor_read(0x8484, 0, serial, buf);
++	pl2303_vendor_write(0x0404, 1, serial);
++	pl2303_vendor_read(0x8484, 0, serial, buf);
++	pl2303_vendor_read(0x8383, 0, serial, buf);
++	pl2303_vendor_write(0, 1, serial);
++	pl2303_vendor_write(1, 0, serial);
++	if (type == HX)
++		pl2303_vendor_write(2, 0x44, serial);
++	else
++		pl2303_vendor_write(2, 0x24, serial);
 +
-+	/* TODO - get remaining rev 4 stuff needed */
- }
- 
--static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
--{
--	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
--	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
--	out->ofdmapo <<= 16;
--	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
--	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
--
--	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
--	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
--	out->ofdmalpo <<= 16;
--	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
--	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
--
--	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
--	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
--	out->ofdmahpo <<= 16;
--	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
--	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
--
--	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
--	     SSB_SPROM3_GPIOLDC_ON_SHIFT);
--	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
--	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);
--	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
--	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
--	     SSB_SPROM3_CCKPO_2M_SHIFT);
--	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
--	     SSB_SPROM3_CCKPO_55M_SHIFT);
--	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
--	     SSB_SPROM3_CCKPO_11M_SHIFT);
--
--	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
--	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
--	out->ofdmgpo <<= 16;
--	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
--	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
--}
--
--static int sprom_extract(struct ssb_bus *bus,
--			 struct ssb_sprom *out, const u16 *in)
-+static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
-+			 const u16 *in, u16 size)
- {
- 	memset(out, 0, sizeof(*out));
++	kfree(buf);
+ 	return 0;
  
--	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
--	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
--	     SSB_SPROM_REVISION_CRC_SHIFT);
--
-+	out->revision = in[size - 1] & 0x00FF;
-+	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
- 	if ((bus->chip_id & 0xFF00) == 0x4400) {
- 		/* Workaround: The BCM44XX chip has a stupid revision
- 		 * number stored in the SPROM.
- 		 * Always extract r1. */
--		sprom_extract_r1(&out->r1, in);
-+		out->revision = 1;
-+		sprom_extract_r123(out, in);
-+	} else if (bus->chip_id == 0x4321) {
-+		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
-+		out->revision = 4;
-+		sprom_extract_r4(out, in);
+ cleanup:
++	kfree(buf);
+ 	for (--i; i>=0; --i) {
+ 		priv = usb_get_serial_port_data(serial->port[i]);
+ 		pl2303_buf_free(priv->buf);
+@@ -582,24 +632,12 @@ static void pl2303_set_termios(struct usb_serial_port *port,
+ 	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+ 
+ 	if (cflag & CRTSCTS) {
+-		__u16 index;
+ 		if (priv->type == HX)
+-			index = 0x61;
++			pl2303_vendor_write(0x0, 0x61, serial);
+ 		else
+-			index = 0x41;
+-		i = usb_control_msg(serial->dev,
+-				    usb_sndctrlpipe(serial->dev, 0),
+-				    VENDOR_WRITE_REQUEST,
+-				    VENDOR_WRITE_REQUEST_TYPE,
+-				    0x0, index, NULL, 0, 100);
+-		dbg("0x40:0x1:0x0:0x%x  %d", index, i);
++			pl2303_vendor_write(0x0, 0x41, serial);
  	} else {
- 		if (out->revision == 0)
- 			goto unsupported;
--		if (out->revision >= 1 && out->revision <= 3)
--			sprom_extract_r1(&out->r1, in);
--		if (out->revision >= 2 && out->revision <= 3)
--			sprom_extract_r2(&out->r2, in);
--		if (out->revision == 3)
--			sprom_extract_r3(&out->r3, in);
--		if (out->revision >= 4)
-+		if (out->revision >= 1 && out->revision <= 3) {
-+			sprom_extract_r123(out, in);
-+		}
-+		if (out->revision == 4)
-+			sprom_extract_r4(out, in);
-+		if (out->revision >= 5)
- 			goto unsupported;
+-		i = usb_control_msg(serial->dev,
+-				    usb_sndctrlpipe(serial->dev, 0),
+-				    VENDOR_WRITE_REQUEST,
+-				    VENDOR_WRITE_REQUEST_TYPE,
+-				    0x0, 0x0, NULL, 0, 100);
+-		dbg ("0x40:0x1:0x0:0x0  %d", i);
++		pl2303_vendor_write(0x0, 0x0, serial);
  	}
  
-@@ -448,7 +486,7 @@ static int sprom_extract(struct ssb_bus *bus,
- unsupported:
- 	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
- 		   "detected. Will extract v1\n", out->revision);
--	sprom_extract_r1(&out->r1, in);
-+	sprom_extract_r123(out, in);
- 	return 0;
- }
- 
-@@ -458,16 +496,29 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
- 	int err = -ENOMEM;
- 	u16 *buf;
+ 	/* FIXME: Need to read back resulting baud rate */
+@@ -629,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
+ 		set_current_state(TASK_INTERRUPTIBLE);
+ 		if (pl2303_buf_data_avail(priv->buf) == 0 ||
+ 		    timeout == 0 || signal_pending(current) ||
+-		    !usb_get_intfdata(port->serial->interface))	/* disconnect */
++		    port->serial->disconnected)
+ 			break;
+ 		spin_unlock_irqrestore(&priv->lock, flags);
+ 		timeout = schedule_timeout(timeout);
+@@ -678,7 +716,6 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
+ 	struct ktermios tmp_termios;
+ 	struct usb_serial *serial = port->serial;
+ 	struct pl2303_private *priv = usb_get_serial_port_data(port);
+-	unsigned char *buf;
+ 	int result;
  
--	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
-+	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
- 	if (!buf)
- 		goto out;
-+	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
- 	sprom_do_read(bus, buf);
--	err = sprom_check_crc(buf);
-+	err = sprom_check_crc(buf, bus->sprom_size);
- 	if (err) {
--		ssb_printk(KERN_WARNING PFX
--			   "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
-+		/* check for rev 4 sprom - has special signature */
-+		if (buf[32] == 0x5372) {
-+			kfree(buf);
-+			buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
-+				      GFP_KERNEL);
-+			if (!buf)
-+				goto out;
-+			bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
-+			sprom_do_read(bus, buf);
-+			err = sprom_check_crc(buf, bus->sprom_size);
-+		}
-+		if (err)
-+			ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
-+				   " SPROM CRC (corrupt SPROM)\n");
+ 	dbg("%s -  port %d", __FUNCTION__, port->number);
+@@ -686,45 +723,12 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
+ 	if (priv->type != HX) {
+ 		usb_clear_halt(serial->dev, port->write_urb->pipe);
+ 		usb_clear_halt(serial->dev, port->read_urb->pipe);
+-	}
+-
+-	buf = kmalloc(10, GFP_KERNEL);
+-	if (buf==NULL)
+-		return -ENOMEM;
+-
+-#define FISH(a,b,c,d)								\
+-	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
+-			       b, a, c, d, buf, 1, 100);			\
+-	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
+-
+-#define SOUP(a,b,c,d)								\
+-	result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
+-			       b, a, c, d, NULL, 0, 100);			\
+-	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
+-
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+-	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
+-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
+-
+-	if (priv->type == HX) {
+-		/* HX chip */
+-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
+-		/* reset upstream data pipes */
+-          	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
+-        	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
+ 	} else {
+-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
++		/* reset upstream data pipes */
++		pl2303_vendor_write(8, 0, serial);
++		pl2303_vendor_write(9, 0, serial);
  	}
--	err = sprom_extract(bus, sprom, buf);
-+	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
  
- 	kfree(buf);
- out:
-@@ -581,29 +632,28 @@ const struct ssb_bus_ops ssb_pci_ops = {
- 	.write32	= ssb_pci_write32,
- };
+-	kfree(buf);
+-
+ 	/* Setup termios */
+ 	if (port->tty) {
+ 		pl2303_set_termios(port, &tmp_termios);
+diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
+index d31f5d2..237a41f 100644
+--- a/drivers/usb/serial/pl2303.h
++++ b/drivers/usb/serial/pl2303.h
+@@ -35,6 +35,7 @@
  
--static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
-+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
- {
- 	int i, pos = 0;
+ #define RATOC_VENDOR_ID		0x0584
+ #define RATOC_PRODUCT_ID	0xb000
++#define RATOC_PRODUCT_ID_USB60F	0xb020
+ 
+ #define TRIPP_VENDOR_ID		0x2478
+ #define TRIPP_PRODUCT_ID	0x2008
+@@ -96,10 +97,6 @@
+ #define ALCOR_VENDOR_ID		0x058F
+ #define ALCOR_PRODUCT_ID	0x9720
+ 
+-/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
+-#define HUAWEI_VENDOR_ID	0x12d1
+-#define HUAWEI_PRODUCT_ID	0x1001
+-
+ /* Willcom WS002IN Data Driver (by NetIndex Inc.) */
+ #define WS002IN_VENDOR_ID	0x11f6
+ #define WS002IN_PRODUCT_ID	0x2001
+@@ -107,3 +104,11 @@
+ /* Corega CG-USBRS232R Serial Adapter */
+ #define COREGA_VENDOR_ID	0x07aa
+ #define COREGA_PRODUCT_ID	0x002a
++
++/* HL HL-340 (ID: 4348:5523) */
++#define HL340_VENDOR_ID		0x4348
++#define HL340_PRODUCT_ID	0x5523
++
++/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
++#define YCCABLE_VENDOR_ID	0x05ad
++#define YCCABLE_PRODUCT_ID	0x0fba
+diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
+index c295d04..4c925e3 100644
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -1,7 +1,7 @@
+ /*
+   USB Driver for Sierra Wireless
  
--	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
-+	for (i = 0; i < size; i++)
- 		pos += snprintf(buf + pos, buf_len - pos - 1,
- 				"%04X", swab16(sprom[i]) & 0xFFFF);
--	}
- 	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+-  Copyright (C) 2006, 2007  Kevin Lloyd <linux at sierrawireless.com>
++  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <linux at sierrawireless.com>
  
- 	return pos + 1;
- }
+   IMPORTANT DISCLAIMER: This driver is not commercially supported by
+   Sierra Wireless. Use at your own risk.
+@@ -14,7 +14,7 @@
+   Whom based his on the Keyspan driver by Hugh Blemings <hugh at blemings.org>
+ */
  
--static int hex2sprom(u16 *sprom, const char *dump, size_t len)
-+static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
- {
- 	char tmp[5] = { 0 };
- 	int cnt = 0;
- 	unsigned long parsed;
+-#define DRIVER_VERSION "v.1.2.5b"
++#define DRIVER_VERSION "v.1.2.7"
+ #define DRIVER_AUTHOR "Kevin Lloyd <linux at sierrawireless.com>"
+ #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
  
--	if (len < SSB_SPROMSIZE_BYTES * 2)
-+	if (len < size * 2)
- 		return -EINVAL;
+@@ -26,10 +26,12 @@
+ #include <linux/module.h>
+ #include <linux/usb.h>
+ #include <linux/usb/serial.h>
++#include <linux/usb/ch9.h>
  
--	while (cnt < SSB_SPROMSIZE_WORDS) {
-+	while (cnt < size) {
- 		memcpy(tmp, dump, 4);
- 		dump += 4;
- 		parsed = simple_strtoul(tmp, NULL, 16);
-@@ -627,7 +677,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
- 	if (!bus)
- 		goto out;
- 	err = -ENOMEM;
--	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
-+	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
- 	if (!sprom)
- 		goto out;
++#define SWIMS_USB_REQUEST_SetPower	0x00
++#define SWIMS_USB_REQUEST_SetNmea	0x07
+ #define SWIMS_USB_REQUEST_SetMode	0x0B
+-#define SWIMS_USB_REQUEST_TYPE_SetMode	0x40
+-#define SWIMS_USB_INDEX_SetMode		0x0000
++#define SWIMS_USB_REQUEST_TYPE_VSC_SET	0x40
+ #define SWIMS_SET_MODE_Modem		0x0001
+ 
+ /* per port private data */
+@@ -38,6 +40,8 @@
+ #define IN_BUFLEN	4096
  
-@@ -640,7 +690,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
- 	sprom_do_read(bus, sprom);
- 	mutex_unlock(&bus->pci_sprom_mutex);
+ static int debug;
++static int nmea;
++static int truinstall = 1;
  
--	count = sprom2hex(sprom, buf, PAGE_SIZE);
-+	count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
- 	err = 0;
+ enum devicetype {
+ 	DEVICE_3_PORT =		0,
+@@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+ 	int result;
+ 	dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
+ 	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+-			0x00,			/* __u8 request      */
+-			0x40,			/* __u8 request type */
+-			swiState,		/* __u16 value       */
+-			0,			/* __u16 index       */
+-			NULL,			/* void *data        */
+-			0,			/* __u16 size 	     */
+-			USB_CTRL_SET_TIMEOUT);	/* int timeout 	     */
++			SWIMS_USB_REQUEST_SetPower,	/* __u8 request      */
++			SWIMS_USB_REQUEST_TYPE_VSC_SET,	/* __u8 request type */
++			swiState,			/* __u16 value       */
++			0,				/* __u16 index       */
++			NULL,				/* void *data        */
++			0,				/* __u16 size 	     */
++			USB_CTRL_SET_TIMEOUT);		/* int timeout 	     */
+ 	return result;
+ }
  
- out_kfree:
-@@ -662,15 +712,15 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
- 	if (!bus)
- 		goto out;
- 	err = -ENOMEM;
--	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
-+	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
- 	if (!sprom)
- 		goto out;
--	err = hex2sprom(sprom, buf, count);
-+	err = hex2sprom(sprom, buf, count, bus->sprom_size);
- 	if (err) {
- 		err = -EINVAL;
- 		goto out_kfree;
- 	}
--	err = sprom_check_crc(sprom);
-+	err = sprom_check_crc(sprom, bus->sprom_size);
- 	if (err) {
- 		err = -EINVAL;
- 		goto out_kfree;
-diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
-index bb44a76..46816cd 100644
---- a/drivers/ssb/pcmcia.c
-+++ b/drivers/ssb/pcmcia.c
-@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- 			   struct ssb_device *dev)
+-static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
++static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
  {
- 	int err;
--	unsigned long flags;
- 
- #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
- 	ssb_printk(KERN_INFO PFX
-@@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- 		   dev->core_index);
- #endif
- 
--	spin_lock_irqsave(&bus->bar_lock, flags);
- 	err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
- 	if (!err)
- 		bus->mapped_device = dev;
--	spin_unlock_irqrestore(&bus->bar_lock, flags);
- 
- 	return err;
+ 	int result;
+ 	dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
+ 	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 			SWIMS_USB_REQUEST_SetMode,	/* __u8 request      */
+-			SWIMS_USB_REQUEST_TYPE_SetMode,	/* __u8 request type */
+-			eSocMode,			/* __u16 value       */
+-			SWIMS_USB_INDEX_SetMode,	/* __u16 index       */
++			SWIMS_USB_REQUEST_TYPE_VSC_SET,	/* __u8 request type */
++			eSWocMode,			/* __u16 value       */
++			0x0000,				/* __u16 index       */
+ 			NULL,				/* void *data        */
+ 			0,				/* __u16 size 	     */
+ 			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
+ 	return result;
  }
-@@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
- int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
- {
- 	int attempts = 0;
--	unsigned long flags;
- 	conf_reg_t reg;
--	int res, err = 0;
-+	int res;
  
- 	SSB_WARN_ON((seg != 0) && (seg != 1));
- 	reg.Offset = 0x34;
- 	reg.Function = 0;
--	spin_lock_irqsave(&bus->bar_lock, flags);
- 	while (1) {
- 		reg.Action = CS_WRITE;
- 		reg.Value = seg;
-@@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
- 		udelay(10);
- 	}
- 	bus->mapped_pcmcia_seg = seg;
--out_unlock:
--	spin_unlock_irqrestore(&bus->bar_lock, flags);
--	return err;
+-static int sierra_probe(struct usb_interface *iface,
+-			const struct usb_device_id *id)
++static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
++{
++	int result;
++	dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
++	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
++			SWIMS_USB_REQUEST_SetNmea,	/* __u8 request      */
++			SWIMS_USB_REQUEST_TYPE_VSC_SET,	/* __u8 request type */
++			enable,				/* __u16 value       */
++			0x0000,				/* __u16 index       */
++			NULL,				/* void *data        */
++			0,				/* __u16 size 	     */
++			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
++	return result;
++}
 +
-+	return 0;
- error:
- 	ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
--	err = -ENODEV;
--	goto out_unlock;
-+	return -ENODEV;
- }
- 
- static int select_core_and_segment(struct ssb_device *dev,
-@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev,
- static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
++static int sierra_calc_num_ports(struct usb_serial *serial)
  {
- 	struct ssb_bus *bus = dev->bus;
-+	unsigned long flags;
-+	int err;
-+	u16 value = 0xFFFF;
+ 	int result;
++	int *num_ports = usb_get_serial_data(serial);
++
++	result = *num_ports;
++
++	if (result) {
++		kfree(num_ports);
++		usb_set_serial_data(serial, NULL);
++	}
++
++	return result;
++}
++
++static int sierra_probe(struct usb_serial *serial,
++			const struct usb_device_id *id)
++{
++	int result = 0;
+ 	struct usb_device *udev;
++	int *num_ports;
++	u8 ifnum;
++
++	num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
++	if (!num_ports)
++		return -ENOMEM;
  
--	if (unlikely(select_core_and_segment(dev, &offset)))
--		return 0xFFFF;
-+	spin_lock_irqsave(&bus->bar_lock, flags);
-+	err = select_core_and_segment(dev, &offset);
-+	if (likely(!err))
-+		value = readw(bus->mmio + offset);
-+	spin_unlock_irqrestore(&bus->bar_lock, flags);
+-	udev = usb_get_dev(interface_to_usbdev(iface));
++	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
++	udev = serial->dev;
+ 
+ 	/* Check if in installer mode */
+-	if (id->driver_info == DEVICE_INSTALLER) {
+-		dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
++	if (truinstall && id->driver_info == DEVICE_INSTALLER) {
++		dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
+ 		result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+-		/*We do not want to bind to the device when in installer mode*/
++		/* Don't bind to the device when in installer mode */
++		kfree(num_ports);
+ 		return -EIO;
+-	}
++	} else if (id->driver_info == DEVICE_1_PORT)
++		*num_ports = 1;
++	else if (ifnum == 0x99)
++		*num_ports = 0;
++	else
++		*num_ports = 3;
++	/*
++	 * save off our num_ports info so that we can use it in the
++	 * calc_num_ports callback
++	 */
++	usb_set_serial_data(serial, (void *)num_ports);
  
--	return readw(bus->mmio + offset);
-+	return value;
+-	return usb_serial_probe(iface, id);
++	return result;
  }
  
- static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
- {
- 	struct ssb_bus *bus = dev->bus;
--	u32 lo, hi;
-+	unsigned long flags;
-+	int err;
-+	u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
- 
--	if (unlikely(select_core_and_segment(dev, &offset)))
--		return 0xFFFFFFFF;
--	lo = readw(bus->mmio + offset);
--	hi = readw(bus->mmio + offset + 2);
-+	spin_lock_irqsave(&bus->bar_lock, flags);
-+	err = select_core_and_segment(dev, &offset);
-+	if (likely(!err)) {
-+		lo = readw(bus->mmio + offset);
-+		hi = readw(bus->mmio + offset + 2);
-+	}
-+	spin_unlock_irqrestore(&bus->bar_lock, flags);
+ static struct usb_device_id id_table [] = {
+@@ -104,6 +156,7 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+ 	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+ 	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U */
++	{ USB_DEVICE(0x1199, 0x0023) },	/* Sierra Wireless AirCard */
+ 
+ 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+ 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
+@@ -117,56 +170,29 @@ static struct usb_device_id id_table [] = {
+ 	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+ 	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880 E */
+ 	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881 E */
++	{ USB_DEVICE(0x1199, 0x6855) },	/* Sierra Wireless AirCard 880 U */
++	{ USB_DEVICE(0x1199, 0x6856) },	/* Sierra Wireless AirCard 881 U */
++
++	{ USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
++	{ USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */
+ 
+ 	{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+ 	{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
++	{ USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */
  
- 	return (lo | (hi << 16));
- }
-@@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
- static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
- {
- 	struct ssb_bus *bus = dev->bus;
-+	unsigned long flags;
-+	int err;
+ 	{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
+ 	{ }
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
  
--	if (unlikely(select_core_and_segment(dev, &offset)))
--		return;
--	writew(value, bus->mmio + offset);
-+	spin_lock_irqsave(&bus->bar_lock, flags);
-+	err = select_core_and_segment(dev, &offset);
-+	if (likely(!err))
-+		writew(value, bus->mmio + offset);
-+	mmiowb();
-+	spin_unlock_irqrestore(&bus->bar_lock, flags);
- }
+-static struct usb_device_id id_table_1port [] = {
+-	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+-	{ USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+-	{ }
+-};
+-
+-static struct usb_device_id id_table_3port [] = {
+-	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
+-	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
+-	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
+-	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+-	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
+-	{ USB_DEVICE(0x1199, 0x0220) },	/* Sierra Wireless MC5725 */
+-	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+-	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+-	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U*/
+-
+-	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+-	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
+-	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
+-	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
+-	{ USB_DEVICE(0x1199, 0x6813) },	/* Sierra Wireless MC8775 (Thinkpad internal) */
+-	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
+-	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
+-	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
+-	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
+-	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+-	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880E */
+-	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881E */
+-	{ }
+-};
+-
+ static struct usb_driver sierra_driver = {
+ 	.name       = "sierra",
+-	.probe      = sierra_probe,
++	.probe      = usb_serial_probe,
+ 	.disconnect = usb_serial_disconnect,
+ 	.id_table   = id_table,
+ 	.no_dynamic_id = 	1,
+ };
  
- static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
+-
+ struct sierra_port_private {
+ 	spinlock_t lock;	/* lock the structure */
+ 	int outstanding_urbs;	/* number of out urbs in flight */
+@@ -188,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
  {
- 	struct ssb_bus *bus = dev->bus;
-+	unsigned long flags;
-+	int err;
+ 	struct usb_serial *serial = port->serial;
+ 	struct sierra_port_private *portdata;
++	__u16 interface = 0;
  
--	if (unlikely(select_core_and_segment(dev, &offset)))
--		return;
--	writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
--	writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
--	writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
--	writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
-+	spin_lock_irqsave(&bus->bar_lock, flags);
-+	err = select_core_and_segment(dev, &offset);
-+	if (likely(!err)) {
-+		writew((value & 0x0000FFFF), bus->mmio + offset);
-+		writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
-+	}
-+	mmiowb();
-+	spin_unlock_irqrestore(&bus->bar_lock, flags);
- }
+ 	dbg("%s", __FUNCTION__);
  
- /* Not "static", as it's used in main.c */
-@@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = {
- 	.write32	= ssb_pcmcia_write32,
- };
+@@ -200,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port)
+ 		if (portdata->rts_state)
+ 			val |= 0x02;
+ 
++		/* Determine which port is targeted */
++		if (port->bulk_out_endpointAddress == 2)
++			interface = 0;
++		else if (port->bulk_out_endpointAddress == 4)
++			interface = 1;
++		else if (port->bulk_out_endpointAddress == 5)
++			interface = 2;
++
+ 		return usb_control_msg(serial->dev,
+ 				usb_rcvctrlpipe(serial->dev, 0),
+-				0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
++				0x22, 0x21, val, interface,
++				NULL, 0, USB_CTRL_SET_TIMEOUT);
+ 	}
  
-+#include <linux/etherdevice.h>
- int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
- 			      struct ssb_init_invariants *iv)
- {
- 	//TODO
-+	random_ether_addr(iv->sprom.il0mac);
  	return 0;
- }
+@@ -561,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
+ 	portdata->dtr_state = 0;
  
-diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
-index 865f32b..cc246fa 100644
---- a/drivers/uio/uio.c
-+++ b/drivers/uio/uio.c
-@@ -34,12 +34,12 @@ struct uio_device {
- 	wait_queue_head_t	wait;
- 	int			vma_count;
- 	struct uio_info		*info;
--	struct kset 		map_attr_kset;
-+	struct kobject		*map_dir;
- };
+ 	if (serial->dev) {
+-		sierra_send_setup(port);
++		mutex_lock(&serial->disc_mutex);
++		if (!serial->disconnected)
++			sierra_send_setup(port);
++		mutex_unlock(&serial->disc_mutex);
  
- static int uio_major;
- static DEFINE_IDR(uio_idr);
--static struct file_operations uio_fops;
-+static const struct file_operations uio_fops;
+ 		/* Stop reading/writing urbs */
+ 		for (i = 0; i < N_IN_URB; i++)
+@@ -583,9 +622,13 @@ static int sierra_startup(struct usb_serial *serial)
  
- /* UIO class infrastructure */
- static struct uio_class {
-@@ -51,47 +51,48 @@ static struct uio_class {
-  * attributes
-  */
+ 	dbg("%s", __FUNCTION__);
  
--static struct attribute attr_addr = {
--	.name  = "addr",
--	.mode  = S_IRUGO,
-+struct uio_map {
-+	struct kobject kobj;
-+	struct uio_mem *mem;
- };
-+#define to_map(map) container_of(map, struct uio_map, kobj)
+-	/*Set Device mode to D0 */
++	/* Set Device mode to D0 */
+ 	sierra_set_power_state(serial->dev, 0x0000);
  
--static struct attribute attr_size = {
--	.name  = "size",
--	.mode  = S_IRUGO,
--};
++	/* Check NMEA and set */
++	if (nmea)
++		sierra_vsc_set_nmea(serial->dev, 1);
++
+ 	/* Now setup per port private data */
+ 	for (i = 0; i < serial->num_ports; i++) {
+ 		port = serial->port[i];
+@@ -646,47 +689,19 @@ static void sierra_shutdown(struct usb_serial *serial)
+ 	}
+ }
  
--static struct attribute* map_attrs[] = {
--	&attr_addr, &attr_size, NULL
+-static struct usb_serial_driver sierra_1port_device = {
++static struct usb_serial_driver sierra_device = {
+ 	.driver = {
+ 		.owner =	THIS_MODULE,
+ 		.name =		"sierra1",
+ 	},
+-	.description       = "Sierra USB modem (1 port)",
+-	.id_table          = id_table_1port,
+-	.usb_driver        = &sierra_driver,
+-	.num_interrupt_in  = NUM_DONT_CARE,
+-	.num_bulk_in       = 1,
+-	.num_bulk_out      = 1,
+-	.num_ports         = 1,
+-	.open              = sierra_open,
+-	.close             = sierra_close,
+-	.write             = sierra_write,
+-	.write_room        = sierra_write_room,
+-	.chars_in_buffer   = sierra_chars_in_buffer,
+-	.throttle          = sierra_rx_throttle,
+-	.unthrottle        = sierra_rx_unthrottle,
+-	.ioctl             = sierra_ioctl,
+-	.set_termios       = sierra_set_termios,
+-	.break_ctl         = sierra_break_ctl,
+-	.tiocmget          = sierra_tiocmget,
+-	.tiocmset          = sierra_tiocmset,
+-	.attach            = sierra_startup,
+-	.shutdown          = sierra_shutdown,
+-	.read_int_callback = sierra_instat_callback,
 -};
 -
--static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
-+static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
- 			     char *buf)
+-static struct usb_serial_driver sierra_3port_device = {
+-	.driver = {
+-		.owner =	THIS_MODULE,
+-		.name =		"sierra3",
+-	},
+-	.description       = "Sierra USB modem (3 port)",
+-	.id_table          = id_table_3port,
++	.description       = "Sierra USB modem",
++	.id_table          = id_table,
+ 	.usb_driver        = &sierra_driver,
+ 	.num_interrupt_in  = NUM_DONT_CARE,
+-	.num_bulk_in       = 3,
+-	.num_bulk_out      = 3,
+-	.num_ports         = 3,
++	.num_bulk_in       = NUM_DONT_CARE,
++	.num_bulk_out      = NUM_DONT_CARE,
++	.calc_num_ports	   = sierra_calc_num_ports,
++	.probe		   = sierra_probe,
+ 	.open              = sierra_open,
+ 	.close             = sierra_close,
+ 	.write             = sierra_write,
+@@ -708,12 +723,9 @@ static struct usb_serial_driver sierra_3port_device = {
+ static int __init sierra_init(void)
  {
--	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
-+	struct uio_map *map = to_map(kobj);
-+	struct uio_mem *mem = map->mem;
+ 	int retval;
+-	retval = usb_serial_register(&sierra_1port_device);
+-	if (retval)
+-		goto failed_1port_device_register;
+-	retval = usb_serial_register(&sierra_3port_device);
++	retval = usb_serial_register(&sierra_device);
+ 	if (retval)
+-		goto failed_3port_device_register;
++		goto failed_device_register;
  
--	if (strncmp(attr->name,"addr",4) == 0)
-+	if (strncmp(attr->attr.name, "addr", 4) == 0)
- 		return sprintf(buf, "0x%lx\n", mem->addr);
  
--	if (strncmp(attr->name,"size",4) == 0)
-+	if (strncmp(attr->attr.name, "size", 4) == 0)
- 		return sprintf(buf, "0x%lx\n", mem->size);
+ 	retval = usb_register(&sierra_driver);
+@@ -725,18 +737,15 @@ static int __init sierra_init(void)
+ 	return 0;
  
- 	return -ENODEV;
+ failed_driver_register:
+-	usb_serial_deregister(&sierra_3port_device);
+-failed_3port_device_register:
+-	usb_serial_deregister(&sierra_1port_device);
+-failed_1port_device_register:
++	usb_serial_deregister(&sierra_device);
++failed_device_register:
+ 	return retval;
  }
  
--static void map_attr_release(struct kobject *kobj)
--{
--	/* TODO ??? */
--}
-+static struct kobj_attribute attr_attribute =
-+	__ATTR(addr, S_IRUGO, map_attr_show, NULL);
-+static struct kobj_attribute size_attribute =
-+	__ATTR(size, S_IRUGO, map_attr_show, NULL);
+ static void __exit sierra_exit(void)
+ {
+ 	usb_deregister (&sierra_driver);
+-	usb_serial_deregister(&sierra_1port_device);
+-	usb_serial_deregister(&sierra_3port_device);
++	usb_serial_deregister(&sierra_device);
+ }
  
--static struct sysfs_ops map_attr_ops = {
--	.show  = map_attr_show,
-+static struct attribute *attrs[] = {
-+	&attr_attribute.attr,
-+	&size_attribute.attr,
-+	NULL,	/* need to NULL terminate the list of attributes */
- };
+ module_init(sierra_init);
+@@ -747,6 +756,12 @@ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_VERSION(DRIVER_VERSION);
+ MODULE_LICENSE("GPL");
  
-+static void map_release(struct kobject *kobj)
-+{
-+	struct uio_map *map = to_map(kobj);
-+	kfree(map);
-+}
++module_param(truinstall, bool, 0);
++MODULE_PARM_DESC(truinstall, "TRU-Install support");
 +
- static struct kobj_type map_attr_type = {
--	.release	= map_attr_release,
--	.sysfs_ops	= &map_attr_ops,
--	.default_attrs	= map_attrs,
-+	.release	= map_release,
-+	.default_attrs	= attrs,
++module_param(nmea, bool, 0);
++MODULE_PARM_DESC(nmea, "NMEA streaming");
++
+ #ifdef CONFIG_USB_DEBUG
+ module_param(debug, bool, S_IRUGO | S_IWUSR);
+ MODULE_PARM_DESC(debug, "Debug messages");
+diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
+index 1f01494..b517f93 100644
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -80,6 +80,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/serial.h>
+ #include <linux/circ_buf.h>
++#include <linux/mutex.h>
+ #include <asm/uaccess.h>
+ #include <asm/semaphore.h>
+ #include <linux/usb.h>
+@@ -139,7 +140,7 @@ struct ti_port {
  };
  
- static ssize_t show_name(struct device *dev,
-@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
- 	int mi;
- 	int map_found = 0;
- 	struct uio_mem *mem;
-+	struct uio_map *map;
+ struct ti_device {
+-	struct semaphore	td_open_close_sem;
++	struct mutex		td_open_close_lock;
+ 	int			td_open_port_count;
+ 	struct usb_serial	*td_serial;
+ 	int			td_is_3410;
+@@ -424,7 +425,7 @@ static int ti_startup(struct usb_serial *serial)
+ 		dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
+ 		return -ENOMEM;
+ 	}
+-	sema_init(&tdev->td_open_close_sem, 1);
++	mutex_init(&tdev->td_open_close_lock);
+ 	tdev->td_serial = serial;
+ 	usb_set_serial_data(serial, tdev);
+ 
+@@ -547,7 +548,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
+ 	tdev = tport->tp_tdev;
+ 
+ 	/* only one open on any port on a device at a time */
+-	if (down_interruptible(&tdev->td_open_close_sem))
++	if (mutex_lock_interruptible(&tdev->td_open_close_lock))
+ 		return -ERESTARTSYS;
  
- 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
- 	if (ret)
-@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
- 			break;
- 		if (!map_found) {
- 			map_found = 1;
--			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
--			idev->map_attr_kset.ktype = &map_attr_type;
--			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
--			ret = kset_register(&idev->map_attr_kset);
--			if (ret)
--				goto err_remove_group;
-+			idev->map_dir = kobject_create_and_add("maps",
-+							&idev->dev->kobj);
-+			if (!idev->map_dir)
-+				goto err;
+ 	if (port->tty)
+@@ -568,7 +569,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
+ 		if (!urb) {
+ 			dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__);
+ 			status = -EINVAL;
+-			goto up_sem;
++			goto release_lock;
+ 		}
+ 		urb->complete = ti_interrupt_callback;
+ 		urb->context = tdev;
+@@ -576,11 +577,11 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
+ 		status = usb_submit_urb(urb, GFP_KERNEL);
+ 		if (status) {
+ 			dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status);
+-			goto up_sem;
++			goto release_lock;
  		}
--		kobject_init(&mem->kobj);
--		kobject_set_name(&mem->kobj,"map%d",mi);
--		mem->kobj.parent = &idev->map_attr_kset.kobj;
--		mem->kobj.kset = &idev->map_attr_kset;
--		ret = kobject_add(&mem->kobj);
-+		map = kzalloc(sizeof(*map), GFP_KERNEL);
-+		if (!map)
-+			goto err;
-+		kobject_init(&map->kobj, &map_attr_type);
-+		map->mem = mem;
-+		mem->map = map;
-+		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
-+		if (ret)
-+			goto err;
-+		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
- 		if (ret)
--			goto err_remove_maps;
-+			goto err;
  	}
  
- 	return 0;
- 
--err_remove_maps:
-+err:
- 	for (mi--; mi>=0; mi--) {
- 		mem = &idev->info->mem[mi];
--		kobject_unregister(&mem->kobj);
-+		map = mem->map;
-+		kobject_put(&map->kobj);
- 	}
--	kset_unregister(&idev->map_attr_kset); /* Needed ? */
--err_remove_group:
-+	kobject_put(idev->map_dir);
- 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
- err_group:
- 	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
-@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
- 		mem = &idev->info->mem[mi];
- 		if (mem->size == 0)
- 			break;
--		kobject_unregister(&mem->kobj);
-+		kobject_put(&mem->map->kobj);
- 	}
--	kset_unregister(&idev->map_attr_kset);
-+	kobject_put(idev->map_dir);
- 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+-	ti_set_termios(port, NULL);
++	ti_set_termios(port, port->tty->termios);
+ 
+ 	dbg("%s - sending TI_OPEN_PORT", __FUNCTION__);
+ 	status = ti_command_out_sync(tdev, TI_OPEN_PORT,
+@@ -617,7 +618,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
+ 	usb_clear_halt(dev, port->write_urb->pipe);
+ 	usb_clear_halt(dev, port->read_urb->pipe);
+ 
+-	ti_set_termios(port, NULL);
++	ti_set_termios(port, port->tty->termios);
+ 
+ 	dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__);
+ 	status = ti_command_out_sync(tdev, TI_OPEN_PORT,
+@@ -656,13 +657,13 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
+ 	tport->tp_is_open = 1;
+ 	++tdev->td_open_port_count;
+ 
+-	goto up_sem;
++	goto release_lock;
+ 
+ unlink_int_urb:
+ 	if (tdev->td_open_port_count == 0)
+ 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+-up_sem:
+-	up(&tdev->td_open_close_sem);
++release_lock:
++	mutex_unlock(&tdev->td_open_close_lock);
+ 	dbg("%s - exit %d", __FUNCTION__, status);
+ 	return status;
  }
+@@ -674,7 +675,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
+ 	struct ti_port *tport;
+ 	int port_number;
+ 	int status;
+-	int do_up;
++	int do_unlock;
  
-@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
- 	}
- }
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 			 
+@@ -699,16 +700,16 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
+ 	if (status)
+ 		dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status);
  
--static struct file_operations uio_fops = {
-+static const struct file_operations uio_fops = {
- 	.owner		= THIS_MODULE,
- 	.open		= uio_open,
- 	.release	= uio_release,
-diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
-index 7580aa5..7a64990 100644
---- a/drivers/usb/Kconfig
-+++ b/drivers/usb/Kconfig
-@@ -33,6 +33,7 @@ config USB_ARCH_HAS_OHCI
- 	default y if ARCH_LH7A404
- 	default y if ARCH_S3C2410
- 	default y if PXA27x
-+	default y if PXA3xx
- 	default y if ARCH_EP93XX
- 	default y if ARCH_AT91
- 	default y if ARCH_PNX4008
-diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
-index c51f8e9..7c3aaa9 100644
---- a/drivers/usb/core/driver.c
-+++ b/drivers/usb/core/driver.c
-@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
- 		goto exit;
+-	/* if down is interrupted, continue anyway */
+-	do_up = !down_interruptible(&tdev->td_open_close_sem);
++	/* if mutex_lock is interrupted, continue anyway */
++	do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
+ 	--tport->tp_tdev->td_open_port_count;
+ 	if (tport->tp_tdev->td_open_port_count <= 0) {
+ 		/* last port is closed, shut down interrupt urb */
+ 		usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
+ 		tport->tp_tdev->td_open_port_count = 0;
+ 	}
+-	if (do_up)
+-		up(&tdev->td_open_close_sem);
++	if (do_unlock)
++		mutex_unlock(&tdev->td_open_close_lock);
  
- 	if (usb_drv->probe != NULL)
--		error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
--					  &driver_attr_new_id.attr);
-+		error = driver_create_file(&usb_drv->drvwrap.driver,
-+					   &driver_attr_new_id);
- exit:
- 	return error;
+ 	dbg("%s - exit", __FUNCTION__);
  }
-@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
- 		return;
+@@ -896,24 +897,11 @@ static void ti_set_termios(struct usb_serial_port *port,
  
- 	if (usb_drv->probe != NULL)
--		sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
--				  &driver_attr_new_id.attr);
-+		driver_remove_file(&usb_drv->drvwrap.driver,
-+				   &driver_attr_new_id);
- }
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
  
- static void usb_free_dynids(struct usb_driver *usb_drv)
-diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
-index f81d08d..77a3759 100644
---- a/drivers/usb/gadget/Kconfig
-+++ b/drivers/usb/gadget/Kconfig
-@@ -308,7 +308,7 @@ config USB_S3C2410_DEBUG
+-	if (!tty || !tty->termios) {
+-		dbg("%s - no tty or termios", __FUNCTION__);
+-		return;
+-	}
+-
+ 	cflag = tty->termios->c_cflag;
+ 	iflag = tty->termios->c_iflag;
  
- config USB_GADGET_AT91
- 	boolean "AT91 USB Device Port"
--	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
-+	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
- 	select USB_GADGET_SELECTED
- 	help
- 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
-diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
-index 0689189..7da7fcb 100644
---- a/drivers/usb/gadget/gmidi.c
-+++ b/drivers/usb/gadget/gmidi.c
-@@ -24,7 +24,6 @@
- #include <linux/utsname.h>
- #include <linux/device.h>
+-	if (old_termios && cflag == old_termios->c_cflag
+-	&& iflag == old_termios->c_iflag) {
+-		dbg("%s - nothing to change", __FUNCTION__);
+-		return;
+-	}
+-
+-	dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
+-
+-	if (old_termios)
+-		dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
++	dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
++	dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
  
--#include <sound/driver.h>
- #include <sound/core.h>
- #include <sound/initval.h>
- #include <sound/rawmidi.h>
-diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
-index ecfe800..ddd4ee1 100644
---- a/drivers/usb/host/ohci-hcd.c
-+++ b/drivers/usb/host/ohci-hcd.c
-@@ -997,7 +997,7 @@ MODULE_LICENSE ("GPL");
- #define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
- #endif
+ 	if (tport == NULL)
+ 		return;
+@@ -947,6 +935,9 @@ static void ti_set_termios(struct usb_serial_port *port,
+ 			    break;
+ 	}
  
--#ifdef CONFIG_PXA27x
-+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
- #include "ohci-pxa27x.c"
- #define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
- #endif
-diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
-index 5cfa3d1..74e1f4b 100644
---- a/drivers/usb/host/ohci-omap.c
-+++ b/drivers/usb/host/ohci-omap.c
-@@ -47,7 +47,7 @@
- #endif
++	/* CMSPAR isn't supported by this driver */
++	tty->termios->c_cflag &= ~CMSPAR;
++
+ 	if (cflag & PARENB) {
+ 		if (cflag & PARODD) {
+ 			config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING;
+@@ -989,12 +980,17 @@ static void ti_set_termios(struct usb_serial_port *port,
+ 	}
  
- #ifdef CONFIG_TPS65010
--#include <asm/arch/tps65010.h>
-+#include <linux/i2c/tps65010.h>
- #else
+ 	baud = tty_get_baud_rate(tty);
+-	if (!baud) baud = 9600;
++	if (!baud)
++		baud = 9600;
+ 	if (tport->tp_tdev->td_is_3410)
+ 		config->wBaudRate = (__u16)((923077 + baud/2) / baud);
+ 	else
+ 		config->wBaudRate = (__u16)((461538 + baud/2) / baud);
  
- #define LOW	0
-diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
-index ca2a6ab..6c52c66 100644
---- a/drivers/usb/host/ohci-pnx4008.c
-+++ b/drivers/usb/host/ohci-pnx4008.c
-@@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client);
- static int isp1301_command(struct i2c_client *client, unsigned int cmd,
- 			   void *arg);
++	/* FIXME: Should calculate resulting baud here and report it back */
++	if ((cflag & CBAUD) != B0)
++		tty_encode_baud_rate(tty, baud, baud);
++
+ 	dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
+ 	__FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
+ 
+@@ -1497,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
+ 	struct ti_device *tdev = tport->tp_tdev;
+ 	struct usb_serial_port *port = tport->tp_port;
+ 	wait_queue_t wait;
+-	unsigned long flags;
  
--static unsigned short normal_i2c[] =
-+static const unsigned short normal_i2c[] =
-     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
--static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
-+static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
  
- static struct i2c_client_address_data addr_data = {
- 	.normal_i2c = normal_i2c,
-@@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = {
- };
+-	spin_lock_irqsave(&tport->tp_lock, flags);
++	spin_lock_irq(&tport->tp_lock);
  
- struct i2c_driver isp1301_driver = {
--	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
- 	.class = I2C_CLASS_HWMON,
- 	.attach_adapter = isp1301_probe,
- 	.detach_client = isp1301_detach,
-diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
-index 0c3e6b7..a672527 100644
---- a/drivers/usb/host/ohci-ppc-of.c
-+++ b/drivers/usb/host/ohci-ppc-of.c
-@@ -136,6 +136,8 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
- 	ohci = hcd_to_ohci(hcd);
- 	if (is_bigendian) {
- 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
-+		if (of_device_is_compatible(dn, "fsl,mpc5200-ohci"))
-+			ohci->flags |= OHCI_QUIRK_FRAME_NO;
- 		if (of_device_is_compatible(dn, "mpc5200-ohci"))
- 			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ 	/* wait for data to drain from the buffer */
+ 	tdev->td_urb_error = 0;
+@@ -1512,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
+ 		if (ti_buf_data_avail(tport->tp_write_buf) == 0
+ 		|| timeout == 0 || signal_pending(current)
+ 		|| tdev->td_urb_error
+-		|| !usb_get_intfdata(port->serial->interface))  /* disconnect */
++		|| port->serial->disconnected)  /* disconnect */
+ 			break;
+-		spin_unlock_irqrestore(&tport->tp_lock, flags);
++		spin_unlock_irq(&tport->tp_lock);
+ 		timeout = schedule_timeout(timeout);
+-		spin_lock_irqsave(&tport->tp_lock, flags);
++		spin_lock_irq(&tport->tp_lock);
+ 	}
+ 	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&tport->tp_write_wait, &wait);
+@@ -1525,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
+ 	if (flush)
+ 		ti_buf_clear(tport->tp_write_buf);
+ 
+-	spin_unlock_irqrestore(&tport->tp_lock, flags);
++	spin_unlock_irq(&tport->tp_lock);
+ 
++	mutex_lock(&port->serial->disc_mutex);
+ 	/* wait for data to drain from the device */
+ 	/* wait for empty tx register, plus 20 ms */
+ 	timeout += jiffies;
+ 	tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
+ 	while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
+ 	&& !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
+-	&& usb_get_intfdata(port->serial->interface)) {  /* not disconnected */
++	&& !port->serial->disconnected) {
+ 		if (ti_get_lsr(tport))
+ 			break;
++		mutex_unlock(&port->serial->disc_mutex);
+ 		msleep_interruptible(20);
++		mutex_lock(&port->serial->disc_mutex);
  	}
-diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
-index 23d2fe5..ff9a798 100644
---- a/drivers/usb/host/ohci-pxa27x.c
-+++ b/drivers/usb/host/ohci-pxa27x.c
-@@ -22,6 +22,7 @@
- #include <linux/device.h>
- #include <linux/signal.h>
- #include <linux/platform_device.h>
-+#include <linux/clk.h>
++	mutex_unlock(&port->serial->disc_mutex);
+ }
  
- #include <asm/mach-types.h>
- #include <asm/hardware.h>
-@@ -32,6 +33,8 @@
  
- #define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
+diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
+index 497e29a..3ce98e8 100644
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
+ 			goto bailout_mutex_unlock;
+ 		}
  
-+static struct clk *usb_clk;
-+
- /*
-   PMM_NPS_MODE -- PMM Non-power switching mode
-       Ports are powered continuously.
-@@ -80,7 +83,7 @@ static int pxa27x_start_hc(struct device *dev)
++		retval = usb_autopm_get_interface(serial->interface);
++		if (retval)
++			goto bailout_module_put;
+ 		/* only call the device specific open if this 
+ 		 * is the first time the port is opened */
+ 		retval = serial->type->open(port, filp);
+ 		if (retval)
+-			goto bailout_module_put;
++			goto bailout_interface_put;
+ 	}
  
- 	inf = dev->platform_data;
+ 	mutex_unlock(&port->mutex);
+ 	return 0;
  
--	pxa_set_cken(CKEN_USBHOST, 1);
-+	clk_enable(usb_clk);
++bailout_interface_put:
++	usb_autopm_put_interface(serial->interface);
+ bailout_module_put:
+ 	module_put(serial->type->driver.owner);
+ bailout_mutex_unlock:
+@@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
+ 	}
  
- 	UHCHR |= UHCHR_FHR;
- 	udelay(11);
-@@ -123,7 +126,7 @@ static void pxa27x_stop_hc(struct device *dev)
- 	UHCCOMS |= 1;
- 	udelay(10);
+ 	--port->open_count;
+-	if (port->open_count == 0) {
++	if (port->open_count == 0)
+ 		/* only call the device specific close if this 
+ 		 * port is being closed by the last owner */
+ 		port->serial->type->close(port, filp);
  
--	pxa_set_cken(CKEN_USBHOST, 0);
-+	clk_disable(usb_clk);
++	if (port->open_count == (port->console? 1 : 0)) {
+ 		if (port->tty) {
+ 			if (port->tty->driver_data)
+ 				port->tty->driver_data = NULL;
+ 			port->tty = NULL;
+ 		}
++	}
+ 
++	if (port->open_count == 0) {
++		usb_autopm_put_interface(port->serial->interface);
+ 		module_put(port->serial->type->driver.owner);
+ 	}
+ 
+@@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
+ 	serial->type = driver;
+ 	serial->interface = interface;
+ 	kref_init(&serial->kref);
++	mutex_init(&serial->disc_mutex);
+ 
+ 	return serial;
  }
+@@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
+ 	usb_serial_console_disconnect(serial);
+ 	dbg ("%s", __FUNCTION__);
  
++	mutex_lock(&serial->disc_mutex);
+ 	usb_set_intfdata (interface, NULL);
+-	if (serial) {
+-		for (i = 0; i < serial->num_ports; ++i) {
+-			port = serial->port[i];
+-			if (port) {
+-				if (port->tty)
+-					tty_hangup(port->tty);
+-				kill_traffic(port);
+-			}
++	/* must set a flag, to signal subdrivers */
++	serial->disconnected = 1;
++	for (i = 0; i < serial->num_ports; ++i) {
++		port = serial->port[i];
++		if (port) {
++			if (port->tty)
++				tty_hangup(port->tty);
++			kill_traffic(port);
+ 		}
+-		/* let the last holder of this object 
+-		 * cause it to be cleaned up */
+-		usb_serial_put(serial);
+ 	}
++	/* let the last holder of this object
++	 * cause it to be cleaned up */
++	mutex_unlock(&serial->disc_mutex);
++	usb_serial_put(serial);
+ 	dev_info(dev, "device disconnected\n");
+ }
+ 
+@@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
+ 	struct usb_serial_port *port;
+ 	int i, r = 0;
  
-@@ -158,6 +161,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
- 		return -ENOMEM;
- 	}
+-	if (!serial) /* device has been disconnected */
+-		return 0;
+-
+ 	for (i = 0; i < serial->num_ports; ++i) {
+ 		port = serial->port[i];
+ 		if (port)
+@@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device)
+ 	set_to_generic_if_null(device, read_bulk_callback);
+ 	set_to_generic_if_null(device, write_bulk_callback);
+ 	set_to_generic_if_null(device, shutdown);
++	set_to_generic_if_null(device, resume);
+ }
+ 
+ int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
+diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
+index 7ee087f..22b3f78 100644
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
+ 	usb_kill_urb(port->read_urb);
+ 	usb_kill_urb(port->interrupt_in_urb);
+ 
+-	/* Try to send shutdown message, if the device is gone, this will just fail. */
+-	transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+-	if (transfer_buffer) {
+-		usb_control_msg (port->serial->dev,
+-				 usb_rcvctrlpipe(port->serial->dev, 0),
+-				 VISOR_CLOSE_NOTIFICATION, 0xc2,
+-				 0x0000, 0x0000, 
+-				 transfer_buffer, 0x12, 300);
+-		kfree (transfer_buffer);
++	mutex_lock(&port->serial->disc_mutex);
++	if (!port->serial->disconnected) {
++		/* Try to send shutdown message, unless the device is gone */
++		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
++		if (transfer_buffer) {
++			usb_control_msg (port->serial->dev,
++					 usb_rcvctrlpipe(port->serial->dev, 0),
++					 VISOR_CLOSE_NOTIFICATION, 0xc2,
++					 0x0000, 0x0000,
++					 transfer_buffer, 0x12, 300);
++			kfree (transfer_buffer);
++		}
+ 	}
++	mutex_unlock(&port->serial->disc_mutex);
+ 
+ 	if (stats)
+ 		dev_info(&port->dev, "Bytes In = %d  Bytes Out = %d\n",
+diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
+index ee5dd8b..38726ef 100644
+--- a/drivers/usb/serial/whiteheat.c
++++ b/drivers/usb/serial/whiteheat.c
+@@ -610,8 +610,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
+ 	if (retval)
+ 		goto exit;
  
-+	usb_clk = clk_get(&pdev->dev, "USBCLK");
-+	if (IS_ERR(usb_clk))
-+		return PTR_ERR(usb_clk);
+-	if (port->tty)
+-		port->tty->low_latency = 1;
++	port->tty->low_latency = 1;
+ 
+ 	/* send an open port command */
+ 	retval = firm_open(port);
+@@ -659,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
+ 	struct list_head *tmp2;
+ 
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+-	
 +
- 	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
- 	if (!hcd)
- 		return -ENOMEM;
-@@ -201,6 +208,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
- 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-  err1:
- 	usb_put_hcd(hcd);
-+	clk_put(usb_clk);
- 	return retval;
- }
++	mutex_lock(&port->serial->disc_mutex);
+ 	/* filp is NULL when called from usb_serial_disconnect */
+-	if (filp && (tty_hung_up_p(filp))) {
++	if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
++		mutex_unlock(&port->serial->disc_mutex);
+ 		return;
+ 	}
++	mutex_unlock(&port->serial->disc_mutex);
  
-@@ -225,6 +233,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
- 	iounmap(hcd->regs);
- 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- 	usb_put_hcd(hcd);
-+	clk_put(usb_clk);
- }
+ 	port->tty->closing = 1;
  
- /*-------------------------------------------------------------------------*/
 diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
 index 88aa59a..f5a4e8d 100644
 --- a/drivers/usb/storage/freecom.c
@@ -709209,19 +754721,47 @@
  		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
  	}
  
+diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
+index ee5b42a..187dd1e 100644
+--- a/drivers/usb/storage/initializers.c
++++ b/drivers/usb/storage/initializers.c
+@@ -66,7 +66,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
+ {
+ 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
+ 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
+-	int res, partial;
++	int res;
++	unsigned int partial;
+ 	static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
+ 
+ 	US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
 diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
-index 49ba6c0..0db4886 100644
+index 49ba6c0..2ae1e86 100644
 --- a/drivers/usb/storage/isd200.c
 +++ b/drivers/usb/storage/isd200.c
-@@ -49,6 +49,7 @@
+@@ -48,7 +48,7 @@
+ #include <linux/errno.h>
  #include <linux/slab.h>
  #include <linux/hdreg.h>
- #include <linux/ide.h>
+-#include <linux/ide.h>
 +#include <linux/scatterlist.h>
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
-@@ -287,6 +288,7 @@ struct isd200_info {
+@@ -109,6 +109,12 @@
+ #define REG_STATUS		0x80
+ #define REG_COMMAND		0x80
+ 
++/* ATA registers offset definitions */
++#define ATA_REG_ERROR_OFFSET		1
++#define ATA_REG_LCYL_OFFSET		4
++#define ATA_REG_HCYL_OFFSET		5
++#define ATA_REG_STATUS_OFFSET		7
++
+ /* ATA error definitions not in <linux/hdreg.h> */
+ #define ATA_ERROR_MEDIA_CHANGE		0x20
+ 
+@@ -287,6 +293,7 @@ struct isd200_info {
  	/* maximum number of LUNs supported */
  	unsigned char MaxLUNs;
  	struct scsi_cmnd srb;
@@ -709229,7 +754769,16 @@
  };
  
  
-@@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+@@ -358,7 +365,7 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+ {
+ 	struct isd200_info *info = (struct isd200_info *)us->extra;
+ 	struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
+-	unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
++	unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET];
+ 
+ 	if(error & ATA_ERROR_MEDIA_CHANGE) {
+ 		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+@@ -398,6 +405,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
   * Transport routines
   ***********************************************************************/
  
@@ -709261,7 +754810,7 @@
  
  /**************************************************************************
   *  isd200_action
-@@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action,
+@@ -432,9 +464,7 @@ static int isd200_action( struct us_data *us, int action,
  		ata.generic.RegisterSelect =
  		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
  		  REG_STATUS | REG_ERROR;
@@ -709272,7 +754821,7 @@
  		break;
  
  	case ACTION_ENUM:
-@@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action,
+@@ -444,7 +474,7 @@ static int isd200_action( struct us_data *us, int action,
  					   ACTION_SELECT_5;
  		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
  		ata.write.DeviceHeadByte = value;
@@ -709281,7 +754830,7 @@
  		break;
  
  	case ACTION_RESET:
-@@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action,
+@@ -453,7 +483,7 @@ static int isd200_action( struct us_data *us, int action,
  					   ACTION_SELECT_3|ACTION_SELECT_4;
  		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
  		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
@@ -709290,7 +754839,7 @@
  		break;
  
  	case ACTION_REENABLE:
-@@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action,
+@@ -462,7 +492,7 @@ static int isd200_action( struct us_data *us, int action,
  					   ACTION_SELECT_3|ACTION_SELECT_4;
  		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
  		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
@@ -709299,7 +754848,7 @@
  		break;
  
  	case ACTION_SOFT_RESET:
-@@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action,
+@@ -471,21 +501,20 @@ static int isd200_action( struct us_data *us, int action,
  		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
  		ata.write.DeviceHeadByte = info->DeviceHead;
  		ata.write.CommandByte = WIN_SRST;
@@ -709325,7 +754874,18 @@
  	}
  
  	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
-@@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us,
+@@ -525,8 +554,8 @@ static int isd200_read_regs( struct us_data *us )
+ 		retStatus = ISD200_ERROR;
+ 	} else {
+ 		memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
+-		US_DEBUGP("   Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", 
+-			  info->ATARegs[IDE_ERROR_OFFSET]);
++		US_DEBUGP("   Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
++			  info->ATARegs[ATA_REG_ERROR_OFFSET]);
+ 	}
+ 
+ 	return retStatus;
+@@ -590,7 +619,7 @@ static void isd200_invoke_transport( struct us_data *us,
  		return;
  	}
  
@@ -709334,7 +754894,55 @@
  	    !((srb->cmnd[0] == REQUEST_SENSE) ||
  	      (srb->cmnd[0] == INQUIRY) ||
  	      (srb->cmnd[0] == MODE_SENSE) ||
-@@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
+@@ -868,7 +897,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+ 			break;
+ 
+ 		if (!detect) {
+-			if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
++			if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) {
+ 				US_DEBUGP("   %s status is still BSY, try again...\n",mstr);
+ 			} else {
+ 				US_DEBUGP("   %s status !BSY, continue with next operation\n",mstr);
+@@ -878,12 +907,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+ 		/* check for BUSY_STAT and */
+ 		/* WRERR_STAT (workaround ATA Zip drive) and */ 
+ 		/* ERR_STAT (workaround for Archos CD-ROM) */
+-		else if (regs[IDE_STATUS_OFFSET] & 
++		else if (regs[ATA_REG_STATUS_OFFSET] &
+ 			 (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
+ 			US_DEBUGP("   Status indicates it is not ready, try again...\n");
+ 		}
+ 		/* check for DRDY, ATA devices set DRDY after SRST */
+-		else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
++		else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) {
+ 			US_DEBUGP("   Identified ATA device\n");
+ 			info->DeviceFlags |= DF_ATA_DEVICE;
+ 			info->DeviceHead = master_slave;
+@@ -892,8 +921,8 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+ 		/* check Cylinder High/Low to
+ 		   determine if it is an ATAPI device
+ 		*/
+-		else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
+-			 (regs[IDE_LCYL_OFFSET] == 0x14)) {
++		else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
++			 regs[ATA_REG_LCYL_OFFSET] == 0x14) {
+ 			/* It seems that the RICOH 
+ 			   MP6200A CD/RW drive will 
+ 			   report itself okay as a
+@@ -977,12 +1006,6 @@ static int isd200_manual_enum(struct us_data *us)
+ 	return(retStatus);
+ }
+ 
+-/*
+- *	We are the last non IDE user of the legacy IDE ident structures
+- *	and we thus want to keep a private copy of this function so the
+- *	driver can be used without the obsolete drivers/ide layer
+- */
+-
+ static void isd200_fix_driveid (struct hd_driveid *id)
+ {
+ #ifndef __LITTLE_ENDIAN
+@@ -1217,7 +1240,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
  	return(retStatus);
  }
  
@@ -709342,7 +754950,7 @@
  /**************************************************************************
   * isd200_scsi_to_ata
   *									 
-@@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+@@ -1266,7 +1288,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
  			ataCdb->generic.TransferBlockSize = 1;
  			ataCdb->generic.RegisterSelect = REG_COMMAND;
  			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
@@ -709351,7 +754959,7 @@
  		} else {
  			US_DEBUGP("   Media Status not supported, just report okay\n");
  			srb->result = SAM_STAT_GOOD;
-@@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+@@ -1284,7 +1306,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
  			ataCdb->generic.TransferBlockSize = 1;
  			ataCdb->generic.RegisterSelect = REG_COMMAND;
  			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
@@ -709360,7 +754968,7 @@
  		} else {
  			US_DEBUGP("   Media Status not supported, just report okay\n");
  			srb->result = SAM_STAT_GOOD;
-@@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+@@ -1390,7 +1412,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
  			ataCdb->generic.RegisterSelect = REG_COMMAND;
  			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
  				WIN_DOORLOCK : WIN_DOORUNLOCK;
@@ -709369,7 +754977,7 @@
  		} else {
  			US_DEBUGP("   Not removeable media, just report okay\n");
  			srb->result = SAM_STAT_GOOD;
-@@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+@@ -1416,7 +1438,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
  			ataCdb->generic.TransferBlockSize = 1;
  			ataCdb->generic.RegisterSelect = REG_COMMAND;
  			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
@@ -709378,7 +754986,7 @@
  		} else {
  			US_DEBUGP("   Nothing to do, just report okay\n");
  			srb->result = SAM_STAT_GOOD;
-@@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us)
+@@ -1525,7 +1547,7 @@ int isd200_Initialization(struct us_data *us)
  
  void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
  {
@@ -709387,7 +754995,7 @@
  	union ata_cdb ataCdb;
  
  	/* Make sure driver was initialized */
-@@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+@@ -1533,11 +1555,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
  	if (us->extra == NULL)
  		US_DEBUGP("ERROR Driver not initialized\n");
  
@@ -710003,6 +755611,25 @@
  
  extern int usb_stor_port_reset(struct us_data *us);
  #endif
+diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
+index 6d6108b..fe12737 100644
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -86,6 +86,14 @@ UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001,
+ 		US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
+ #endif
+ 
++/* Reported by Grant Grundler <grundler at parisc-linux.org>
++ * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
++ */
++UNUSUAL_DEV(  0x03f0, 0x4002, 0x0001, 0x0001,
++		"HP",
++		"PhotoSmart R707",
++		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
++
+ /* Reported by Sebastian Kapfer <sebastian_kapfer at gmx.net>
+  * and Olaf Hering <olh at suse.de> (different bcd's, same vendor/product)
+  * for USB floppies that need the SINGLE_LUN enforcement.
 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
 index 5b3dbcf..758435f 100644
 --- a/drivers/video/Kconfig
@@ -710094,6 +755721,106 @@
  #include <asm/arch/omapfb.h>
  
  #define MODULE_NAME	"omapfb-lcd_h3"
+diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
+index d53bf69..9b05da6 100644
+--- a/drivers/video/sis/sis.h
++++ b/drivers/video/sis/sis.h
+@@ -39,12 +39,7 @@
+ #include <linux/spinlock.h>
+ 
+ #ifdef CONFIG_COMPAT
+-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
+-#include <linux/ioctl32.h>
+-#define SIS_OLD_CONFIG_COMPAT
+-#else
+ #define SIS_NEW_CONFIG_COMPAT
+-#endif
+ #endif	/* CONFIG_COMPAT */
+ 
+ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+@@ -607,9 +602,6 @@ struct sis_video_info {
+ 	int		haveXGIROM;
+ 	int		registered;
+ 	int		warncount;
+-#ifdef SIS_OLD_CONFIG_COMPAT
+-	int		ioctl32registered;
+-#endif
+ 
+ 	int		sisvga_engine;
+ 	int		hwcursor_size;
+diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
+index 37bd24b..93ae747 100644
+--- a/drivers/video/sis/sis_main.c
++++ b/drivers/video/sis/sis_main.c
+@@ -5805,9 +5805,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ 	ivideo->pcifunc = PCI_FUNC(pdev->devfn);
+ 	ivideo->subsysvendor = pdev->subsystem_vendor;
+ 	ivideo->subsysdevice = pdev->subsystem_device;
+-#ifdef SIS_OLD_CONFIG_COMPAT
+-	ivideo->ioctl32registered = 0;
+-#endif
+ 
+ #ifndef MODULE
+ 	if(sisfb_mode_idx == -1) {
+@@ -6420,30 +6417,6 @@ error_3:	vfree(ivideo->bios_abase);
+ 		ivideo->next = card_list;
+ 		card_list = ivideo;
+ 
+-#ifdef SIS_OLD_CONFIG_COMPAT
+-		{
+-		int ret;
+-		/* Our ioctls are all "32/64bit compatible" */
+-		ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
+-		ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
+-		ret |= register_ioctl32_conversion(FBIOGET_VBLANK,         NULL);
+-		ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
+-		ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
+-		ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
+-		ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
+-		ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
+-		ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
+-		ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
+-		ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
+-		ret |= register_ioctl32_conversion(SISFB_COMMAND,          NULL);
+-		if(ret)
+-			printk(KERN_ERR
+-				"sisfb: Error registering ioctl32 translations\n");
+-		else
+-			ivideo->ioctl32registered = 1;
+-		}
+-#endif
+-
+ 		printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
+ 			ivideo->sisfb_accel ? "enabled" : "disabled",
+ 			ivideo->sisfb_ypan  ?
+@@ -6473,27 +6446,6 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
+ 	int			registered = ivideo->registered;
+ 	int			modechanged = ivideo->modechanged;
+ 
+-#ifdef SIS_OLD_CONFIG_COMPAT
+-	if(ivideo->ioctl32registered) {
+-		int ret;
+-		ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
+-		ret |= unregister_ioctl32_conversion(FBIO_FREE);
+-		ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
+-		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
+-		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
+-		ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
+-		ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
+-		ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
+-		ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
+-		ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
+-		ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
+-		ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
+-		if(ret)
+-			printk(KERN_ERR
+-			     "sisfb: Error unregistering ioctl32 translations\n");
+-	}
+-#endif
+-
+ 	/* Unmap */
+ 	iounmap(ivideo->mmio_vbase);
+ 	iounmap(ivideo->video_vbase);
 diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
 index c31f549..1c65666 100644
 --- a/drivers/video/vermilion/vermilion.c
@@ -710950,7 +756677,7 @@
  	if (!machine_is_netwinder())
  	        release_region(IO_INDEX_PORT,2);
 diff --git a/fs/Kconfig b/fs/Kconfig
-index 781b47d..219ec06 100644
+index 781b47d..987b5d7 100644
 --- a/fs/Kconfig
 +++ b/fs/Kconfig
 @@ -236,6 +236,7 @@ config JBD_DEBUG
@@ -710989,7 +756716,16 @@
  	help
  	  configfs is a ram-based filesystem that provides the converse
  	  of sysfs's functionality. Where sysfs is a filesystem-based
-@@ -1905,13 +1900,15 @@ config CIFS
+@@ -1679,6 +1674,8 @@ config NFSD
+ 	select CRYPTO_MD5 if NFSD_V4
+ 	select CRYPTO if NFSD_V4
+ 	select FS_POSIX_ACL if NFSD_V4
++	select PROC_FS if NFSD_V4
++	select PROC_FS if SUNRPC_GSS
+ 	help
+ 	  If you want your Linux box to act as an NFS *server*, so that other
+ 	  computers on your local network which support NFS can access certain
+@@ -1905,13 +1902,15 @@ config CIFS
  	  file servers such as Windows 2000 (including Windows 2003, NT 4  
  	  and Windows XP) as well by Samba (which provides excellent CIFS
  	  server support for Linux and many other operating systems). Limited
@@ -711012,7 +756748,7 @@
  	  If you need to mount to Samba or Windows from this machine, say Y.
  
  config CIFS_STATS
-@@ -1943,7 +1940,8 @@ config CIFS_WEAK_PW_HASH
+@@ -1943,7 +1942,8 @@ config CIFS_WEAK_PW_HASH
  	  (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
  	  security mechanisms. These hash the password more securely
  	  than the mechanisms used in the older LANMAN version of the
@@ -711022,7 +756758,7 @@
  
  	  Enabling this option allows the cifs module to mount to older
  	  LANMAN based servers such as OS/2 and Windows 95, but such
-@@ -1951,8 +1949,8 @@ config CIFS_WEAK_PW_HASH
+@@ -1951,8 +1951,8 @@ config CIFS_WEAK_PW_HASH
  	  security mechanisms if you are on a public network.  Unless you
  	  have a need to access old SMB servers (and are on a private 
  	  network) you probably want to say N.  Even if this support
@@ -711033,7 +756769,7 @@
  	  can be set to required (or optional) either in
  	  /proc/fs/cifs (see fs/cifs/README for more detail) or via an
  	  option on the mount command. This support is disabled by 
-@@ -2018,12 +2016,22 @@ config CIFS_UPCALL
+@@ -2018,12 +2018,22 @@ config CIFS_UPCALL
  	  depends on CIFS_EXPERIMENTAL
  	  depends on KEYS
  	  help
@@ -711059,7 +756795,7 @@
  config NCP_FS
  	tristate "NCP file system support (to mount NetWare volumes)"
  	depends on IPX!=n || INET
-@@ -2130,4 +2138,3 @@ source "fs/nls/Kconfig"
+@@ -2130,4 +2140,3 @@ source "fs/nls/Kconfig"
  source "fs/dlm/Kconfig"
  
  endmenu
@@ -731500,6 +777236,355 @@
  }
  
  static int nlm_wait_on_grace(wait_queue_head_t *queue)
+diff --git a/fs/lockd/host.c b/fs/lockd/host.c
+index 572601e..ca6b16f 100644
+--- a/fs/lockd/host.c
++++ b/fs/lockd/host.c
+@@ -34,10 +34,10 @@ static DEFINE_MUTEX(nlm_host_mutex);
+ 
+ static void			nlm_gc_hosts(void);
+ static struct nsm_handle *	__nsm_find(const struct sockaddr_in *,
+-					const char *, int, int);
++					const char *, unsigned int, int);
+ static struct nsm_handle *	nsm_find(const struct sockaddr_in *sin,
+ 					 const char *hostname,
+-					 int hostname_len);
++					 unsigned int hostname_len);
+ 
+ /*
+  * Common host lookup routine for server & client
+@@ -45,7 +45,8 @@ static struct nsm_handle *	nsm_find(const struct sockaddr_in *sin,
+ static struct nlm_host *
+ nlm_lookup_host(int server, const struct sockaddr_in *sin,
+ 		int proto, int version, const char *hostname,
+-		int hostname_len, const struct sockaddr_in *ssin)
++		unsigned int hostname_len,
++		const struct sockaddr_in *ssin)
+ {
+ 	struct hlist_head *chain;
+ 	struct hlist_node *pos;
+@@ -176,7 +177,7 @@ nlm_destroy_host(struct nlm_host *host)
+  */
+ struct nlm_host *
+ nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
+-			const char *hostname, int hostname_len)
++			const char *hostname, unsigned int hostname_len)
+ {
+ 	struct sockaddr_in ssin = {0};
+ 
+@@ -189,7 +190,7 @@ nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
+  */
+ struct nlm_host *
+ nlmsvc_lookup_host(struct svc_rqst *rqstp,
+-			const char *hostname, int hostname_len)
++			const char *hostname, unsigned int hostname_len)
+ {
+ 	struct sockaddr_in ssin = {0};
+ 
+@@ -307,7 +308,8 @@ void nlm_release_host(struct nlm_host *host)
+  * Release all resources held by that peer.
+  */
+ void nlm_host_rebooted(const struct sockaddr_in *sin,
+-				const char *hostname, int hostname_len,
++				const char *hostname,
++				unsigned int hostname_len,
+ 				u32 new_state)
+ {
+ 	struct hlist_head *chain;
+@@ -377,8 +379,13 @@ nlm_shutdown_hosts(void)
+ 	/* First, make all hosts eligible for gc */
+ 	dprintk("lockd: nuking all hosts...\n");
+ 	for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+-		hlist_for_each_entry(host, pos, chain, h_hash)
++		hlist_for_each_entry(host, pos, chain, h_hash) {
+ 			host->h_expires = jiffies - 1;
++			if (host->h_rpcclnt) {
++				rpc_shutdown_client(host->h_rpcclnt);
++				host->h_rpcclnt = NULL;
++			}
++		}
+ 	}
+ 
+ 	/* Then, perform a garbage collection pass */
+@@ -449,7 +456,7 @@ static DEFINE_MUTEX(nsm_mutex);
+ 
+ static struct nsm_handle *
+ __nsm_find(const struct sockaddr_in *sin,
+-		const char *hostname, int hostname_len,
++		const char *hostname, unsigned int hostname_len,
+ 		int create)
+ {
+ 	struct nsm_handle *nsm = NULL;
+@@ -503,7 +510,8 @@ out:
+ }
+ 
+ static struct nsm_handle *
+-nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
++nsm_find(const struct sockaddr_in *sin, const char *hostname,
++	 unsigned int hostname_len)
+ {
+ 	return __nsm_find(sin, hostname, hostname_len, 1);
+ }
+diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
+index 82e2192..0822646 100644
+--- a/fs/lockd/svc.c
++++ b/fs/lockd/svc.c
+@@ -219,19 +219,6 @@ lockd(struct svc_rqst *rqstp)
+ 	module_put_and_exit(0);
+ }
+ 
+-
+-static int find_socket(struct svc_serv *serv, int proto)
+-{
+-	struct svc_sock *svsk;
+-	int found = 0;
+-	list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
+-		if (svsk->sk_sk->sk_protocol == proto) {
+-			found = 1;
+-			break;
+-		}
+-	return found;
+-}
+-
+ /*
+  * Make any sockets that are needed but not present.
+  * If nlm_udpport or nlm_tcpport were set as module
+@@ -240,17 +227,25 @@ static int find_socket(struct svc_serv *serv, int proto)
+ static int make_socks(struct svc_serv *serv, int proto)
+ {
+ 	static int warned;
++	struct svc_xprt *xprt;
+ 	int err = 0;
+ 
+-	if (proto == IPPROTO_UDP || nlm_udpport)
+-		if (!find_socket(serv, IPPROTO_UDP))
+-			err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport,
+-						SVC_SOCK_DEFAULTS);
+-	if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport))
+-		if (!find_socket(serv, IPPROTO_TCP))
+-			err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport,
+-						SVC_SOCK_DEFAULTS);
+-
++	if (proto == IPPROTO_UDP || nlm_udpport) {
++		xprt = svc_find_xprt(serv, "udp", 0, 0);
++		if (!xprt)
++			err = svc_create_xprt(serv, "udp", nlm_udpport,
++					      SVC_SOCK_DEFAULTS);
++		else
++			svc_xprt_put(xprt);
++	}
++	if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
++		xprt = svc_find_xprt(serv, "tcp", 0, 0);
++		if (!xprt)
++			err = svc_create_xprt(serv, "tcp", nlm_tcpport,
++					      SVC_SOCK_DEFAULTS);
++		else
++			svc_xprt_put(xprt);
++	}
+ 	if (err >= 0) {
+ 		warned = 0;
+ 		err = 0;
+diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
+index bf27b6c..385437e 100644
+--- a/fs/lockd/svc4proc.c
++++ b/fs/lockd/svc4proc.c
+@@ -84,6 +84,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ {
+ 	struct nlm_host	*host;
+ 	struct nlm_file	*file;
++	int rc = rpc_success;
+ 
+ 	dprintk("lockd: TEST4        called\n");
+ 	resp->cookie = argp->cookie;
+@@ -91,7 +92,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Don't accept test requests during grace period */
+ 	if (nlmsvc_grace_period) {
+ 		resp->status = nlm_lck_denied_grace_period;
+-		return rpc_success;
++		return rc;
+ 	}
+ 
+ 	/* Obtain client and file */
+@@ -101,12 +102,13 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Now check for conflicting locks */
+ 	resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
+ 	if (resp->status == nlm_drop_reply)
+-		return rpc_drop_reply;
++		rc = rpc_drop_reply;
++	else
++		dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));
+ 
+-	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
+ 	nlm_release_host(host);
+ 	nlm_release_file(file);
+-	return rpc_success;
++	return rc;
+ }
+ 
+ static __be32
+@@ -115,6 +117,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ {
+ 	struct nlm_host	*host;
+ 	struct nlm_file	*file;
++	int rc = rpc_success;
+ 
+ 	dprintk("lockd: LOCK          called\n");
+ 
+@@ -123,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Don't accept new lock requests during grace period */
+ 	if (nlmsvc_grace_period && !argp->reclaim) {
+ 		resp->status = nlm_lck_denied_grace_period;
+-		return rpc_success;
++		return rc;
+ 	}
+ 
+ 	/* Obtain client and file */
+@@ -146,12 +149,13 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
+ 					argp->block, &argp->cookie);
+ 	if (resp->status == nlm_drop_reply)
+-		return rpc_drop_reply;
++		rc = rpc_drop_reply;
++	else
++		dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
+ 
+-	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
+ 	nlm_release_host(host);
+ 	nlm_release_file(file);
+-	return rpc_success;
++	return rc;
+ }
+ 
+ static __be32
+diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
+index d120ec3..2f4d8fa 100644
+--- a/fs/lockd/svclock.c
++++ b/fs/lockd/svclock.c
+@@ -501,25 +501,29 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+ 			block, block->b_flags, block->b_fl);
+ 		if (block->b_flags & B_TIMED_OUT) {
+ 			nlmsvc_unlink_block(block);
+-			return nlm_lck_denied;
++			ret = nlm_lck_denied;
++			goto out;
+ 		}
+ 		if (block->b_flags & B_GOT_CALLBACK) {
++			nlmsvc_unlink_block(block);
+ 			if (block->b_fl != NULL
+ 					&& block->b_fl->fl_type != F_UNLCK) {
+ 				lock->fl = *block->b_fl;
+ 				goto conf_lock;
+-			}
+-			else {
+-				nlmsvc_unlink_block(block);
+-				return nlm_granted;
++			} else {
++				ret = nlm_granted;
++				goto out;
+ 			}
+ 		}
+-		return nlm_drop_reply;
++		ret = nlm_drop_reply;
++		goto out;
+ 	}
+ 
+ 	error = vfs_test_lock(file->f_file, &lock->fl);
+-	if (error == -EINPROGRESS)
+-		return nlmsvc_defer_lock_rqst(rqstp, block);
++	if (error == -EINPROGRESS) {
++		ret = nlmsvc_defer_lock_rqst(rqstp, block);
++		goto out;
++	}
+ 	if (error) {
+ 		ret = nlm_lck_denied_nolocks;
+ 		goto out;
+diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
+index 9cd5c8b..88379cc 100644
+--- a/fs/lockd/svcproc.c
++++ b/fs/lockd/svcproc.c
+@@ -113,6 +113,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ {
+ 	struct nlm_host	*host;
+ 	struct nlm_file	*file;
++	int rc = rpc_success;
+ 
+ 	dprintk("lockd: TEST          called\n");
+ 	resp->cookie = argp->cookie;
+@@ -120,7 +121,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Don't accept test requests during grace period */
+ 	if (nlmsvc_grace_period) {
+ 		resp->status = nlm_lck_denied_grace_period;
+-		return rpc_success;
++		return rc;
+ 	}
+ 
+ 	/* Obtain client and file */
+@@ -130,13 +131,14 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Now check for conflicting locks */
+ 	resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
+ 	if (resp->status == nlm_drop_reply)
+-		return rpc_drop_reply;
++		rc = rpc_drop_reply;
++	else
++		dprintk("lockd: TEST          status %d vers %d\n",
++			ntohl(resp->status), rqstp->rq_vers);
+ 
+-	dprintk("lockd: TEST          status %d vers %d\n",
+-		ntohl(resp->status), rqstp->rq_vers);
+ 	nlm_release_host(host);
+ 	nlm_release_file(file);
+-	return rpc_success;
++	return rc;
+ }
+ 
+ static __be32
+@@ -145,6 +147,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ {
+ 	struct nlm_host	*host;
+ 	struct nlm_file	*file;
++	int rc = rpc_success;
+ 
+ 	dprintk("lockd: LOCK          called\n");
+ 
+@@ -153,7 +156,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	/* Don't accept new lock requests during grace period */
+ 	if (nlmsvc_grace_period && !argp->reclaim) {
+ 		resp->status = nlm_lck_denied_grace_period;
+-		return rpc_success;
++		return rc;
+ 	}
+ 
+ 	/* Obtain client and file */
+@@ -176,12 +179,13 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ 	resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
+ 					       argp->block, &argp->cookie));
+ 	if (resp->status == nlm_drop_reply)
+-		return rpc_drop_reply;
++		rc = rpc_drop_reply;
++	else
++		dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
+ 
+-	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
+ 	nlm_release_host(host);
+ 	nlm_release_file(file);
+-	return rpc_success;
++	return rc;
+ }
+ 
+ static __be32
+diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
+index 84ebba3..dbbefbc 100644
+--- a/fs/lockd/svcsubs.c
++++ b/fs/lockd/svcsubs.c
+@@ -87,7 +87,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
+ 	unsigned int	hash;
+ 	__be32		nfserr;
+ 
+-	nlm_debug_print_fh("nlm_file_lookup", f);
++	nlm_debug_print_fh("nlm_lookup_file", f);
+ 
+ 	hash = file_hash(f);
+ 
 diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
 index 633653b..3e459e1 100644
 --- a/fs/lockd/xdr.c
@@ -731544,7 +777629,7 @@
  	init_mount_tree();
  }
 diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
-index a796be5..9b6bbf1 100644
+index a796be5..bd185a5 100644
 --- a/fs/nfs/callback.c
 +++ b/fs/nfs/callback.c
 @@ -73,8 +73,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
@@ -731565,6 +777650,17 @@
  		svc_process(rqstp);
  	}
  
+@@ -123,8 +119,8 @@ int nfs_callback_up(void)
+ 	if (!serv)
+ 		goto out_err;
+ 
+-	ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport,
+-							SVC_SOCK_ANONYMOUS);
++	ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
++			      SVC_SOCK_ANONYMOUS);
+ 	if (ret <= 0)
+ 		goto out_destroy;
+ 	nfs_callback_tcpport = ret;
 @@ -168,12 +164,11 @@ void nfs_callback_down(void)
  
  static int nfs_callback_authenticate(struct svc_rqst *rqstp)
@@ -735784,200 +781880,1566 @@
 +			if (!nfs_set_page_tag_locked(req)) {
  				int error;
  
- 				spin_unlock(&inode->i_lock);
-@@ -646,7 +644,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
- 	    || req->wb_page != page
- 	    || !nfs_dirty_request(req)
- 	    || offset > rqend || end < req->wb_offset) {
--		nfs_unlock_request(req);
-+		nfs_clear_page_tag_locked(req);
- 		return ERR_PTR(-EBUSY);
+ 				spin_unlock(&inode->i_lock);
+@@ -646,7 +644,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
+ 	    || req->wb_page != page
+ 	    || !nfs_dirty_request(req)
+ 	    || offset > rqend || end < req->wb_offset) {
+-		nfs_unlock_request(req);
++		nfs_clear_page_tag_locked(req);
+ 		return ERR_PTR(-EBUSY);
+ 	}
+ 
+@@ -755,7 +753,7 @@ static void nfs_writepage_release(struct nfs_page *req)
+ 	nfs_clear_page_tag_locked(req);
+ }
+ 
+-static inline int flush_task_priority(int how)
++static int flush_task_priority(int how)
+ {
+ 	switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
+ 		case FLUSH_HIGHPRI:
+@@ -775,15 +773,31 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
+ 		unsigned int count, unsigned int offset,
+ 		int how)
+ {
+-	struct inode		*inode;
+-	int flags;
++	struct inode *inode = req->wb_context->path.dentry->d_inode;
++	int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
++	int priority = flush_task_priority(how);
++	struct rpc_task *task;
++	struct rpc_message msg = {
++		.rpc_argp = &data->args,
++		.rpc_resp = &data->res,
++		.rpc_cred = req->wb_context->cred,
++	};
++	struct rpc_task_setup task_setup_data = {
++		.rpc_client = NFS_CLIENT(inode),
++		.task = &data->task,
++		.rpc_message = &msg,
++		.callback_ops = call_ops,
++		.callback_data = data,
++		.flags = flags,
++		.priority = priority,
++	};
+ 
+ 	/* Set up the RPC argument and reply structs
+ 	 * NB: take care not to mess about with data->commit et al. */
+ 
+ 	data->req = req;
+ 	data->inode = inode = req->wb_context->path.dentry->d_inode;
+-	data->cred = req->wb_context->cred;
++	data->cred = msg.rpc_cred;
+ 
+ 	data->args.fh     = NFS_FH(inode);
+ 	data->args.offset = req_offset(req) + offset;
+@@ -791,6 +805,12 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
+ 	data->args.pages  = data->pagevec;
+ 	data->args.count  = count;
+ 	data->args.context = req->wb_context;
++	data->args.stable  = NFS_UNSTABLE;
++	if (how & FLUSH_STABLE) {
++		data->args.stable = NFS_DATA_SYNC;
++		if (!NFS_I(inode)->ncommit)
++			data->args.stable = NFS_FILE_SYNC;
++	}
+ 
+ 	data->res.fattr   = &data->fattr;
+ 	data->res.count   = count;
+@@ -798,12 +818,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
+ 	nfs_fattr_init(&data->fattr);
+ 
+ 	/* Set up the initial task struct.  */
+-	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+-	rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data);
+-	NFS_PROTO(inode)->write_setup(data, how);
+-
+-	data->task.tk_priority = flush_task_priority(how);
+-	data->task.tk_cookie = (unsigned long)inode;
++	NFS_PROTO(inode)->write_setup(data, &msg);
+ 
+ 	dprintk("NFS: %5u initiated write call "
+ 		"(req %s/%Ld, %u bytes @ offset %Lu)\n",
+@@ -812,16 +827,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
+ 		(long long)NFS_FILEID(inode),
+ 		count,
+ 		(unsigned long long)data->args.offset);
+-}
+-
+-static void nfs_execute_write(struct nfs_write_data *data)
+-{
+-	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
+-	sigset_t oldset;
+ 
+-	rpc_clnt_sigmask(clnt, &oldset);
+-	rpc_execute(&data->task);
+-	rpc_clnt_sigunmask(clnt, &oldset);
++	task = rpc_run_task(&task_setup_data);
++	if (!IS_ERR(task))
++		rpc_put_task(task);
+ }
+ 
+ /*
+@@ -868,7 +877,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
+ 				   wsize, offset, how);
+ 		offset += wsize;
+ 		nbytes -= wsize;
+-		nfs_execute_write(data);
+ 	} while (nbytes != 0);
+ 
+ 	return 0;
+@@ -916,7 +924,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
+ 	/* Set up the argument struct */
+ 	nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how);
+ 
+-	nfs_execute_write(data);
+ 	return 0;
+  out_bad:
+ 	while (!list_empty(head)) {
+@@ -932,7 +939,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
+ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+ 				  struct inode *inode, int ioflags)
+ {
+-	int wsize = NFS_SERVER(inode)->wsize;
++	size_t wsize = NFS_SERVER(inode)->wsize;
+ 
+ 	if (wsize < PAGE_CACHE_SIZE)
+ 		nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
+@@ -1146,19 +1153,33 @@ static void nfs_commit_rpcsetup(struct list_head *head,
+ 		struct nfs_write_data *data,
+ 		int how)
+ {
+-	struct nfs_page		*first;
+-	struct inode		*inode;
+-	int flags;
++	struct nfs_page *first = nfs_list_entry(head->next);
++	struct inode *inode = first->wb_context->path.dentry->d_inode;
++	int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
++	int priority = flush_task_priority(how);
++	struct rpc_task *task;
++	struct rpc_message msg = {
++		.rpc_argp = &data->args,
++		.rpc_resp = &data->res,
++		.rpc_cred = first->wb_context->cred,
++	};
++	struct rpc_task_setup task_setup_data = {
++		.task = &data->task,
++		.rpc_client = NFS_CLIENT(inode),
++		.rpc_message = &msg,
++		.callback_ops = &nfs_commit_ops,
++		.callback_data = data,
++		.flags = flags,
++		.priority = priority,
++	};
+ 
+ 	/* Set up the RPC argument and reply structs
+ 	 * NB: take care not to mess about with data->commit et al. */
+ 
+ 	list_splice_init(head, &data->pages);
+-	first = nfs_list_entry(data->pages.next);
+-	inode = first->wb_context->path.dentry->d_inode;
+ 
+ 	data->inode	  = inode;
+-	data->cred	  = first->wb_context->cred;
++	data->cred	  = msg.rpc_cred;
+ 
+ 	data->args.fh     = NFS_FH(data->inode);
+ 	/* Note: we always request a commit of the entire inode */
+@@ -1170,14 +1191,13 @@ static void nfs_commit_rpcsetup(struct list_head *head,
+ 	nfs_fattr_init(&data->fattr);
+ 
+ 	/* Set up the initial task struct.  */
+-	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+-	rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data);
+-	NFS_PROTO(inode)->commit_setup(data, how);
++	NFS_PROTO(inode)->commit_setup(data, &msg);
+ 
+-	data->task.tk_priority = flush_task_priority(how);
+-	data->task.tk_cookie = (unsigned long)inode;
+-	
+ 	dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
++
++	task = rpc_run_task(&task_setup_data);
++	if (!IS_ERR(task))
++		rpc_put_task(task);
+ }
+ 
+ /*
+@@ -1197,7 +1217,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
+ 	/* Set up the argument struct */
+ 	nfs_commit_rpcsetup(head, data, how);
+ 
+-	nfs_execute_write(data);
+ 	return 0;
+  out_bad:
+ 	while (!list_empty(head)) {
+diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h
+new file mode 100644
+index 0000000..78b3c0e
+--- /dev/null
++++ b/fs/nfsd/auth.h
+@@ -0,0 +1,22 @@
++/*
++ * nfsd-specific authentication stuff.
++ * uid/gid mapping not yet implemented.
++ *
++ * Copyright (C) 1995, 1996 Olaf Kirch <okir at monad.swb.de>
++ */
++
++#ifndef LINUX_NFSD_AUTH_H
++#define LINUX_NFSD_AUTH_H
++
++#define nfsd_luid(rq, uid)	((u32)(uid))
++#define nfsd_lgid(rq, gid)	((u32)(gid))
++#define nfsd_ruid(rq, uid)	((u32)(uid))
++#define nfsd_rgid(rq, gid)	((u32)(gid))
++
++/*
++ * Set the current process's fsuid/fsgid etc to those of the NFS
++ * client user
++ */
++int nfsd_setuser(struct svc_rqst *, struct svc_export *);
++
++#endif /* LINUX_NFSD_AUTH_H */
+diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
+index 66d0aeb..79b4bf8 100644
+--- a/fs/nfsd/export.c
++++ b/fs/nfsd/export.c
+@@ -1357,8 +1357,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
+ 	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
+ 
+ 	exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+-	if (PTR_ERR(exp) == -ENOENT)
+-		return nfserr_perm;
+ 	if (IS_ERR(exp))
+ 		return nfserrno(PTR_ERR(exp));
+ 	rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
+@@ -1637,13 +1635,19 @@ exp_verify_string(char *cp, int max)
+ /*
+  * Initialize the exports module.
+  */
+-void
++int
+ nfsd_export_init(void)
+ {
++	int rv;
+ 	dprintk("nfsd: initializing export module.\n");
+ 
+-	cache_register(&svc_export_cache);
+-	cache_register(&svc_expkey_cache);
++	rv = cache_register(&svc_export_cache);
++	if (rv)
++		return rv;
++	rv = cache_register(&svc_expkey_cache);
++	if (rv)
++		cache_unregister(&svc_export_cache);
++	return rv;
+ 
+ }
+ 
+@@ -1670,10 +1674,8 @@ nfsd_export_shutdown(void)
+ 
+ 	exp_writelock();
+ 
+-	if (cache_unregister(&svc_expkey_cache))
+-		printk(KERN_ERR "nfsd: failed to unregister expkey cache\n");
+-	if (cache_unregister(&svc_export_cache))
+-		printk(KERN_ERR "nfsd: failed to unregister export cache\n");
++	cache_unregister(&svc_expkey_cache);
++	cache_unregister(&svc_export_cache);
+ 	svcauth_unix_purge();
+ 
+ 	exp_writeunlock();
+diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
+index 0e5fa11..1c3b765 100644
+--- a/fs/nfsd/nfs2acl.c
++++ b/fs/nfsd/nfs2acl.c
+@@ -221,12 +221,17 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
+ 		struct nfsd3_getaclres *resp)
+ {
+ 	struct dentry *dentry = resp->fh.fh_dentry;
+-	struct inode *inode = dentry->d_inode;
++	struct inode *inode;
+ 	struct kvec *head = rqstp->rq_res.head;
+ 	unsigned int base;
+ 	int n;
+ 	int w;
+ 
++	/*
++	 * Since this is version 2, the check for nfserr in
++	 * nfsd_dispatch actually ensures the following cannot happen.
++	 * However, it seems fragile to depend on that.
++	 */
+ 	if (dentry == NULL || dentry->d_inode == NULL)
+ 		return 0;
+ 	inode = dentry->d_inode;
+diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
+index f917fd2..d7647f7 100644
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -21,6 +21,7 @@
+ #include <linux/sunrpc/svc.h>
+ #include <linux/nfsd/nfsd.h>
+ #include <linux/nfsd/xdr3.h>
++#include "auth.h"
+ 
+ #define NFSDDBG_FACILITY		NFSDDBG_XDR
+ 
+@@ -88,10 +89,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
+  * no slashes or null bytes.
+  */
+ static __be32 *
+-decode_filename(__be32 *p, char **namp, int *lenp)
++decode_filename(__be32 *p, char **namp, unsigned int *lenp)
+ {
+ 	char		*name;
+-	int		i;
++	unsigned int	i;
+ 
+ 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
+ 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
+@@ -452,8 +453,7 @@ int
+ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
+ 					struct nfsd3_symlinkargs *args)
+ {
+-	unsigned int len;
+-	int avail;
++	unsigned int len, avail;
+ 	char *old, *new;
+ 	struct kvec *vec;
+ 
+@@ -486,7 +486,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
+ 	/* now copy next page if there is one */
+ 	if (len && !avail && rqstp->rq_arg.page_len) {
+ 		avail = rqstp->rq_arg.page_len;
+-		if (avail > PAGE_SIZE) avail = PAGE_SIZE;
++		if (avail > PAGE_SIZE)
++			avail = PAGE_SIZE;
+ 		old = page_address(rqstp->rq_arg.pages[0]);
+ 	}
+ 	while (len && avail && *old) {
+@@ -816,11 +817,11 @@ static __be32 *
+ encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
+ 		struct svc_fh *fhp)
+ {
+-		p = encode_post_op_attr(cd->rqstp, p, fhp);
+-		*p++ = xdr_one;			/* yes, a file handle follows */
+-		p = encode_fh(p, fhp);
+-		fh_put(fhp);
+-		return p;
++	p = encode_post_op_attr(cd->rqstp, p, fhp);
++	*p++ = xdr_one;			/* yes, a file handle follows */
++	p = encode_fh(p, fhp);
++	fh_put(fhp);
++	return p;
+ }
+ 
+ static int
+diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
+index 9d536a8..aae2b29 100644
+--- a/fs/nfsd/nfs4callback.c
++++ b/fs/nfsd/nfs4callback.c
+@@ -350,30 +350,6 @@ static struct rpc_version *	nfs_cb_version[] = {
+ static int do_probe_callback(void *data)
+ {
+ 	struct nfs4_client *clp = data;
+-	struct nfs4_callback *cb = &clp->cl_callback;
+-	struct rpc_message msg = {
+-		.rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+-		.rpc_argp       = clp,
+-	};
+-	int status;
+-
+-	status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
+-
+-	if (status) {
+-		rpc_shutdown_client(cb->cb_client);
+-		cb->cb_client = NULL;
+-	} else
+-		atomic_set(&cb->cb_set, 1);
+-	put_nfs4_client(clp);
+-	return 0;
+-}
+-
+-/*
+- * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
+- */
+-void
+-nfsd4_probe_callback(struct nfs4_client *clp)
+-{
+ 	struct sockaddr_in	addr;
+ 	struct nfs4_callback    *cb = &clp->cl_callback;
+ 	struct rpc_timeout	timeparms = {
+@@ -390,13 +366,15 @@ nfsd4_probe_callback(struct nfs4_client *clp)
+ 		.timeout	= &timeparms,
+ 		.program	= program,
+ 		.version	= nfs_cb_version[1]->number,
+-		.authflavor	= RPC_AUTH_UNIX,	/* XXX: need AUTH_GSS... */
++		.authflavor	= RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
+ 		.flags		= (RPC_CLNT_CREATE_NOPING),
+ 	};
+-	struct task_struct *t;
+-
+-	if (atomic_read(&cb->cb_set))
+-		return;
++	struct rpc_message msg = {
++		.rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
++		.rpc_argp       = clp,
++	};
++	struct rpc_clnt *client;
++	int status;
+ 
+ 	/* Initialize address */
+ 	memset(&addr, 0, sizeof(addr));
+@@ -416,29 +394,50 @@ nfsd4_probe_callback(struct nfs4_client *clp)
+ 	program->stats->program = program;
+ 
+ 	/* Create RPC client */
+-	cb->cb_client = rpc_create(&args);
+-	if (IS_ERR(cb->cb_client)) {
++	client = rpc_create(&args);
++	if (IS_ERR(client)) {
+ 		dprintk("NFSD: couldn't create callback client\n");
++		status = PTR_ERR(client);
+ 		goto out_err;
+ 	}
+ 
++	status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
++
++	if (status)
++		goto out_release_client;
++
++	cb->cb_client = client;
++	atomic_set(&cb->cb_set, 1);
++	put_nfs4_client(clp);
++	return 0;
++out_release_client:
++	rpc_shutdown_client(client);
++out_err:
++	put_nfs4_client(clp);
++	dprintk("NFSD: warning: no callback path to client %.*s\n",
++		(int)clp->cl_name.len, clp->cl_name.data);
++	return status;
++}
++
++/*
++ * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
++ */
++void
++nfsd4_probe_callback(struct nfs4_client *clp)
++{
++	struct task_struct *t;
++
++	BUG_ON(atomic_read(&clp->cl_callback.cb_set));
++
+ 	/* the task holds a reference to the nfs4_client struct */
+ 	atomic_inc(&clp->cl_count);
+ 
+ 	t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
+ 
+ 	if (IS_ERR(t))
+-		goto out_release_clp;
++		atomic_dec(&clp->cl_count);
+ 
+ 	return;
+-
+-out_release_clp:
+-	atomic_dec(&clp->cl_count);
+-	rpc_shutdown_client(cb->cb_client);
+-out_err:
+-	cb->cb_client = NULL;
+-	dprintk("NFSD: warning: no callback path to client %.*s\n",
+-		(int)clp->cl_name.len, clp->cl_name.data);
+ }
+ 
+ /*
+@@ -458,9 +457,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
+ 	int retries = 1;
+ 	int status = 0;
+ 
+-	if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
+-		return;
+-
+ 	cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
+ 	cbr->cbr_dp = dp;
+ 
+@@ -469,6 +465,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
+ 		switch (status) {
+ 			case -EIO:
+ 				/* Network partition? */
++				atomic_set(&clp->cl_callback.cb_set, 0);
+ 			case -EBADHANDLE:
+ 			case -NFS4ERR_BAD_STATEID:
+ 				/* Race: client probably got cb_recall
+@@ -481,11 +478,10 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
+ 		status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+ 	}
+ out_put_cred:
+-	if (status == -EIO)
+-		atomic_set(&clp->cl_callback.cb_set, 0);
+-	/* Success or failure, now we're either waiting for lease expiration
+-	 * or deleg_return. */
+-	dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
++	/*
++	 * Success or failure, now we're either waiting for lease expiration
++	 * or deleg_return.
++	 */
+ 	put_nfs4_client(clp);
+ 	nfs4_put_delegation(dp);
+ 	return;
+diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
+index 4c0c683..996bd88 100644
+--- a/fs/nfsd/nfs4idmap.c
++++ b/fs/nfsd/nfs4idmap.c
+@@ -255,13 +255,10 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
+ 		goto out;
+ 	if (len == 0)
+ 		set_bit(CACHE_NEGATIVE, &ent.h.flags);
+-	else {
+-		if (error >= IDMAP_NAMESZ) {
+-			error = -EINVAL;
+-			goto out;
+-		}
++	else if (len >= IDMAP_NAMESZ)
++		goto out;
++	else
+ 		memcpy(ent.name, buf1, sizeof(ent.name));
+-	}
+ 	error = -ENOMEM;
+ 	res = idtoname_update(&ent, res);
+ 	if (res == NULL)
+@@ -467,20 +464,25 @@ nametoid_update(struct ent *new, struct ent *old)
+  * Exported API
+  */
+ 
+-void
++int
+ nfsd_idmap_init(void)
+ {
+-	cache_register(&idtoname_cache);
+-	cache_register(&nametoid_cache);
++	int rv;
++
++	rv = cache_register(&idtoname_cache);
++	if (rv)
++		return rv;
++	rv = cache_register(&nametoid_cache);
++	if (rv)
++		cache_unregister(&idtoname_cache);
++	return rv;
+ }
+ 
+ void
+ nfsd_idmap_shutdown(void)
+ {
+-	if (cache_unregister(&idtoname_cache))
+-		printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
+-	if (cache_unregister(&nametoid_cache))
+-		printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
++	cache_unregister(&idtoname_cache);
++	cache_unregister(&nametoid_cache);
+ }
+ 
+ /*
+diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
+index 18ead17..c593db0 100644
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 				    cstate->current_fh.fh_export,
+ 				    cstate->current_fh.fh_dentry, buf,
+ 				    &count, verify->ve_bmval,
+-				    rqstp);
++				    rqstp, 0);
+ 
+ 	/* this means that nfsd4_encode_fattr() ran out of space */
+ 	if (status == nfserr_resource && count == 0)
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 31673cd..f6744bc 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -61,7 +61,6 @@ static time_t lease_time = 90;     /* default lease time */
+ static time_t user_lease_time = 90;
+ static time_t boot_time;
+ static int in_grace = 1;
+-static u32 current_clientid = 1;
+ static u32 current_ownerid = 1;
+ static u32 current_fileid = 1;
+ static u32 current_delegid = 1;
+@@ -340,21 +339,20 @@ STALE_CLIENTID(clientid_t *clid)
+  * This type of memory management is somewhat inefficient, but we use it
+  * anyway since SETCLIENTID is not a common operation.
+  */
+-static inline struct nfs4_client *
+-alloc_client(struct xdr_netobj name)
++static struct nfs4_client *alloc_client(struct xdr_netobj name)
+ {
+ 	struct nfs4_client *clp;
+ 
+-	if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
+-		if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
+-			memcpy(clp->cl_name.data, name.data, name.len);
+-			clp->cl_name.len = name.len;
+-		}
+-		else {
+-			kfree(clp);
+-			clp = NULL;
+-		}
++	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
++	if (clp == NULL)
++		return NULL;
++	clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
++	if (clp->cl_name.data == NULL) {
++		kfree(clp);
++		return NULL;
+ 	}
++	memcpy(clp->cl_name.data, name.data, name.len);
++	clp->cl_name.len = name.len;
+ 	return clp;
+ }
+ 
+@@ -363,8 +361,11 @@ shutdown_callback_client(struct nfs4_client *clp)
+ {
+ 	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+ 
+-	/* shutdown rpc client, ending any outstanding recall rpcs */
+ 	if (clnt) {
++		/*
++		 * Callback threads take a reference on the client, so there
++		 * should be no outstanding callbacks at this point.
++		 */
+ 		clp->cl_callback.cb_client = NULL;
+ 		rpc_shutdown_client(clnt);
+ 	}
+@@ -422,12 +423,13 @@ expire_client(struct nfs4_client *clp)
+ 	put_nfs4_client(clp);
+ }
+ 
+-static struct nfs4_client *
+-create_client(struct xdr_netobj name, char *recdir) {
++static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
++{
+ 	struct nfs4_client *clp;
+ 
+-	if (!(clp = alloc_client(name)))
+-		goto out;
++	clp = alloc_client(name);
++	if (clp == NULL)
++		return NULL;
+ 	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
+ 	atomic_set(&clp->cl_count, 1);
+ 	atomic_set(&clp->cl_callback.cb_set, 0);
+@@ -436,32 +438,30 @@ create_client(struct xdr_netobj name, char *recdir) {
+ 	INIT_LIST_HEAD(&clp->cl_openowners);
+ 	INIT_LIST_HEAD(&clp->cl_delegations);
+ 	INIT_LIST_HEAD(&clp->cl_lru);
+-out:
+ 	return clp;
+ }
+ 
+-static void
+-copy_verf(struct nfs4_client *target, nfs4_verifier *source) {
+-	memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data));
++static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
++{
++	memcpy(target->cl_verifier.data, source->data,
++			sizeof(target->cl_verifier.data));
+ }
+ 
+-static void
+-copy_clid(struct nfs4_client *target, struct nfs4_client *source) {
++static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
++{
+ 	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 
+ 	target->cl_clientid.cl_id = source->cl_clientid.cl_id; 
+ }
+ 
+-static void
+-copy_cred(struct svc_cred *target, struct svc_cred *source) {
+-
++static void copy_cred(struct svc_cred *target, struct svc_cred *source)
++{
+ 	target->cr_uid = source->cr_uid;
+ 	target->cr_gid = source->cr_gid;
+ 	target->cr_group_info = source->cr_group_info;
+ 	get_group_info(target->cr_group_info);
+ }
+ 
+-static inline int
+-same_name(const char *n1, const char *n2)
++static int same_name(const char *n1, const char *n2)
+ {
+ 	return 0 == memcmp(n1, n2, HEXDIR_LEN);
+ }
+@@ -485,26 +485,26 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
+ 	return cr1->cr_uid == cr2->cr_uid;
+ }
+ 
+-static void
+-gen_clid(struct nfs4_client *clp) {
++static void gen_clid(struct nfs4_client *clp)
++{
++	static u32 current_clientid = 1;
++
+ 	clp->cl_clientid.cl_boot = boot_time;
+ 	clp->cl_clientid.cl_id = current_clientid++; 
+ }
+ 
+-static void
+-gen_confirm(struct nfs4_client *clp) {
+-	struct timespec 	tv;
+-	u32 *			p;
++static void gen_confirm(struct nfs4_client *clp)
++{
++	static u32 i;
++	u32 *p;
+ 
+-	tv = CURRENT_TIME;
+ 	p = (u32 *)clp->cl_confirm.data;
+-	*p++ = tv.tv_sec;
+-	*p++ = tv.tv_nsec;
++	*p++ = get_seconds();
++	*p++ = i++;
+ }
+ 
+-static int
+-check_name(struct xdr_netobj name) {
+-
++static int check_name(struct xdr_netobj name)
++{
+ 	if (name.len == 0) 
+ 		return 0;
+ 	if (name.len > NFS4_OPAQUE_LIMIT) {
+@@ -683,39 +683,6 @@ out_err:
+ 	return;
+ }
+ 
+-/*
+- * RFC 3010 has a complex implmentation description of processing a 
+- * SETCLIENTID request consisting of 5 bullets, labeled as 
+- * CASE0 - CASE4 below.
+- *
+- * NOTES:
+- * 	callback information will be processed in a future patch
+- *
+- *	an unconfirmed record is added when:
+- *      NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
+- *	CASE 1: confirmed record found with matching name, principal,
+- *		verifier, and clientid.
+- *	CASE 2: confirmed record found with matching name, principal,
+- *		and there is no unconfirmed record with matching
+- *		name and principal
+- *
+- *      an unconfirmed record is replaced when:
+- *	CASE 3: confirmed record found with matching name, principal,
+- *		and an unconfirmed record is found with matching 
+- *		name, principal, and with clientid and
+- *		confirm that does not match the confirmed record.
+- *	CASE 4: there is no confirmed record with matching name and 
+- *		principal. there is an unconfirmed record with 
+- *		matching name, principal.
+- *
+- *	an unconfirmed record is deleted when:
+- *	CASE 1: an unconfirmed record that matches input name, verifier,
+- *		and confirmed clientid.
+- *	CASE 4: any unconfirmed records with matching name and principal
+- *		that exist after an unconfirmed record has been replaced
+- *		as described above.
+- *
+- */
+ __be32
+ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 		  struct nfsd4_setclientid *setclid)
+@@ -748,11 +715,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 	nfs4_lock_state();
+ 	conf = find_confirmed_client_by_str(dname, strhashval);
+ 	if (conf) {
+-		/* 
+-		 * CASE 0:
+-		 * clname match, confirmed, different principal
+-		 * or different ip_address
+-		 */
++		/* RFC 3530 14.2.33 CASE 0: */
+ 		status = nfserr_clid_inuse;
+ 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
+ 				|| conf->cl_addr != sin->sin_addr.s_addr) {
+@@ -761,12 +724,17 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 			goto out;
+ 		}
+ 	}
++	/*
++	 * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
++	 * has a description of SETCLIENTID request processing consisting
++	 * of 5 bullet points, labeled as CASE0 - CASE4 below.
++	 */
+ 	unconf = find_unconfirmed_client_by_str(dname, strhashval);
+ 	status = nfserr_resource;
+ 	if (!conf) {
+-		/* 
+-		 * CASE 4:
+-		 * placed first, because it is the normal case.
++		/*
++		 * RFC 3530 14.2.33 CASE 4:
++		 * placed first, because it is the normal case
+ 		 */
+ 		if (unconf)
+ 			expire_client(unconf);
+@@ -776,17 +744,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 		gen_clid(new);
+ 	} else if (same_verf(&conf->cl_verifier, &clverifier)) {
+ 		/*
+-		 * CASE 1:
+-		 * cl_name match, confirmed, principal match
+-		 * verifier match: probable callback update
+-		 *
+-		 * remove any unconfirmed nfs4_client with 
+-		 * matching cl_name, cl_verifier, and cl_clientid
+-		 *
+-		 * create and insert an unconfirmed nfs4_client with same 
+-		 * cl_name, cl_verifier, and cl_clientid as existing 
+-		 * nfs4_client,  but with the new callback info and a 
+-		 * new cl_confirm
++		 * RFC 3530 14.2.33 CASE 1:
++		 * probable callback update
+ 		 */
+ 		if (unconf) {
+ 			/* Note this is removing unconfirmed {*x***},
+@@ -802,43 +761,25 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ 		copy_clid(new, conf);
+ 	} else if (!unconf) {
+ 		/*
+-		 * CASE 2:
+-		 * clname match, confirmed, principal match
+-		 * verfier does not match
+-		 * no unconfirmed. create a new unconfirmed nfs4_client
+-		 * using input clverifier, clname, and callback info
+-		 * and generate a new cl_clientid and cl_confirm.
++		 * RFC 3530 14.2.33 CASE 2:
++		 * probable client reboot; state will be removed if
++		 * confirmed.
+ 		 */
+ 		new = create_client(clname, dname);
+ 		if (new == NULL)
+ 			goto out;
+ 		gen_clid(new);
+-	} else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
+-		/*	
+-		 * CASE3:
+-		 * confirmed found (name, principal match)
+-		 * confirmed verifier does not match input clverifier
+-		 *
+-		 * unconfirmed found (name match)
+-		 * confirmed->cl_confirm != unconfirmed->cl_confirm
+-		 *
+-		 * remove unconfirmed.
+-		 *
+-		 * create an unconfirmed nfs4_client 
+-		 * with same cl_name as existing confirmed nfs4_client, 
+-		 * but with new callback info, new cl_clientid,
+-		 * new cl_verifier and a new cl_confirm
++	} else {
++		/*
++		 * RFC 3530 14.2.33 CASE 3:
++		 * probable client reboot; state will be removed if
++		 * confirmed.
+ 		 */
+ 		expire_client(unconf);
+ 		new = create_client(clname, dname);
+ 		if (new == NULL)
+ 			goto out;
+ 		gen_clid(new);
+-	} else {
+-		/* No cases hit !!! */
+-		status = nfserr_inval;
+-		goto out;
+-
+ 	}
+ 	copy_verf(new, &clverifier);
+ 	new->cl_addr = sin->sin_addr.s_addr;
+@@ -857,11 +798,9 @@ out:
+ 
+ 
+ /*
+- * RFC 3010 has a complex implmentation description of processing a 
+- * SETCLIENTID_CONFIRM request consisting of 4 bullets describing
+- * processing on a DRC miss, labeled as CASE1 - CASE4 below.
+- *
+- * NOTE: callback information will be processed here in a future patch
++ * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
++ * a description of SETCLIENTID_CONFIRM request processing consisting of 4
++ * bullets, labeled as CASE1 - CASE4 below.
+  */
+ __be32
+ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+@@ -892,16 +831,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ 	if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
+ 		goto out;
+ 
+-	if ((conf && unconf) && 
+-	    (same_verf(&unconf->cl_confirm, &confirm)) &&
+-	    (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
+-	    (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
+-	    (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+-		/* CASE 1:
+-		* unconf record that matches input clientid and input confirm.
+-		* conf record that matches input clientid.
+-		* conf and unconf records match names, verifiers
+-		*/
++	/*
++	 * section 14.2.34 of RFC 3530 has a description of
++	 * SETCLIENTID_CONFIRM request processing consisting
++	 * of 4 bullet points, labeled as CASE1 - CASE4 below.
++	 */
++	if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
++		/*
++		 * RFC 3530 14.2.34 CASE 1:
++		 * callback update
++		 */
+ 		if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
+ 			status = nfserr_clid_inuse;
+ 		else {
+@@ -914,15 +853,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ 			status = nfs_ok;
+ 
+ 		}
+-	} else if ((conf && !unconf) ||
+-	    ((conf && unconf) && 
+-	     (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
+-	      !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
+-		/* CASE 2:
+-		 * conf record that matches input clientid.
+-		 * if unconf record matches input clientid, then
+-		 * unconf->cl_name or unconf->cl_verifier don't match the
+-		 * conf record.
++	} else if (conf && !unconf) {
++		/*
++		 * RFC 3530 14.2.34 CASE 2:
++		 * probable retransmitted request; play it safe and
++		 * do nothing.
+ 		 */
+ 		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
+ 			status = nfserr_clid_inuse;
+@@ -930,10 +865,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ 			status = nfs_ok;
+ 	} else if (!conf && unconf
+ 			&& same_verf(&unconf->cl_confirm, &confirm)) {
+-		/* CASE 3:
+-		 * conf record not found.
+-		 * unconf record found.
+-		 * unconf->cl_confirm matches input confirm
++		/*
++		 * RFC 3530 14.2.34 CASE 3:
++		 * Normal case; new or rebooted client:
+ 		 */
+ 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
+ 			status = nfserr_clid_inuse;
+@@ -948,16 +882,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ 			}
+ 			move_to_confirmed(unconf);
+ 			conf = unconf;
++			nfsd4_probe_callback(conf);
+ 			status = nfs_ok;
+ 		}
+ 	} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
+ 	    && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
+ 				    				&confirm)))) {
+-		/* CASE 4:
+-		 * conf record not found, or if conf, conf->cl_confirm does not
+-		 * match input confirm.
+-		 * unconf record not found, or if unconf, unconf->cl_confirm
+-		 * does not match input confirm.
++		/*
++		 * RFC 3530 14.2.34 CASE 4:
++		 * Client probably hasn't noticed that we rebooted yet.
+ 		 */
+ 		status = nfserr_stale_clientid;
+ 	} else {
+@@ -965,8 +898,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+ 		status = nfserr_clid_inuse;
+ 	}
+ out:
+-	if (!status)
+-		nfsd4_probe_callback(conf);
+ 	nfs4_unlock_state();
+ 	return status;
+ }
+@@ -1226,14 +1157,19 @@ find_file(struct inode *ino)
+ 	return NULL;
+ }
+ 
+-static int access_valid(u32 x)
++static inline int access_valid(u32 x)
+ {
+-	return (x > 0 && x < 4);
++	if (x < NFS4_SHARE_ACCESS_READ)
++		return 0;
++	if (x > NFS4_SHARE_ACCESS_BOTH)
++		return 0;
++	return 1;
+ }
+ 
+-static int deny_valid(u32 x)
++static inline int deny_valid(u32 x)
+ {
+-	return (x >= 0 && x < 5);
++	/* Note: unlike access bits, deny bits may be zero. */
++	return x <= NFS4_SHARE_DENY_BOTH;
+ }
+ 
+ static void
+@@ -2162,8 +2098,10 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
+ 		goto check_replay;
+ 	}
+ 
++	*stpp = stp;
++	*sopp = sop = stp->st_stateowner;
++
+ 	if (lock) {
+-		struct nfs4_stateowner *sop = stp->st_stateowner;
+ 		clientid_t *lockclid = &lock->v.new.clientid;
+ 		struct nfs4_client *clp = sop->so_client;
+ 		int lkflg = 0;
+@@ -2193,9 +2131,6 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
+ 		return nfserr_bad_stateid;
+ 	}
+ 
+-	*stpp = stp;
+-	*sopp = sop = stp->st_stateowner;
+-
+ 	/*
+ 	*  We now validate the seqid and stateid generation numbers.
+ 	*  For the moment, we ignore the possibility of 
+diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
+index 5733394..b0592e7 100644
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -148,12 +148,12 @@ xdr_error:					\
+ 	}					\
+ } while (0)
+ 
+-static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
++static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
+ {
+ 	/* We want more bytes than seem to be available.
+ 	 * Maybe we need a new page, maybe we have just run out
+ 	 */
+-	int avail = (char*)argp->end - (char*)argp->p;
++	unsigned int avail = (char *)argp->end - (char *)argp->p;
+ 	__be32 *p;
+ 	if (avail + argp->pagelen < nbytes)
+ 		return NULL;
+@@ -169,6 +169,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+ 			return NULL;
+ 		
+ 	}
++	/*
++	 * The following memcpy is safe because read_buf is always
++	 * called with nbytes > avail, and the two cases above both
++	 * guarantee p points to at least nbytes bytes.
++	 */
+ 	memcpy(p, argp->p, avail);
+ 	/* step to next page */
+ 	argp->p = page_address(argp->pagelist[0]);
+@@ -1448,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+ __be32
+ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+ 		struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
+-		struct svc_rqst *rqstp)
++		struct svc_rqst *rqstp, int ignore_crossmnt)
+ {
+ 	u32 bmval0 = bmval[0];
+ 	u32 bmval1 = bmval[1];
+@@ -1828,7 +1833,12 @@ out_acl:
+ 	if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
+ 		if ((buflen -= 8) < 0)
+                 	goto out_resource;
+-		if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
++		/*
++		 * Get parent's attributes if not ignoring crossmount
++		 * and this is the root of a cross-mounted filesystem.
++		 */
++		if (ignore_crossmnt == 0 &&
++		    exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
+ 			err = vfs_getattr(exp->ex_mnt->mnt_parent,
+ 				exp->ex_mnt->mnt_mountpoint, &stat);
+ 			if (err)
+@@ -1864,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
+ 	struct svc_export *exp = cd->rd_fhp->fh_export;
+ 	struct dentry *dentry;
+ 	__be32 nfserr;
++	int ignore_crossmnt = 0;
+ 
+ 	dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
+ 	if (IS_ERR(dentry))
+ 		return nfserrno(PTR_ERR(dentry));
+ 
+ 	exp_get(exp);
+-	if (d_mountpoint(dentry)) {
++	/*
++	 * In the case of a mountpoint, the client may be asking for
++	 * attributes that are only properties of the underlying filesystem
++	 * as opposed to the cross-mounted file system. In such a case,
++	 * we will not follow the cross mount and will fill the attribtutes
++	 * directly from the mountpoint dentry.
++	 */
++	if (d_mountpoint(dentry) &&
++	    (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
++	    (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
++		ignore_crossmnt = 1;
++	else if (d_mountpoint(dentry)) {
+ 		int err;
+ 
+ 		/*
+@@ -1889,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
+ 
  	}
+ 	nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
+-					cd->rd_rqstp);
++					cd->rd_rqstp, ignore_crossmnt);
+ out_put:
+ 	dput(dentry);
+ 	exp_put(exp);
+@@ -2043,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
+ 	buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
+ 	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
+ 				    resp->p, &buflen, getattr->ga_bmval,
+-				    resp->rqstp);
++				    resp->rqstp, 0);
+ 	if (!nfserr)
+ 		resp->p += buflen;
+ 	return nfserr;
+diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
+index 578f2c9..5bfc2ac 100644
+--- a/fs/nfsd/nfscache.c
++++ b/fs/nfsd/nfscache.c
+@@ -44,17 +44,17 @@ static int	nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
+  */
+ static DEFINE_SPINLOCK(cache_lock);
  
-@@ -755,7 +753,7 @@ static void nfs_writepage_release(struct nfs_page *req)
- 	nfs_clear_page_tag_locked(req);
+-void
+-nfsd_cache_init(void)
++int nfsd_reply_cache_init(void)
+ {
+ 	struct svc_cacherep	*rp;
+ 	int			i;
+ 
+ 	INIT_LIST_HEAD(&lru_head);
+ 	i = CACHESIZE;
+-	while(i) {
++	while (i) {
+ 		rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+-		if (!rp) break;
++		if (!rp)
++			goto out_nomem;
+ 		list_add(&rp->c_lru, &lru_head);
+ 		rp->c_state = RC_UNUSED;
+ 		rp->c_type = RC_NOCACHE;
+@@ -62,23 +62,19 @@ nfsd_cache_init(void)
+ 		i--;
+ 	}
+ 
+-	if (i)
+-		printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
+-			CACHESIZE, CACHESIZE-i);
+-
+ 	hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
+-	if (!hash_list) {
+-		nfsd_cache_shutdown();
+-		printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
+-			HASHSIZE * sizeof(struct hlist_head));
+-		return;
+-	}
++	if (!hash_list)
++		goto out_nomem;
+ 
+ 	cache_disabled = 0;
++	return 0;
++out_nomem:
++	printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
++	nfsd_reply_cache_shutdown();
++	return -ENOMEM;
  }
  
--static inline int flush_task_priority(int how)
-+static int flush_task_priority(int how)
- {
- 	switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) {
- 		case FLUSH_HIGHPRI:
-@@ -775,15 +773,31 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
- 		unsigned int count, unsigned int offset,
- 		int how)
+-void
+-nfsd_cache_shutdown(void)
++void nfsd_reply_cache_shutdown(void)
  {
--	struct inode		*inode;
--	int flags;
-+	struct inode *inode = req->wb_context->path.dentry->d_inode;
-+	int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
-+	int priority = flush_task_priority(how);
-+	struct rpc_task *task;
-+	struct rpc_message msg = {
-+		.rpc_argp = &data->args,
-+		.rpc_resp = &data->res,
-+		.rpc_cred = req->wb_context->cred,
-+	};
-+	struct rpc_task_setup task_setup_data = {
-+		.rpc_client = NFS_CLIENT(inode),
-+		.task = &data->task,
-+		.rpc_message = &msg,
-+		.callback_ops = call_ops,
-+		.callback_data = data,
-+		.flags = flags,
-+		.priority = priority,
-+	};
- 
- 	/* Set up the RPC argument and reply structs
- 	 * NB: take care not to mess about with data->commit et al. */
+ 	struct svc_cacherep	*rp;
  
- 	data->req = req;
- 	data->inode = inode = req->wb_context->path.dentry->d_inode;
--	data->cred = req->wb_context->cred;
-+	data->cred = msg.rpc_cred;
+diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
+index 77dc989..8516137 100644
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -304,6 +304,9 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
+ 	struct auth_domain *dom;
+ 	struct knfsd_fh fh;
  
- 	data->args.fh     = NFS_FH(inode);
- 	data->args.offset = req_offset(req) + offset;
-@@ -791,6 +805,12 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
- 	data->args.pages  = data->pagevec;
- 	data->args.count  = count;
- 	data->args.context = req->wb_context;
-+	data->args.stable  = NFS_UNSTABLE;
-+	if (how & FLUSH_STABLE) {
-+		data->args.stable = NFS_DATA_SYNC;
-+		if (!NFS_I(inode)->ncommit)
-+			data->args.stable = NFS_FILE_SYNC;
++	if (size == 0)
++		return -EINVAL;
++
+ 	if (buf[size-1] != '\n')
+ 		return -EINVAL;
+ 	buf[size-1] = 0;
+@@ -503,7 +506,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
+ 		int len = 0;
+ 		lock_kernel();
+ 		if (nfsd_serv)
+-			len = svc_sock_names(buf, nfsd_serv, NULL);
++			len = svc_xprt_names(nfsd_serv, buf, 0);
+ 		unlock_kernel();
+ 		return len;
+ 	}
+@@ -540,7 +543,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
+ 		}
+ 		return err < 0 ? err : 0;
+ 	}
+-	if (buf[0] == '-') {
++	if (buf[0] == '-' && isdigit(buf[1])) {
+ 		char *toclose = kstrdup(buf+1, GFP_KERNEL);
+ 		int len = 0;
+ 		if (!toclose)
+@@ -554,6 +557,53 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
+ 		kfree(toclose);
+ 		return len;
+ 	}
++	/*
++	 * Add a transport listener by writing it's transport name
++	 */
++	if (isalpha(buf[0])) {
++		int err;
++		char transport[16];
++		int port;
++		if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
++			err = nfsd_create_serv();
++			if (!err) {
++				err = svc_create_xprt(nfsd_serv,
++						      transport, port,
++						      SVC_SOCK_ANONYMOUS);
++				if (err == -ENOENT)
++					/* Give a reasonable perror msg for
++					 * bad transport string */
++					err = -EPROTONOSUPPORT;
++			}
++			return err < 0 ? err : 0;
++		}
++	}
++	/*
++	 * Remove a transport by writing it's transport name and port number
++	 */
++	if (buf[0] == '-' && isalpha(buf[1])) {
++		struct svc_xprt *xprt;
++		int err = -EINVAL;
++		char transport[16];
++		int port;
++		if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
++			if (port == 0)
++				return -EINVAL;
++			lock_kernel();
++			if (nfsd_serv) {
++				xprt = svc_find_xprt(nfsd_serv, transport,
++						     AF_UNSPEC, port);
++				if (xprt) {
++					svc_close_xprt(xprt);
++					svc_xprt_put(xprt);
++					err = 0;
++				} else
++					err = -ENOTCONN;
++			}
++			unlock_kernel();
++			return err < 0 ? err : 0;
++		}
 +	}
+ 	return -EINVAL;
+ }
  
- 	data->res.fattr   = &data->fattr;
- 	data->res.count   = count;
-@@ -798,12 +818,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
- 	nfs_fattr_init(&data->fattr);
+@@ -616,7 +666,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
+ 	char *recdir;
+ 	int len, status;
  
- 	/* Set up the initial task struct.  */
--	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
--	rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data);
--	NFS_PROTO(inode)->write_setup(data, how);
--
--	data->task.tk_priority = flush_task_priority(how);
--	data->task.tk_cookie = (unsigned long)inode;
-+	NFS_PROTO(inode)->write_setup(data, &msg);
+-	if (size > PATH_MAX || buf[size-1] != '\n')
++	if (size == 0 || size > PATH_MAX || buf[size-1] != '\n')
+ 		return -EINVAL;
+ 	buf[size-1] = 0;
  
- 	dprintk("NFS: %5u initiated write call "
- 		"(req %s/%Ld, %u bytes @ offset %Lu)\n",
-@@ -812,16 +827,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
- 		(long long)NFS_FILEID(inode),
- 		count,
- 		(unsigned long long)data->args.offset);
--}
--
--static void nfs_execute_write(struct nfs_write_data *data)
--{
--	struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
--	sigset_t oldset;
+@@ -674,6 +724,27 @@ static struct file_system_type nfsd_fs_type = {
+ 	.kill_sb	= kill_litter_super,
+ };
  
--	rpc_clnt_sigmask(clnt, &oldset);
--	rpc_execute(&data->task);
--	rpc_clnt_sigunmask(clnt, &oldset);
-+	task = rpc_run_task(&task_setup_data);
-+	if (!IS_ERR(task))
-+		rpc_put_task(task);
++#ifdef CONFIG_PROC_FS
++static int create_proc_exports_entry(void)
++{
++	struct proc_dir_entry *entry;
++
++	entry = proc_mkdir("fs/nfs", NULL);
++	if (!entry)
++		return -ENOMEM;
++	entry = create_proc_entry("fs/nfs/exports", 0, NULL);
++	if (!entry)
++		return -ENOMEM;
++	entry->proc_fops =  &exports_operations;
++	return 0;
++}
++#else /* CONFIG_PROC_FS */
++static int create_proc_exports_entry(void)
++{
++	return 0;
++}
++#endif
++
+ static int __init init_nfsd(void)
+ {
+ 	int retval;
+@@ -683,32 +754,43 @@ static int __init init_nfsd(void)
+ 	if (retval)
+ 		return retval;
+ 	nfsd_stat_init();	/* Statistics */
+-	nfsd_cache_init();	/* RPC reply cache */
+-	nfsd_export_init();	/* Exports table */
++	retval = nfsd_reply_cache_init();
++	if (retval)
++		goto out_free_stat;
++	retval = nfsd_export_init();
++	if (retval)
++		goto out_free_cache;
+ 	nfsd_lockd_init();	/* lockd->nfsd callbacks */
+-	nfsd_idmap_init();      /* Name to ID mapping */
+-	if (proc_mkdir("fs/nfs", NULL)) {
+-		struct proc_dir_entry *entry;
+-		entry = create_proc_entry("fs/nfs/exports", 0, NULL);
+-		if (entry)
+-			entry->proc_fops =  &exports_operations;
+-	}
++	retval = nfsd_idmap_init();
++	if (retval)
++		goto out_free_lockd;
++	retval = create_proc_exports_entry();
++	if (retval)
++		goto out_free_idmap;
+ 	retval = register_filesystem(&nfsd_fs_type);
+-	if (retval) {
+-		nfsd_export_shutdown();
+-		nfsd_cache_shutdown();
+-		remove_proc_entry("fs/nfs/exports", NULL);
+-		remove_proc_entry("fs/nfs", NULL);
+-		nfsd_stat_shutdown();
+-		nfsd_lockd_shutdown();
+-	}
++	if (retval)
++		goto out_free_all;
++	return 0;
++out_free_all:
++	remove_proc_entry("fs/nfs/exports", NULL);
++	remove_proc_entry("fs/nfs", NULL);
++out_free_idmap:
++	nfsd_idmap_shutdown();
++out_free_lockd:
++	nfsd_lockd_shutdown();
++	nfsd_export_shutdown();
++out_free_cache:
++	nfsd_reply_cache_shutdown();
++out_free_stat:
++	nfsd_stat_shutdown();
++	nfsd4_free_slabs();
+ 	return retval;
  }
  
- /*
-@@ -868,7 +877,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
- 				   wsize, offset, how);
- 		offset += wsize;
- 		nbytes -= wsize;
--		nfs_execute_write(data);
- 	} while (nbytes != 0);
+ static void __exit exit_nfsd(void)
+ {
+ 	nfsd_export_shutdown();
+-	nfsd_cache_shutdown();
++	nfsd_reply_cache_shutdown();
+ 	remove_proc_entry("fs/nfs/exports", NULL);
+ 	remove_proc_entry("fs/nfs", NULL);
+ 	nfsd_stat_shutdown();
+diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
+index 468f17a..8fbd2dc 100644
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -22,6 +22,7 @@
+ #include <linux/sunrpc/svc.h>
+ #include <linux/sunrpc/svcauth_gss.h>
+ #include <linux/nfsd/nfsd.h>
++#include "auth.h"
+ 
+ #define NFSDDBG_FACILITY		NFSDDBG_FH
+ 
+diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
+index 1190aea..9647b0f 100644
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -155,8 +155,8 @@ static int killsig;	/* signal that was used to kill last nfsd */
+ static void nfsd_last_thread(struct svc_serv *serv)
+ {
+ 	/* When last nfsd thread exits we need to do some clean-up */
+-	struct svc_sock *svsk;
+-	list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
++	struct svc_xprt *xprt;
++	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
+ 		lockd_down();
+ 	nfsd_serv = NULL;
+ 	nfsd_racache_shutdown();
+@@ -236,7 +236,7 @@ static int nfsd_init_socks(int port)
+ 
+ 	error = lockd_up(IPPROTO_UDP);
+ 	if (error >= 0) {
+-		error = svc_makesock(nfsd_serv, IPPROTO_UDP, port,
++		error = svc_create_xprt(nfsd_serv, "udp", port,
+ 					SVC_SOCK_DEFAULTS);
+ 		if (error < 0)
+ 			lockd_down();
+@@ -247,7 +247,7 @@ static int nfsd_init_socks(int port)
+ #ifdef CONFIG_NFSD_TCP
+ 	error = lockd_up(IPPROTO_TCP);
+ 	if (error >= 0) {
+-		error = svc_makesock(nfsd_serv, IPPROTO_TCP, port,
++		error = svc_create_xprt(nfsd_serv, "tcp", port,
+ 					SVC_SOCK_DEFAULTS);
+ 		if (error < 0)
+ 			lockd_down();
+diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
+index b86e365..61ad617 100644
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -15,6 +15,7 @@
+ #include <linux/nfsd/nfsd.h>
+ #include <linux/nfsd/xdr.h>
+ #include <linux/mm.h>
++#include "auth.h"
  
- 	return 0;
-@@ -916,7 +924,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
- 	/* Set up the argument struct */
- 	nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how);
+ #define NFSDDBG_FACILITY		NFSDDBG_XDR
  
--	nfs_execute_write(data);
- 	return 0;
-  out_bad:
- 	while (!list_empty(head)) {
-@@ -932,7 +939,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
- static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
- 				  struct inode *inode, int ioflags)
+@@ -62,10 +63,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
+  * no slashes or null bytes.
+  */
+ static __be32 *
+-decode_filename(__be32 *p, char **namp, int *lenp)
++decode_filename(__be32 *p, char **namp, unsigned int *lenp)
  {
--	int wsize = NFS_SERVER(inode)->wsize;
-+	size_t wsize = NFS_SERVER(inode)->wsize;
+ 	char		*name;
+-	int		i;
++	unsigned int	i;
  
- 	if (wsize < PAGE_CACHE_SIZE)
- 		nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
-@@ -1146,19 +1153,33 @@ static void nfs_commit_rpcsetup(struct list_head *head,
- 		struct nfs_write_data *data,
- 		int how)
- {
--	struct nfs_page		*first;
--	struct inode		*inode;
--	int flags;
-+	struct nfs_page *first = nfs_list_entry(head->next);
-+	struct inode *inode = first->wb_context->path.dentry->d_inode;
-+	int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
-+	int priority = flush_task_priority(how);
-+	struct rpc_task *task;
-+	struct rpc_message msg = {
-+		.rpc_argp = &data->args,
-+		.rpc_resp = &data->res,
-+		.rpc_cred = first->wb_context->cred,
-+	};
-+	struct rpc_task_setup task_setup_data = {
-+		.task = &data->task,
-+		.rpc_client = NFS_CLIENT(inode),
-+		.rpc_message = &msg,
-+		.callback_ops = &nfs_commit_ops,
-+		.callback_data = data,
-+		.flags = flags,
-+		.priority = priority,
-+	};
+ 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
+ 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
+@@ -78,10 +79,10 @@ decode_filename(__be32 *p, char **namp, int *lenp)
+ }
  
- 	/* Set up the RPC argument and reply structs
- 	 * NB: take care not to mess about with data->commit et al. */
+ static __be32 *
+-decode_pathname(__be32 *p, char **namp, int *lenp)
++decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
+ {
+ 	char		*name;
+-	int		i;
++	unsigned int	i;
  
- 	list_splice_init(head, &data->pages);
--	first = nfs_list_entry(data->pages.next);
--	inode = first->wb_context->path.dentry->d_inode;
+ 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
+ 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index d019918..cc75e4f 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -132,7 +132,7 @@ out:
  
- 	data->inode	  = inode;
--	data->cred	  = first->wb_context->cred;
-+	data->cred	  = msg.rpc_cred;
+ __be32
+ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-		   const char *name, int len,
++		   const char *name, unsigned int len,
+ 		   struct svc_export **exp_ret, struct dentry **dentry_ret)
+ {
+ 	struct svc_export	*exp;
+@@ -226,7 +226,7 @@ out_nfserr:
+  */
+ __be32
+ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+-					int len, struct svc_fh *resfh)
++				unsigned int len, struct svc_fh *resfh)
+ {
+ 	struct svc_export	*exp;
+ 	struct dentry		*dentry;
+@@ -1151,6 +1151,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ }
+ #endif /* CONFIG_NFSD_V3 */
  
- 	data->args.fh     = NFS_FH(data->inode);
- 	/* Note: we always request a commit of the entire inode */
-@@ -1170,14 +1191,13 @@ static void nfs_commit_rpcsetup(struct list_head *head,
- 	nfs_fattr_init(&data->fattr);
++__be32
++nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
++			struct iattr *iap)
++{
++	/*
++	 * Mode has already been set earlier in create:
++	 */
++	iap->ia_valid &= ~ATTR_MODE;
++	/*
++	 * Setting uid/gid works only for root.  Irix appears to
++	 * send along the gid on create when it tries to implement
++	 * setgid directories via NFS:
++	 */
++	if (current->fsuid != 0)
++		iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
++	if (iap->ia_valid)
++		return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
++	return 0;
++}
++
+ /*
+  * Create a file (regular, directory, device, fifo); UNIX sockets 
+  * not yet implemented.
+@@ -1167,6 +1187,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 	struct dentry	*dentry, *dchild = NULL;
+ 	struct inode	*dirp;
+ 	__be32		err;
++	__be32		err2;
+ 	int		host_err;
  
- 	/* Set up the initial task struct.  */
--	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
--	rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data);
--	NFS_PROTO(inode)->commit_setup(data, how);
-+	NFS_PROTO(inode)->commit_setup(data, &msg);
+ 	err = nfserr_perm;
+@@ -1257,16 +1278,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 	}
  
--	data->task.tk_priority = flush_task_priority(how);
--	data->task.tk_cookie = (unsigned long)inode;
--	
- 	dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
-+
-+	task = rpc_run_task(&task_setup_data);
-+	if (!IS_ERR(task))
-+		rpc_put_task(task);
- }
  
- /*
-@@ -1197,7 +1217,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
- 	/* Set up the argument struct */
- 	nfs_commit_rpcsetup(head, data, how);
+-	/* Set file attributes. Mode has already been set and
+-	 * setting uid/gid works only for root. Irix appears to
+-	 * send along the gid when it tries to implement setgid
+-	 * directories via NFS.
+-	 */
+-	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+-		__be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+-		if (err2)
+-			err = err2;
+-	}
++	err2 = nfsd_create_setattr(rqstp, resfhp, iap);
++	if (err2)
++		err = err2;
+ 	/*
+ 	 * Update the file handle to get the new inode info.
+ 	 */
+@@ -1295,6 +1309,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 	struct dentry	*dentry, *dchild = NULL;
+ 	struct inode	*dirp;
+ 	__be32		err;
++	__be32		err2;
+ 	int		host_err;
+ 	__u32		v_mtime=0, v_atime=0;
+ 
+@@ -1399,16 +1414,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 		iap->ia_atime.tv_nsec = 0;
+ 	}
+ 
+-	/* Set file attributes.
+-	 * Irix appears to send along the gid when it tries to
+-	 * implement setgid directories via NFS. Clear out all that cruft.
+-	 */
+  set_attr:
+-	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+- 		__be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+-		if (err2)
+-			err = err2;
+-	}
++	err2 = nfsd_create_setattr(rqstp, resfhp, iap);
++	if (err2)
++		err = err2;
  
--	nfs_execute_write(data);
- 	return 0;
-  out_bad:
- 	while (!list_empty(head)) {
+ 	/*
+ 	 * Update the filehandle to get the new inode info.
 diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
 index 9fb8132..4d4ce48 100644
 --- a/fs/ocfs2/Makefile
@@ -742219,7 +789681,7 @@
  
  	while (state) {
 diff --git a/fs/proc/base.c b/fs/proc/base.c
-index 7411bfb..9fa9708 100644
+index 7411bfb..3353748 100644
 --- a/fs/proc/base.c
 +++ b/fs/proc/base.c
 @@ -199,7 +199,7 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
@@ -742309,6 +789771,15 @@
  /* The badness from the OOM killer */
  unsigned long badness(struct task_struct *p, unsigned long uptime);
  static int proc_oom_score(struct task_struct *task, char *buffer)
+@@ -913,7 +984,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
+ 	if (!task)
+ 		return -ESRCH;
+ 	length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
+-				audit_get_loginuid(task->audit_context));
++				audit_get_loginuid(task));
+ 	put_task_struct(task);
+ 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+ }
 @@ -1020,6 +1091,7 @@ static const struct file_operations proc_fault_inject_operations = {
  };
  #endif
@@ -742619,7 +790090,7 @@
  		current->policy = SCHED_YIELD;
  		schedule();
 diff --git a/fs/splice.c b/fs/splice.c
-index 6bdcb61..1577a73 100644
+index 6bdcb61..4ee49e8 100644
 --- a/fs/splice.c
 +++ b/fs/splice.c
 @@ -254,11 +254,16 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
@@ -742670,30 +790141,28 @@
  	return in->f_op->splice_read(in, ppos, pipe, len, flags);
  }
  
-@@ -1033,7 +1031,11 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+@@ -1033,7 +1031,9 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
  			goto out_release;
  	}
  
 +done:
  	pipe->nrbufs = pipe->curbuf = 0;
-+	if (bytes > 0)
-+		file_accessed(in);
-+
++	file_accessed(in);
  	return bytes;
  
  out_release:
-@@ -1049,16 +1051,11 @@ out_release:
+@@ -1049,16 +1049,11 @@ out_release:
  			buf->ops = NULL;
  		}
  	}
 -	pipe->nrbufs = pipe->curbuf = 0;
--
+ 
 -	/*
 -	 * If we transferred some data, return the number of bytes:
 -	 */
 -	if (bytes > 0)
 -		return bytes;
- 
+-
 -	return ret;
 +	if (!bytes)
 +		bytes = ret;
@@ -742702,7 +790171,7 @@
  }
  EXPORT_SYMBOL(splice_direct_to_actor);
  
-@@ -1440,6 +1437,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
+@@ -1440,6 +1435,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
  		.partial = partial,
  		.flags = flags,
  		.ops = &user_page_pipe_buf_ops,
@@ -743041,6 +790510,19 @@
  extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
  /*
   * External Functions
+diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
+index 9512f04..b729e64 100644
+--- a/include/acpi/acpixf.h
++++ b/include/acpi/acpixf.h
+@@ -335,6 +335,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);
+ 
+ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void);
+ 
++acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
++
+ acpi_status acpi_leave_sleep_state(u8 sleep_state);
+ 
+ #endif				/* __ACXFACE_H__ */
 diff --git a/include/acpi/reboot.h b/include/acpi/reboot.h
 new file mode 100644
 index 0000000..8857f57
@@ -743068,6 +790550,17 @@
  #define flush_agp_cache() mb()
  
  /* Convert a physical address to an address suitable for the GART. */
+diff --git a/include/asm-alpha/socket.h b/include/asm-alpha/socket.h
+index 1fede7f..08c9793 100644
+--- a/include/asm-alpha/socket.h
++++ b/include/asm-alpha/socket.h
+@@ -60,4 +60,6 @@
+ #define SO_SECURITY_ENCRYPTION_TRANSPORT	20
+ #define SO_SECURITY_ENCRYPTION_NETWORK		21
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-alpha/tlbflush.h b/include/asm-alpha/tlbflush.h
 index eefab3f..b9e9147 100644
 --- a/include/asm-alpha/tlbflush.h
@@ -743640,10 +791133,10 @@
  #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
  #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
 diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
-index 7905496..55b07bd 100644
+index 7905496..dc189f0 100644
 --- a/include/asm-arm/arch-at91/board.h
 +++ b/include/asm-arm/arch-at91/board.h
-@@ -34,6 +34,7 @@
+@@ -34,12 +34,14 @@
  #include <linux/mtd/partitions.h>
  #include <linux/device.h>
  #include <linux/i2c.h>
@@ -743651,7 +791144,15 @@
  #include <linux/spi/spi.h>
  
   /* USB Device */
-@@ -71,7 +72,7 @@ struct at91_eth_data {
+ struct at91_udc_data {
+ 	u8	vbus_pin;		/* high == host powering us */
+-	u8	pullup_pin;		/* high == D+ pulled up */
++	u8	pullup_pin;		/* active == D+ pulled up */
++	u8	pullup_active_low;	/* true == pullup_pin is active low */
+ };
+ extern void __init at91_add_device_udc(struct at91_udc_data *data);
+ 
+@@ -71,7 +73,7 @@ struct at91_eth_data {
  };
  extern void __init at91_add_device_eth(struct at91_eth_data *data);
  
@@ -743660,7 +791161,7 @@
  #define eth_platform_data	at91_eth_data
  #endif
  
-@@ -101,13 +102,23 @@ extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_de
+@@ -101,13 +103,23 @@ extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_de
  extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
  
   /* Serial */
@@ -743685,7 +791186,7 @@
  
  struct atmel_uart_data {
  	short		use_dma_tx;	/* use transmit DMA? */
-@@ -116,6 +127,23 @@ struct atmel_uart_data {
+@@ -116,6 +128,23 @@ struct atmel_uart_data {
  };
  extern void __init at91_add_device_serial(void);
  
@@ -743709,7 +791210,7 @@
   /* LCD Controller */
  struct atmel_lcdfb_info;
  extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
-@@ -126,10 +154,12 @@ struct atmel_ac97_data {
+@@ -126,10 +155,12 @@ struct atmel_ac97_data {
  };
  extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
  
@@ -748078,6 +795579,20 @@
 +void __init arm_kprobe_decode_init(void);
 +
 +#endif /* _ARM_KPROBES_H */
+diff --git a/include/asm-arm/mach/udc_pxa2xx.h b/include/asm-arm/mach/udc_pxa2xx.h
+index ff0a957..f191e14 100644
+--- a/include/asm-arm/mach/udc_pxa2xx.h
++++ b/include/asm-arm/mach/udc_pxa2xx.h
+@@ -19,7 +19,9 @@ struct pxa2xx_udc_mach_info {
+ 	 * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
+ 	 * VBUS IRQ and omit the methods above.  Store the GPIO number
+ 	 * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
++	 * Note that sometimes the signals go through inverters...
+ 	 */
++	bool	gpio_vbus_inverted;
+ 	u16	gpio_vbus;			/* high == vbus present */
+ 	u16	gpio_pullup;			/* high == pullup activated */
+ };
 diff --git a/include/asm-arm/plat-s3c24xx/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
 index 2c59406..c78efe3 100644
 --- a/include/asm-arm/plat-s3c24xx/dma.h
@@ -748274,6 +795789,17 @@
  # ifdef CONFIG_CPU_V6
  #  ifdef CPU_NAME
  #   undef  MULTI_CPU
+diff --git a/include/asm-arm/socket.h b/include/asm-arm/socket.h
+index 65a1a64..6817be9 100644
+--- a/include/asm-arm/socket.h
++++ b/include/asm-arm/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h
 index d4f34dc..f1541af 100644
 --- a/include/asm-arm/traps.h
@@ -748632,6 +796158,17 @@
  #define __tagtable(tag, fn)						\
  	static struct tagtable __tagtable_##fn __tag = { tag, fn }
  
+diff --git a/include/asm-avr32/socket.h b/include/asm-avr32/socket.h
+index a0d0507..35863f2 100644
+--- a/include/asm-avr32/socket.h
++++ b/include/asm-avr32/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* __ASM_AVR32_SOCKET_H */
 diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
 index 184b574..07049f6 100644
 --- a/include/asm-avr32/thread_info.h
@@ -749625,6 +797162,18 @@
 +#endif
  
  #endif
+diff --git a/include/asm-blackfin/socket.h b/include/asm-blackfin/socket.h
+index 5213c96..2ca702e 100644
+--- a/include/asm-blackfin/socket.h
++++ b/include/asm-blackfin/socket.h
+@@ -50,4 +50,7 @@
+ #define SO_PASSSEC		34
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
++
++#define SO_MARK			36
++
+ #endif				/* _ASM_SOCKET_H */
 diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
 index ee1cbf7..f0e5f94 100644
 --- a/include/asm-blackfin/traps.h
@@ -749700,6 +797249,19 @@
  #define IDE_ARCH_ACK_INTR
  #define ide_ack_intr(hwif)	((hwif)->ack_intr(hwif))
  
+diff --git a/include/asm-cris/socket.h b/include/asm-cris/socket.h
+index 5b18dfd..9df0ca8 100644
+--- a/include/asm-cris/socket.h
++++ b/include/asm-cris/socket.h
+@@ -54,6 +54,8 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
+ 
+ 
 diff --git a/include/asm-frv/ide.h b/include/asm-frv/ide.h
 index f0bd2cb..8c9a540 100644
 --- a/include/asm-frv/ide.h
@@ -749717,6 +797279,18 @@
  #ifndef MAX_HWIFS
  #define MAX_HWIFS 8
  #endif
+diff --git a/include/asm-frv/socket.h b/include/asm-frv/socket.h
+index a823bef..e51ca67 100644
+--- a/include/asm-frv/socket.h
++++ b/include/asm-frv/socket.h
+@@ -52,5 +52,7 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
+ 
 diff --git a/include/asm-generic/bitops/ext2-non-atomic.h b/include/asm-generic/bitops/ext2-non-atomic.h
 index 1697404..63cf822 100644
 --- a/include/asm-generic/bitops/ext2-non-atomic.h
@@ -750058,6 +797632,17 @@
  		/* DWARF debug sections.
  		Symbols in the DWARF debugging sections are relative to
  		the beginning of the section so we begin them at 0.  */
+diff --git a/include/asm-h8300/socket.h b/include/asm-h8300/socket.h
+index 39911d8..da2520d 100644
+--- a/include/asm-h8300/socket.h
++++ b/include/asm-h8300/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
 index 81bcd5e..cd1cc39 100644
 --- a/include/asm-ia64/acpi.h
@@ -750182,6 +797767,17 @@
  
  #endif /* !__ASSEMBLY__ */
  
+diff --git a/include/asm-ia64/socket.h b/include/asm-ia64/socket.h
+index 9e42ce4..d5ef0aa 100644
+--- a/include/asm-ia64/socket.h
++++ b/include/asm-ia64/socket.h
+@@ -61,4 +61,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_IA64_SOCKET_H */
 diff --git a/include/asm-m32r/signal.h b/include/asm-m32r/signal.h
 index 9372586..1a60706 100644
 --- a/include/asm-m32r/signal.h
@@ -750195,6 +797791,17 @@
  
  #define ptrace_signal_deliver(regs, cookie)	do { } while (0)
  
+diff --git a/include/asm-m32r/socket.h b/include/asm-m32r/socket.h
+index 793d5d3..9a0e200 100644
+--- a/include/asm-m32r/socket.h
++++ b/include/asm-m32r/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_M32R_SOCKET_H */
 diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
 index 2976b5d..83d1f28 100644
 --- a/include/asm-m68k/bitops.h
@@ -750208,6 +797815,17 @@
  
  #endif /* __KERNEL__ */
  
+diff --git a/include/asm-m68k/socket.h b/include/asm-m68k/socket.h
+index 6d21b90..dbc64e9 100644
+--- a/include/asm-m68k/socket.h
++++ b/include/asm-m68k/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h
 index f8dfb7b..f43afe1 100644
 --- a/include/asm-m68knommu/bitops.h
@@ -750221,6 +797839,53 @@
  #include <asm-generic/bitops/minix.h>
  
  #endif /* __KERNEL__ */
+diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h
+index 163dcb1..29bc0aa 100644
+--- a/include/asm-m68knommu/cacheflush.h
++++ b/include/asm-m68knommu/cacheflush.h
+@@ -53,7 +53,7 @@ static inline void __flush_cache_all(void)
+ #endif /* CONFIG_M5407 */
+ #if defined(CONFIG_M527x) || defined(CONFIG_M528x)
+ 	__asm__ __volatile__ (
+-        	"movel	#0x81400100, %%d0\n\t"
++		"movel	#0x81000200, %%d0\n\t"
+         	"movec	%%d0, %%CACR\n\t"
+ 		"nop\n\t"
+ 		: : : "d0" );
+diff --git a/include/asm-m68knommu/mcfcache.h b/include/asm-m68knommu/mcfcache.h
+index 7b61a8a..c042634 100644
+--- a/include/asm-m68knommu/mcfcache.h
++++ b/include/asm-m68knommu/mcfcache.h
+@@ -60,7 +60,7 @@
+ 	nop
+ 	movel	#0x0000c020, %d0	/* Set SDRAM cached only */
+ 	movec	%d0, %ACR0
+-	movel	#0xff00c000, %d0	/* Cache Flash also */
++	movel	#0x00000000, %d0	/* No other regions cached */
+ 	movec	%d0, %ACR1
+ 	movel	#0x80000200, %d0	/* Setup cache mask */
+ 	movec	%d0, %CACR		/* Enable cache */
+diff --git a/include/asm-m68knommu/mcfuart.h b/include/asm-m68knommu/mcfuart.h
+index 873d080..1319a81 100644
+--- a/include/asm-m68knommu/mcfuart.h
++++ b/include/asm-m68knommu/mcfuart.h
+@@ -12,7 +12,6 @@
+ #define	mcfuart_h
+ /****************************************************************************/
+ 
+-
+ /*
+  *	Define the base address of the UARTS within the MBAR address
+  *	space.
+@@ -33,7 +32,7 @@
+ #define MCFUART_BASE2		0x240           /* Base address of UART2 */
+ #define MCFUART_BASE3		0x280           /* Base address of UART3 */
+ #elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+-#if defined(CONFIG_NETtel) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3)
++#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
+ #define MCFUART_BASE1		0x200           /* Base address of UART1 */
+ #define MCFUART_BASE2		0x1c0           /* Base address of UART2 */
+ #else
 diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h
 index 0bb7a93..569f80a 100644
 --- a/include/asm-mips/addrspace.h
@@ -750762,6 +798427,18 @@
  
  #define CFE_OK			 0
  #define CFE_ERR                 -1	/* generic error */
+diff --git a/include/asm-mips/mach-au1x00/au1xxx_ide.h b/include/asm-mips/mach-au1x00/au1xxx_ide.h
+index aef0edb..e4fe26c 100644
+--- a/include/asm-mips/mach-au1x00/au1xxx_ide.h
++++ b/include/asm-mips/mach-au1x00/au1xxx_ide.h
+@@ -74,7 +74,6 @@ typedef struct
+         struct dbdma_cmd        *dma_table_cpu;
+         dma_addr_t              dma_table_dma;
+ #endif
+-        struct device           *dev;
+ 	int			irq;
+ 	u32			regbase;
+ #ifdef CONFIG_PM
 diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h
 index a79e7ca..5b9fce7 100644
 --- a/include/asm-mips/mach-cobalt/cobalt.h
@@ -751520,6 +799197,19 @@
  /* common irq stuff */
  extern void (*sni_hwint)(void);
  extern struct irqaction sni_isa_irq;
+diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h
+index 9594568..63f6025 100644
+--- a/include/asm-mips/socket.h
++++ b/include/asm-mips/socket.h
+@@ -73,6 +73,8 @@ To add: #define SO_REUSEPORT 0x0200	/* Allow local address and port reuse.  */
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #ifdef __KERNEL__
+ 
+ /** sock_type - Socket types
 diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
 index fb41a8d..051e1af 100644
 --- a/include/asm-mips/stackframe.h
@@ -751753,6 +799443,17 @@
  #define flush_agp_cache()		mb()
  
  /* Convert a physical address to an address suitable for the GART. */
+diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h
+index 99e868f..69a7a0d 100644
+--- a/include/asm-parisc/socket.h
++++ b/include/asm-parisc/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_PEERSEC		0x401d
+ #define SO_PASSSEC		0x401e
+ 
++#define SO_MARK			0x401f
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-powerpc/8xx_immap.h b/include/asm-powerpc/8xx_immap.h
 index 1311cef..4b0e152 100644
 --- a/include/asm-powerpc/8xx_immap.h
@@ -756241,6 +803942,17 @@
  };
  
  #endif /*  _SMU_H */
+diff --git a/include/asm-powerpc/socket.h b/include/asm-powerpc/socket.h
+index 403e9fd..f5a4e16 100644
+--- a/include/asm-powerpc/socket.h
++++ b/include/asm-powerpc/socket.h
+@@ -59,4 +59,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif	/* _ASM_POWERPC_SOCKET_H */
 diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h
 index 48ad807..e8b493d 100644
 --- a/include/asm-powerpc/sparsemem.h
@@ -758985,6 +806697,17 @@
  #endif
  
  extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+diff --git a/include/asm-s390/socket.h b/include/asm-s390/socket.h
+index 1161ebe..c786ab6 100644
+--- a/include/asm-s390/socket.h
++++ b/include/asm-s390/socket.h
+@@ -60,4 +60,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
 index 3fd4382..df84ae9 100644
 --- a/include/asm-s390/spinlock.h
@@ -765953,6 +813676,17 @@
  };
  
  #endif /* __ASM_SH_SIGCONTEXT_H */
+diff --git a/include/asm-sh/socket.h b/include/asm-sh/socket.h
+index c48d6fc..6d4bf65 100644
+--- a/include/asm-sh/socket.h
++++ b/include/asm-sh/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* __ASM_SH_SOCKET_H */
 diff --git a/include/asm-sh/spi.h b/include/asm-sh/spi.h
 new file mode 100644
 index 0000000..e96f5b0
@@ -776418,6 +824152,19 @@
 -#define HOST_STACK_END_ADDR	(u.start_stack + u.u_ssize * NBPG)
 -
 -#endif /* __ASM_SH64_USER_H */
+diff --git a/include/asm-sparc/socket.h b/include/asm-sparc/socket.h
+index 7c14239..2e2bd0b 100644
+--- a/include/asm-sparc/socket.h
++++ b/include/asm-sparc/socket.h
+@@ -52,6 +52,8 @@
+ #define SO_TIMESTAMPNS		0x0021
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			0x0022
++
+ /* Security levels - as per NRL IPv6 - don't actually do anything */
+ #define SO_SECURITY_AUTHENTICATION		0x5001
+ #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
 diff --git a/include/asm-sparc64/agp.h b/include/asm-sparc64/agp.h
 index 58f8cb6..e9fcf0e 100644
 --- a/include/asm-sparc64/agp.h
@@ -776491,6 +824238,16 @@
 +#include <asm-generic/percpu.h>
  
  #endif /* __ARCH_SPARC64_PERCPU__ */
+diff --git a/include/asm-sparc64/socket.h b/include/asm-sparc64/socket.h
+index 986441d..44a625a 100644
+--- a/include/asm-sparc64/socket.h
++++ b/include/asm-sparc64/socket.h
+@@ -57,4 +57,5 @@
+ #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
+ #define SO_SECURITY_ENCRYPTION_NETWORK		0x5004
+ 
++#define SO_MARK			0x0022
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-um/asm.h b/include/asm-um/asm.h
 new file mode 100644
 index 0000000..af1269a
@@ -776527,6 +824284,17 @@
 +#include "asm/arch/nops.h"
 +
 +#endif
+diff --git a/include/asm-v850/socket.h b/include/asm-v850/socket.h
+index a4c2493..e199a2b 100644
+--- a/include/asm-v850/socket.h
++++ b/include/asm-v850/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* __V850_SOCKET_H__ */
 diff --git a/include/asm-x86/Kbuild b/include/asm-x86/Kbuild
 index 12db5a1..3c6f0f8 100644
 --- a/include/asm-x86/Kbuild
@@ -780747,10 +828515,10 @@
  
  static inline int is_compat_task(void)
 diff --git a/include/asm-x86/cpu.h b/include/asm-x86/cpu.h
-index b1bc7b1..85ece5f 100644
+index b1bc7b1..73f2ea8 100644
 --- a/include/asm-x86/cpu.h
 +++ b/include/asm-x86/cpu.h
-@@ -7,7 +7,7 @@
+@@ -7,11 +7,12 @@
  #include <linux/nodemask.h>
  #include <linux/percpu.h>
  
@@ -780758,7 +828526,13 @@
 +struct x86_cpu {
  	struct cpu cpu;
  };
- extern int arch_register_cpu(int num);
+-extern int arch_register_cpu(int num);
++
+ #ifdef CONFIG_HOTPLUG_CPU
++extern int arch_register_cpu(int num);
+ extern void arch_unregister_cpu(int);
+ #endif
+ 
 diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h
 index b7160a4..3fb7dfa 100644
 --- a/include/asm-x86/cpufeature.h
@@ -783237,10 +831011,10 @@
  #endif/*!__ASSEMBLY__*/
  #endif/*__E820_HEADER*/
 diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h
-index 0bd4787..51e4170 100644
+index 0bd4787..a560c4f 100644
 --- a/include/asm-x86/e820_64.h
 +++ b/include/asm-x86/e820_64.h
-@@ -11,6 +11,8 @@
+@@ -11,19 +11,25 @@
  #ifndef __E820_HEADER
  #define __E820_HEADER
  
@@ -783248,8 +831022,10 @@
 +
  #ifndef __ASSEMBLY__
  extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
- 				    unsigned size);
-@@ -19,11 +21,15 @@ extern void add_memory_region(unsigned long start, unsigned long size,
+-				    unsigned size);
++				    unsigned size, unsigned long align);
+ extern void add_memory_region(unsigned long start, unsigned long size, 
+ 			      int type);
  extern void setup_memory_region(void);
  extern void contig_e820_setup(void); 
  extern unsigned long e820_end_of_ram(void);
@@ -783273,7 +831049,7 @@
  extern struct e820map e820;
 +extern void update_e820(void);
 +
-+extern void reserve_early(unsigned long start, unsigned long end);
++extern void reserve_early(unsigned long start, unsigned long end, char *name);
 +extern void early_res_to_bootmem(void);
  
 -extern unsigned ebda_addr, ebda_size;
@@ -783809,7 +831585,7 @@
 -
 -#endif
 diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h
-index 1f4610e..62828d6 100644
+index 1f4610e..9d91926 100644
 --- a/include/asm-x86/futex.h
 +++ b/include/asm-x86/futex.h
 @@ -1,5 +1,135 @@
@@ -783849,7 +831625,7 @@
 +"1:	movl	%2, %0\n					\
 +	movl	%0, %3\n"					\
 +	insn "\n"						\
-+"2:	" LOCK_PREFIX "cmpxchgl %3, %2\n			\
++"2:	lock; cmpxchgl %3, %2\n					\
 +	jnz	1b\n						\
 +3:	.section .fixup,\"ax\"\n				\
 +4:	mov	%5, %1\n					\
@@ -783891,7 +831667,7 @@
 +		__futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
 +		break;
 +	case FUTEX_OP_ADD:
-+		__futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
++		__futex_atomic_op1("lock; xaddl %0, %2", ret, oldval,
 +				   uaddr, oparg);
 +		break;
 +	case FUTEX_OP_OR:
@@ -783930,8 +831706,8 @@
 +		return -EFAULT;
 +
 +	__asm__ __volatile__(
-+		"1:	" LOCK_PREFIX "cmpxchgl %3, %1		\n"
 +
++		"1:	lock; cmpxchgl %3, %1			\n"
 +		"2:	.section .fixup, \"ax\"			\n"
 +		"3:	mov     %2, %0				\n"
 +		"	jmp     2b				\n"
@@ -798997,6 +846773,17 @@
 -#endif /* !CONFIG_SMP */
  #endif
  
+diff --git a/include/asm-x86/socket.h b/include/asm-x86/socket.h
+index 99ca648..80af9c4 100644
+--- a/include/asm-x86/socket.h
++++ b/include/asm-x86/socket.h
+@@ -52,4 +52,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif /* _ASM_SOCKET_H */
 diff --git a/include/asm-x86/sparsemem.h b/include/asm-x86/sparsemem.h
 index 3f203b1..fa58cd5 100644
 --- a/include/asm-x86/sparsemem.h
@@ -802239,6 +850026,17 @@
   * Optimized RAID-5 checksumming functions for MMX and SSE.
   *
   * This program is free software; you can redistribute it and/or modify
+diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h
+index 1f5aeac..6100682 100644
+--- a/include/asm-xtensa/socket.h
++++ b/include/asm-xtensa/socket.h
+@@ -63,4 +63,6 @@
+ #define SO_TIMESTAMPNS		35
+ #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+ 
++#define SO_MARK			36
++
+ #endif	/* _XTENSA_SOCKET_H */
 diff --git a/include/crypto/aead.h b/include/crypto/aead.h
 new file mode 100644
 index 0000000..0edf949
@@ -803013,7 +850811,7 @@
 +#endif	/* _CRYPTO_SKCIPHER_H */
 +
 diff --git a/include/linux/Kbuild b/include/linux/Kbuild
-index f30fa92..85b2482 100644
+index f30fa92..c0f9bb7 100644
 --- a/include/linux/Kbuild
 +++ b/include/linux/Kbuild
 @@ -1,4 +1,5 @@
@@ -803062,7 +850860,15 @@
  header-y += limits.h
  header-y += lock_dlm_plock.h
  header-y += magic.h
-@@ -157,7 +158,6 @@ header-y += veth.h
+@@ -142,6 +143,7 @@ header-y += snmp.h
+ header-y += sockios.h
+ header-y += som.h
+ header-y += sound.h
++header-y += suspend_ioctls.h
+ header-y += taskstats.h
+ header-y += telephony.h
+ header-y += termios.h
+@@ -157,7 +159,6 @@ header-y += veth.h
  header-y += video_decoder.h
  header-y += video_encoder.h
  header-y += videotext.h
@@ -803070,7 +850876,7 @@
  header-y += x25.h
  
  unifdef-y += acct.h
-@@ -172,6 +172,7 @@ unifdef-y += atm.h
+@@ -172,6 +173,7 @@ unifdef-y += atm.h
  unifdef-y += atm_tcp.h
  unifdef-y += audit.h
  unifdef-y += auto_fs.h
@@ -803078,7 +850884,7 @@
  unifdef-y += binfmts.h
  unifdef-y += capability.h
  unifdef-y += capi.h
-@@ -213,7 +214,7 @@ unifdef-y += hdreg.h
+@@ -213,7 +215,7 @@ unifdef-y += hdreg.h
  unifdef-y += hiddev.h
  unifdef-y += hpet.h
  unifdef-y += i2c.h
@@ -803087,7 +850893,7 @@
  unifdef-y += icmp.h
  unifdef-y += icmpv6.h
  unifdef-y += if_addr.h
-@@ -228,7 +229,6 @@ unifdef-y += if_ltalk.h
+@@ -228,7 +230,6 @@ unifdef-y += if_ltalk.h
  unifdef-y += if_link.h
  unifdef-y += if_pppol2tp.h
  unifdef-y += if_pppox.h
@@ -803095,7 +850901,7 @@
  unifdef-y += if_tr.h
  unifdef-y += if_tun.h
  unifdef-y += if_vlan.h
-@@ -255,6 +255,7 @@ unifdef-y += kd.h
+@@ -255,6 +256,7 @@ unifdef-y += kd.h
  unifdef-y += kernelcapi.h
  unifdef-y += kernel.h
  unifdef-y += keyboard.h
@@ -803103,7 +850909,7 @@
  unifdef-y += llc.h
  unifdef-y += loop.h
  unifdef-y += lp.h
-@@ -348,6 +349,7 @@ unifdef-y += videodev.h
+@@ -348,6 +350,7 @@ unifdef-y += videodev.h
  unifdef-y += virtio_config.h
  unifdef-y += virtio_blk.h
  unifdef-y += virtio_net.h
@@ -803124,6 +850930,56 @@
  #else
  
  static inline u32 acpi_pm_read_early(void)
+diff --git a/include/linux/aspm.h b/include/linux/aspm.h
+new file mode 100644
+index 0000000..f41a698
+--- /dev/null
++++ b/include/linux/aspm.h
+@@ -0,0 +1,44 @@
++/*
++ *	aspm.h
++ *
++ *	PCI Express ASPM defines and function prototypes
++ *
++ *	Copyright (C) 2007 Intel Corp.
++ *		Zhang Yanmin (yanmin.zhang at intel.com)
++ *		Shaohua Li (shaohua.li at intel.com)
++ *
++ *	For more information, please consult the following manuals (look at
++ *	http://www.pcisig.com/ for how to get them):
++ *
++ *	PCI Express Specification
++ */
++
++#ifndef LINUX_ASPM_H
++#define LINUX_ASPM_H
++
++#include <linux/pci.h>
++
++#define PCIE_LINK_STATE_L0S	1
++#define PCIE_LINK_STATE_L1	2
++#define PCIE_LINK_STATE_CLKPM	4
++
++#ifdef CONFIG_PCIEASPM
++extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
++extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
++extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
++extern void pci_disable_link_state(struct pci_dev *pdev, int state);
++#else
++#define pcie_aspm_init_link_state(pdev)		do {} while (0)
++#define pcie_aspm_exit_link_state(pdev)		do {} while (0)
++#define pcie_aspm_pm_state_change(pdev)		do {} while (0)
++#define pci_disable_link_state(pdev, state)	do {} while (0)
++#endif
++
++#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */
++extern void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
++extern void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
++#else
++#define pcie_aspm_create_sysfs_dev_files(pdev)	do {} while (0)
++#define pcie_aspm_remove_sysfs_dev_files(pdev)	do {} while (0)
++#endif
++#endif /* LINUX_ASPM_H */
 diff --git a/include/linux/ata.h b/include/linux/ata.h
 index e672e80..78bbaca 100644
 --- a/include/linux/ata.h
@@ -803439,10 +851295,18 @@
  	int (*match)(struct attribute_container *, struct device *);
  #define	ATTRIBUTE_CONTAINER_NO_CLASSDEVS	0x01
 diff --git a/include/linux/audit.h b/include/linux/audit.h
-index c687816..bdd6f5d 100644
+index c687816..9715302 100644
 --- a/include/linux/audit.h
 +++ b/include/linux/audit.h
-@@ -115,6 +115,8 @@
+@@ -98,6 +98,7 @@
+ #define AUDIT_FD_PAIR		1317    /* audit record for pipe/socketpair */
+ #define AUDIT_OBJ_PID		1318	/* ptrace target */
+ #define AUDIT_TTY		1319	/* Input on an administrative TTY */
++#define AUDIT_EOE		1320	/* End of multi-record event */
+ 
+ #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
+ #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
+@@ -115,6 +116,8 @@
  #define AUDIT_MAC_IPSEC_ADDSPD	1413	/* Not used */
  #define AUDIT_MAC_IPSEC_DELSPD	1414	/* Not used */
  #define AUDIT_MAC_IPSEC_EVENT	1415	/* Audit an IPSec event */
@@ -803451,11 +851315,45 @@
  
  #define AUDIT_FIRST_KERN_ANOM_MSG   1700
  #define AUDIT_LAST_KERN_ANOM_MSG    1799
+@@ -407,7 +410,8 @@ extern unsigned int audit_serial(void);
+ extern void auditsc_get_stamp(struct audit_context *ctx,
+ 			      struct timespec *t, unsigned int *serial);
+ extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
+-extern uid_t audit_get_loginuid(struct audit_context *ctx);
++#define audit_get_loginuid(t) ((t)->loginuid)
++#define audit_get_sessionid(t) ((t)->sessionid)
+ extern void audit_log_task_context(struct audit_buffer *ab);
+ extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
+ extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+@@ -486,7 +490,8 @@ extern int audit_signals;
+ #define audit_inode_child(d,i,p) do { ; } while (0)
+ #define audit_core_dumps(i) do { ; } while (0)
+ #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
+-#define audit_get_loginuid(c) ({ -1; })
++#define audit_get_loginuid(t) (-1)
++#define audit_get_sessionid(t) (-1)
+ #define audit_log_task_context(b) do { ; } while (0)
+ #define audit_ipc_obj(i) ({ 0; })
+ #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
+@@ -520,9 +525,11 @@ extern void		    audit_log_end(struct audit_buffer *ab);
+ extern void		    audit_log_hex(struct audit_buffer *ab,
+ 					  const unsigned char *buf,
+ 					  size_t len);
+-extern const char *	    audit_log_untrustedstring(struct audit_buffer *ab,
++extern int		    audit_string_contains_control(const char *string,
++							  size_t len);
++extern void		    audit_log_untrustedstring(struct audit_buffer *ab,
+ 						      const char *string);
+-extern const char *	    audit_log_n_untrustedstring(struct audit_buffer *ab,
++extern void		    audit_log_n_untrustedstring(struct audit_buffer *ab,
+ 							size_t n,
+ 							const char *string);
+ extern void		    audit_log_d_path(struct audit_buffer *ab,
 diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
-index d18ee67..e18d419 100644
+index d18ee67..90392a9 100644
 --- a/include/linux/blkdev.h
 +++ b/include/linux/blkdev.h
-@@ -34,83 +34,10 @@ struct sg_io_hdr;
+@@ -34,85 +34,11 @@ struct sg_io_hdr;
  #define BLKDEV_MIN_RQ	4
  #define BLKDEV_MAX_RQ	128	/* Default maximum */
  
@@ -803539,9 +851437,11 @@
  struct io_context *get_io_context(gfp_t gfp_flags, int node);
 +struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
  void copy_io_context(struct io_context **pdst, struct io_context **psrc);
- void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
+-void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
  
-@@ -143,8 +70,6 @@ enum rq_cmd_type_bits {
+ struct request;
+ typedef void (rq_end_io_fn)(struct request *, int);
+@@ -143,8 +69,6 @@ enum rq_cmd_type_bits {
  	 * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
  	 * private REQ_LB opcodes to differentiate what type of request this is
  	 */
@@ -803550,7 +851450,7 @@
  	REQ_TYPE_ATA_TASKFILE,
  	REQ_TYPE_ATA_PC,
  };
-@@ -431,6 +356,8 @@ struct request_queue
+@@ -431,6 +355,8 @@ struct request_queue
  	unsigned int		max_segment_size;
  
  	unsigned long		seg_boundary_mask;
@@ -803559,7 +851459,7 @@
  	unsigned int		dma_alignment;
  
  	struct blk_queue_tag	*queue_tags;
-@@ -539,6 +466,8 @@ enum {
+@@ -539,6 +465,8 @@ enum {
  #define blk_fua_rq(rq)		((rq)->cmd_flags & REQ_FUA)
  #define blk_bidi_rq(rq)		((rq)->next_rq != NULL)
  #define blk_empty_barrier(rq)	(blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors)
@@ -803568,7 +851468,7 @@
  
  #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
  
-@@ -718,29 +647,32 @@ static inline void blk_run_address_space(struct address_space *mapping)
+@@ -718,29 +646,35 @@ static inline void blk_run_address_space(struct address_space *mapping)
  }
  
  /*
@@ -803588,15 +851488,18 @@
 -extern int end_that_request_first(struct request *, int, int);
 -extern int end_that_request_chunk(struct request *, int, int);
 -extern void end_that_request_last(struct request *, int);
-+extern int blk_end_request(struct request *rq, int error, int nr_bytes);
-+extern int __blk_end_request(struct request *rq, int error, int nr_bytes);
-+extern int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
-+				int bidi_bytes);
++extern int blk_end_request(struct request *rq, int error,
++				unsigned int nr_bytes);
++extern int __blk_end_request(struct request *rq, int error,
++				unsigned int nr_bytes);
++extern int blk_end_bidi_request(struct request *rq, int error,
++				unsigned int nr_bytes, unsigned int bidi_bytes);
  extern void end_request(struct request *, int);
  extern void end_queued_request(struct request *, int);
  extern void end_dequeued_request(struct request *, int);
-+extern int blk_end_request_callback(struct request *rq, int error, int nr_bytes,
-+				    int (drv_callback)(struct request *));
++extern int blk_end_request_callback(struct request *rq, int error,
++				unsigned int nr_bytes,
++				int (drv_callback)(struct request *));
  extern void blk_complete_request(struct request *);
  
  /*
@@ -803614,7 +851517,7 @@
  
  static inline void blkdev_dequeue_request(struct request *req)
  {
-@@ -762,10 +694,13 @@ extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
+@@ -762,10 +696,13 @@ extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
  extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
  extern void blk_queue_hardsect_size(struct request_queue *, unsigned short);
  extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b);
@@ -803628,7 +851531,7 @@
  extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
  extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
  extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
-@@ -837,12 +772,7 @@ static inline int bdev_hardsect_size(struct block_device *bdev)
+@@ -837,12 +774,7 @@ static inline int bdev_hardsect_size(struct block_device *bdev)
  
  static inline int queue_dma_alignment(struct request_queue *q)
  {
@@ -803642,7 +851545,7 @@
  }
  
  /* assumes size > 256 */
-@@ -895,6 +825,13 @@ static inline void exit_io_context(void)
+@@ -895,6 +827,13 @@ static inline void exit_io_context(void)
  {
  }
  
@@ -804110,7 +852013,7 @@
 +
 +#endif
 diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
-index c6d3e22..fcdc11b 100644
+index c6d3e22..a5cd204 100644
 --- a/include/linux/cdrom.h
 +++ b/include/linux/cdrom.h
 @@ -451,6 +451,7 @@ struct cdrom_generic_command
@@ -804131,6 +852034,27 @@
  /* This is listed as optional in ATAPI 2.6, but is (curiously) 
   * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
   * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
+@@ -1184,6 +1187,20 @@ struct media_event_desc {
+ 
+ extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med);
+ 
++static inline void lba_to_msf(int lba, u8 *m, u8 *s, u8 *f)
++{
++	lba += CD_MSF_OFFSET;
++	lba &= 0xffffff;  /* negative lbas use only 24 bits */
++	*m = lba / (CD_SECS * CD_FRAMES);
++	lba %= (CD_SECS * CD_FRAMES);
++	*s = lba / CD_FRAMES;
++	*f = lba % CD_FRAMES;
++}
++
++static inline int msf_to_lba(u8 m, u8 s, u8 f)
++{
++	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
++}
+ #endif  /* End of kernel only stuff */ 
+ 
+ #endif  /* _LINUX_CDROM_H */
 diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
 index 107787a..85778a4 100644
 --- a/include/linux/clocksource.h
@@ -806491,7 +854415,7 @@
  #define FLOCK_VERIFY_READ  1
  #define FLOCK_VERIFY_WRITE 2
 diff --git a/include/linux/futex.h b/include/linux/futex.h
-index 92d420f..1a15f8e 100644
+index 92d420f..90048fb 100644
 --- a/include/linux/futex.h
 +++ b/include/linux/futex.h
 @@ -1,8 +1,12 @@
@@ -806508,6 +854432,37 @@
  union ktime;
  
  /* Second argument to futex syscall */
+@@ -17,6 +21,8 @@ union ktime;
+ #define FUTEX_LOCK_PI		6
+ #define FUTEX_UNLOCK_PI		7
+ #define FUTEX_TRYLOCK_PI	8
++#define FUTEX_WAIT_BITSET	9
++#define FUTEX_WAKE_BITSET	10
+ 
+ #define FUTEX_PRIVATE_FLAG	128
+ #define FUTEX_CMD_MASK		~FUTEX_PRIVATE_FLAG
+@@ -29,6 +35,8 @@ union ktime;
+ #define FUTEX_LOCK_PI_PRIVATE	(FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+ #define FUTEX_UNLOCK_PI_PRIVATE	(FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+ #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
++#define FUTEX_WAIT_BITSET_PRIVATE	(FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
++#define FUTEX_WAKE_BITSET_PRIVATE	(FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
+ 
+ /*
+  * Support for robust futexes: the kernel cleans up held futexes at
+@@ -107,6 +115,12 @@ struct robust_list_head {
+  */
+ #define ROBUST_LIST_LIMIT	2048
+ 
++/*
++ * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a
++ * match of any bit.
++ */
++#define FUTEX_BITSET_MATCH_ANY	0xffffffff
++
+ #ifdef __KERNEL__
+ long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
+ 	      u32 __user *uaddr2, u32 val2, u32 val3);
 diff --git a/include/linux/genhd.h b/include/linux/genhd.h
 index a47b802..1dbea0a 100644
 --- a/include/linux/genhd.h
@@ -806766,6 +854721,25 @@
  
  /* ATA/ATAPI Commands pre T13 Spec */
  #define WIN_NOP				0x00
+diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h
+index 7974a47..e691921 100644
+--- a/include/linux/hdsmart.h
++++ b/include/linux/hdsmart.h
+@@ -17,6 +17,7 @@
+ #ifndef _LINUX_HDSMART_H
+ #define _LINUX_HDSMART_H
+ 
++#ifndef __KERNEL
+ #define OFFLINE_FULL_SCAN		0
+ #define SHORT_SELF_TEST			1
+ #define EXTEND_SELF_TEST		2
+@@ -120,5 +121,6 @@ typedef struct ata_smart_selftestlog_s {
+ 	unsigned char			resevered[2];
+ 	unsigned char			chksum;
+ } __attribute__ ((packed)) ata_smart_selftestlog_t;
++#endif /* __KERNEL__ *
+ 
+ #endif	/* _LINUX_HDSMART_H */
 diff --git a/include/linux/hid.h b/include/linux/hid.h
 index 6e35b92..3902690 100644
 --- a/include/linux/hid.h
@@ -807535,10 +855509,18 @@
 +#endif /*  __LINUX_I2C_TPS65010_H */
 +
 diff --git a/include/linux/ide.h b/include/linux/ide.h
-index 9a6a41e..27cb39d 100644
+index 9a6a41e..ec10b2a 100644
 --- a/include/linux/ide.h
 +++ b/include/linux/ide.h
-@@ -27,25 +27,10 @@
+@@ -9,7 +9,6 @@
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+ #include <linux/hdreg.h>
+-#include <linux/hdsmart.h>
+ #include <linux/blkdev.h>
+ #include <linux/proc_fs.h>
+ #include <linux/interrupt.h>
+@@ -27,25 +26,10 @@
  #include <asm/semaphore.h>
  #include <asm/mutex.h>
  
@@ -807568,7 +855550,7 @@
  #endif
  
  /*
-@@ -55,10 +40,6 @@
+@@ -55,10 +39,6 @@
   
  #define IDE_NO_IRQ		(-1)
  
@@ -807579,7 +855561,7 @@
  typedef unsigned char	byte;	/* used everywhere */
  
  /*
-@@ -103,8 +84,6 @@ typedef unsigned char	byte;	/* used everywhere */
+@@ -103,8 +83,6 @@ typedef unsigned char	byte;	/* used everywhere */
  #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
  #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
  
@@ -807588,7 +855570,7 @@
  #define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
  #define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
  #define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-@@ -128,7 +107,6 @@ typedef unsigned char	byte;	/* used everywhere */
+@@ -128,7 +106,6 @@ typedef unsigned char	byte;	/* used everywhere */
  #define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
  #define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
  #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
@@ -807596,7 +855578,7 @@
  
  #define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
  
-@@ -219,8 +197,11 @@ typedef struct hw_regs_s {
+@@ -219,8 +196,11 @@ typedef struct hw_regs_s {
  } hw_regs_t;
  
  struct hwif_s * ide_find_port(unsigned long);
@@ -807609,7 +855591,7 @@
  		    struct hwif_s **);
  
  void ide_setup_ports(	hw_regs_t *hw,
-@@ -327,47 +308,16 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw,
+@@ -327,47 +307,16 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw,
  typedef union {
  	unsigned all			: 8;
  	struct {
@@ -807657,7 +855639,7 @@
   * ATA-IDE Select Register, aka Device-Head
   *
   * head		: always zeros here
-@@ -398,131 +348,6 @@ typedef union {
+@@ -398,131 +347,6 @@ typedef union {
  } select_t, ata_select_t;
  
  /*
@@ -807789,7 +855771,7 @@
   * Status returned from various ide_ functions
   */
  typedef enum {
-@@ -568,7 +393,6 @@ typedef struct ide_drive_s {
+@@ -568,7 +392,6 @@ typedef struct ide_drive_s {
  	u8	state;			/* retry state */
  	u8	waiting_for_dma;	/* dma currently in progress */
  	u8	unmask;			/* okay to unmask other irqs */
@@ -807797,6 +855779,16 @@
  	u8	noflush;		/* don't attempt flushes */
  	u8	dsc_overlap;		/* DSC overlap */
  	u8	nice1;			/* give potential excess bandwidth */
+@@ -679,7 +502,8 @@ typedef struct hwif_s {
+ 
+ 	hwif_chipset_t chipset;	/* sub-module for tuning.. */
+ 
+-	struct pci_dev  *pci_dev;	/* for pci chipsets */
++	struct device *dev;
++
+ 	const struct ide_port_info *cds;	/* chipset device struct */
+ 
+ 	ide_ack_intr_t *ack_intr;
 @@ -701,36 +525,29 @@ typedef struct hwif_s {
  	void	(*pre_reset)(ide_drive_t *);
  	/* routine to reset controller after a disk reset */
@@ -807844,7 +855836,7 @@
  	unsigned long	dma_base;	/* base addr for dma ports */
  	unsigned long	dma_command;	/* dma command register */
  	unsigned long	dma_vendor1;	/* dma vendor 1 register */
-@@ -806,7 +622,6 @@ typedef struct hwif_s {
+@@ -806,15 +622,13 @@ typedef struct hwif_s {
  /*
   *  internal ide interrupt handler type
   */
@@ -807852,7 +855844,44 @@
  typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
  typedef int (ide_expiry_t)(ide_drive_t *);
  
-@@ -1020,7 +835,8 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+ typedef struct hwgroup_s {
+ 		/* irq handler, if active */
+ 	ide_startstop_t	(*handler)(ide_drive_t *);
+-		/* irq handler, suspended if active */
+-	ide_startstop_t	(*handler_save)(ide_drive_t *);
++
+ 		/* BOOL: protects all fields below */
+ 	volatile int busy;
+ 		/* BOOL: wake us up on timer expiry */
+@@ -829,25 +643,18 @@ typedef struct hwgroup_s {
+ 		/* ptr to current hwif in linked-list */
+ 	ide_hwif_t *hwif;
+ 
+-		/* for pci chipsets */
+-	struct pci_dev *pci_dev;
+-
+ 		/* current request */
+ 	struct request *rq;
++
+ 		/* failsafe timer */
+ 	struct timer_list timer;
+-		/* local copy of current write rq */
+-	struct request wrq;
+ 		/* timeout value during long polls */
+ 	unsigned long poll_timeout;
+ 		/* queried upon timeouts */
+ 	int (*expiry)(ide_drive_t *);
+-		/* ide_system_bus_speed */
+-	int pio_clock;
++
+ 	int req_gen;
+ 	int req_gen_timer;
+-
+-	unsigned char cmd_buf[4];
+ } ide_hwgroup_t;
+ 
+ typedef struct ide_driver_s ide_driver_t;
+@@ -1020,7 +827,8 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
  
  extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
  
@@ -807862,7 +855891,7 @@
  
  ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8);
  
-@@ -1054,60 +870,126 @@ extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
+@@ -1054,60 +862,124 @@ extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
  
  extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
  
@@ -808010,8 +856039,6 @@
 - */
 -extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
 +ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
-+
-+void task_end_request(ide_drive_t *, struct request *, u8);
  
 -extern ide_startstop_t set_multmode_intr(ide_drive_t *);
 -extern ide_startstop_t set_geometry_intr(ide_drive_t *);
@@ -808019,7 +856046,7 @@
 -extern ide_startstop_t task_no_data_intr(ide_drive_t *);
 -extern ide_startstop_t task_in_intr(ide_drive_t *);
 -extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
-+u8 wait_drive_not_busy(ide_drive_t *);
++void task_end_request(ide_drive_t *, struct request *, u8);
  
 -extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
 +int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
@@ -808027,7 +856054,7 @@
  
  int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
  int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
-@@ -1133,10 +1015,9 @@ extern void do_ide_request(struct request_queue *);
+@@ -1133,10 +1005,8 @@ extern void do_ide_request(struct request_queue *);
  
  void ide_init_disk(struct gendisk *, ide_drive_t *);
  
@@ -808036,21 +856063,24 @@
  #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 -extern void ide_scan_pcibus(int scan_direction) __init;
 +extern int ide_scan_direction;
-+int __init ide_scan_pcibus(void);
  extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
  #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
  #else
-@@ -1212,6 +1093,9 @@ enum {
+@@ -1212,6 +1082,13 @@ enum {
  	IDE_HFLAG_IO_32BIT		= (1 << 24),
  	/* unmask IRQs */
  	IDE_HFLAG_UNMASK_IRQS		= (1 << 25),
 +	IDE_HFLAG_ABUSE_SET_DMA_MODE	= (1 << 26),
 +	/* host is CY82C693 */
 +	IDE_HFLAG_CY82C693		= (1 << 27),
++	/* force host out of "simplex" mode */
++	IDE_HFLAG_CLEAR_SIMPLEX		= (1 << 28),
++	/* DSC overlap is unsupported */
++	IDE_HFLAG_NO_DSC		= (1 << 29),
  };
  
  #ifdef CONFIG_BLK_DEV_OFFBOARD
-@@ -1226,10 +1110,9 @@ struct ide_port_info {
+@@ -1226,10 +1103,9 @@ struct ide_port_info {
  	void			(*init_iops)(ide_hwif_t *);
  	void                    (*init_hwif)(ide_hwif_t *);
  	void			(*init_dma)(ide_hwif_t *, unsigned long);
@@ -808062,7 +856092,7 @@
  	u32			host_flags;
  	u8			pio_mask;
  	u8			swdma_mask;
-@@ -1264,7 +1147,9 @@ static inline u8 ide_max_dma_mode(ide_drive_t *drive)
+@@ -1264,21 +1140,21 @@ static inline u8 ide_max_dma_mode(ide_drive_t *drive)
  	return ide_find_dma_mode(drive, XFER_UDMA_6);
  }
  
@@ -808072,9 +856102,16 @@
  int ide_set_dma(ide_drive_t *);
  ide_startstop_t ide_dma_intr(ide_drive_t *);
  
-@@ -1275,10 +1160,7 @@ extern void ide_destroy_dmatable(ide_drive_t *);
++int ide_build_sglist(ide_drive_t *, struct request *);
++void ide_destroy_dmatable(ide_drive_t *);
++
+ #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+-extern int ide_build_sglist(ide_drive_t *, struct request *);
+ extern int ide_build_dmatable(ide_drive_t *, struct request *);
+-extern void ide_destroy_dmatable(ide_drive_t *);
  extern int ide_release_dma(ide_hwif_t *);
- extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+-extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
++extern void ide_setup_dma(ide_hwif_t *, unsigned long);
  
 -void ide_dma_host_off(ide_drive_t *);
 -void ide_dma_off_quietly(ide_drive_t *);
@@ -808084,7 +856121,7 @@
  extern int ide_dma_setup(ide_drive_t *);
  extern void ide_dma_start(ide_drive_t *);
  extern int __ide_dma_end(ide_drive_t *);
-@@ -1290,7 +1172,9 @@ extern void ide_dma_timeout(ide_drive_t *);
+@@ -1290,7 +1166,9 @@ extern void ide_dma_timeout(ide_drive_t *);
  static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
  static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
  static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
@@ -808094,7 +856131,15 @@
  static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
  static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
  #endif /* CONFIG_BLK_DEV_IDEDMA */
-@@ -1320,8 +1204,9 @@ extern void ide_unregister (unsigned int index);
+@@ -1313,6 +1191,7 @@ static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+ static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
+ #endif
+ 
++void ide_remove_port_from_hwgroup(ide_hwif_t *);
+ extern int ide_hwif_request_regions(ide_hwif_t *hwif);
+ extern void ide_hwif_release_regions(ide_hwif_t* hwif);
+ extern void ide_unregister (unsigned int index);
+@@ -1320,8 +1199,9 @@ extern void ide_unregister (unsigned int index);
  void ide_register_region(struct gendisk *);
  void ide_unregister_region(struct gendisk *);
  
@@ -808105,7 +856150,7 @@
  int ide_device_add(u8 idx[4]);
  
  static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
-@@ -1356,6 +1241,7 @@ static inline int ide_dev_is_sata(struct hd_driveid *id)
+@@ -1356,6 +1236,7 @@ static inline int ide_dev_is_sata(struct hd_driveid *id)
  	return 0;
  }
  
@@ -808113,6 +856158,22 @@
  u8 ide_dump_status(ide_drive_t *, const char *, u8);
  
  typedef struct ide_pio_timings_s {
+@@ -1405,9 +1286,14 @@ extern struct bus_type ide_bus_type;
+ #define ide_id_has_flush_cache_ext(id)	\
+ 	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
+ 
++static inline void ide_dump_identify(u8 *id)
++{
++	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0);
++}
++
+ static inline int hwif_to_node(ide_hwif_t *hwif)
+ {
+-	struct pci_dev *dev = hwif->pci_dev;
++	struct pci_dev *dev = to_pci_dev(hwif->dev);
+ 	return dev ? pcibus_to_node(dev->bus) : -1;
+ }
+ 
 @@ -1418,4 +1304,9 @@ static inline ide_drive_t *ide_get_paired_drive(ide_drive_t *drive)
  	return &hwif->drives[(drive->dn ^ 1) & 1];
  }
@@ -808810,10 +856871,19 @@
  
  #endif	/* _LINUX_IN_H */
 diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
-index d83fee2..8d9eaae 100644
+index d83fee2..fc4e3db 100644
 --- a/include/linux/inetdevice.h
 +++ b/include/linux/inetdevice.h
-@@ -44,7 +44,8 @@ struct in_device
+@@ -17,8 +17,6 @@ struct ipv4_devconf
+ 	DECLARE_BITMAP(state, __NET_IPV4_CONF_MAX - 1);
+ };
+ 
+-extern struct ipv4_devconf ipv4_devconf;
+-
+ struct in_device
+ {
+ 	struct net_device	*dev;
+@@ -44,7 +42,8 @@ struct in_device
  };
  
  #define IPV4_DEVCONF(cnf, attr) ((cnf).data[NET_IPV4_CONF_ ## attr - 1])
@@ -808823,7 +856893,7 @@
  
  static inline int ipv4_devconf_get(struct in_device *in_dev, int index)
  {
-@@ -71,16 +72,17 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
+@@ -71,16 +70,17 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
  	ipv4_devconf_set((in_dev), NET_IPV4_CONF_ ## attr, (val))
  
  #define IN_DEV_ANDCONF(in_dev, attr) \
@@ -808847,7 +856917,7 @@
  #define IN_DEV_RPFILTER(in_dev)		IN_DEV_ANDCONF((in_dev), RP_FILTER)
  #define IN_DEV_SOURCE_ROUTE(in_dev)	IN_DEV_ANDCONF((in_dev), \
  						       ACCEPT_SOURCE_ROUTE)
-@@ -127,15 +129,14 @@ struct in_ifaddr
+@@ -127,15 +127,14 @@ struct in_ifaddr
  extern int register_inetaddr_notifier(struct notifier_block *nb);
  extern int unregister_inetaddr_notifier(struct notifier_block *nb);
  
@@ -809073,10 +857143,24 @@
 +extern void __init init_ohci1394_dma_on_all_controllers(void);
 +#endif
 diff --git a/include/linux/init_task.h b/include/linux/init_task.h
-index cae35b6..e6b3f70 100644
+index cae35b6..f42663e 100644
 --- a/include/linux/init_task.h
 +++ b/include/linux/init_task.h
-@@ -132,9 +132,11 @@ extern struct group_info init_groups;
+@@ -114,6 +114,13 @@ extern struct group_info init_groups;
+ 	.pid = &init_struct_pid,				\
+ }
+ 
++#ifdef CONFIG_AUDITSYSCALL
++#define INIT_IDS \
++	.loginuid = -1, \
++	.sessionid = -1,
++#else
++#define INIT_IDS
++#endif
+ /*
+  *  INIT_TASK is used to set up the first task table, touch at
+  * your own risk!. Base=0, limit=0x1fffff (=2MB)
+@@ -132,9 +139,11 @@ extern struct group_info init_groups;
  	.cpus_allowed	= CPU_MASK_ALL,					\
  	.mm		= NULL,						\
  	.active_mm	= &init_mm,					\
@@ -809091,6 +857175,27 @@
  	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
  	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
  	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
+@@ -171,6 +180,7 @@ extern struct group_info init_groups;
+ 		[PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),		\
+ 	},								\
+ 	.dirties = INIT_PROP_LOCAL_SINGLE(dirties),			\
++	INIT_IDS							\
+ 	INIT_TRACE_IRQFLAGS						\
+ 	INIT_LOCKDEP							\
+ }
+diff --git a/include/linux/input.h b/include/linux/input.h
+index 2075d6d..056a17a 100644
+--- a/include/linux/input.h
++++ b/include/linux/input.h
+@@ -371,6 +371,8 @@ struct input_absinfo {
+ #define KEY_BRIGHTNESS_ZERO	244	/* brightness off, use ambient */
+ #define KEY_DISPLAY_OFF		245	/* display device to off state */
+ 
++#define KEY_WIMAX		246
++
+ #define BTN_MISC		0x100
+ #define BTN_0			0x100
+ #define BTN_1			0x101
 diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
 index 2306920..c3db4a0 100644
 --- a/include/linux/interrupt.h
@@ -809259,6 +857364,35 @@
  
  	return IOPRIO_CLASS_BE;
  }
+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
+index 5d35a4c..4aaefc3 100644
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -457,14 +457,22 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
+ #define inet_v6_ipv6only(__sk)		0
+ #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+ 
+-#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
+-	(((__sk)->sk_hash == (__hash))				&& \
++#define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&& \
+ 	 ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))  	&& \
+ 	 ((__sk)->sk_family		== AF_INET6)		&& \
+ 	 ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr))	&& \
+ 	 ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr))	&& \
+ 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ 
++#define INET6_TW_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif) \
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&& \
++	 (*((__portpair *)&(inet_twsk(__sk)->tw_dport)) == (__ports))	&& \
++	 ((__sk)->sk_family	       == PF_INET6)			&& \
++	 (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr)))	&& \
++	 (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_rcv_saddr, (__daddr))) && \
++	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
++
+ #endif /* __KERNEL__ */
+ 
+ #endif /* _IPV6_H */
 diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
 index 06ef114..2cbf6fd 100644
 --- a/include/linux/jbd2.h
@@ -811089,6 +859223,53 @@
  extern int	lockd_up(int proto);
  extern void	lockd_down(void);
  
+diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
+index e2d1ce3..4babb2a 100644
+--- a/include/linux/lockd/lockd.h
++++ b/include/linux/lockd/lockd.h
+@@ -173,14 +173,17 @@ void		  nlmclnt_next_cookie(struct nlm_cookie *);
+ /*
+  * Host cache
+  */
+-struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
+-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
++struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr_in *, int, int,
++					const char *, unsigned int);
++struct nlm_host  *nlmsvc_lookup_host(struct svc_rqst *, const char *,
++					unsigned int);
+ struct rpc_clnt * nlm_bind_host(struct nlm_host *);
+ void		  nlm_rebind_host(struct nlm_host *);
+ struct nlm_host * nlm_get_host(struct nlm_host *);
+ void		  nlm_release_host(struct nlm_host *);
+ void		  nlm_shutdown_hosts(void);
+-extern void	  nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
++extern void	  nlm_host_rebooted(const struct sockaddr_in *, const char *,
++					unsigned int, u32);
+ void		  nsm_release(struct nsm_handle *);
+ 
+ 
+diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
+index 83a1f9f..df18fa0 100644
+--- a/include/linux/lockd/xdr.h
++++ b/include/linux/lockd/xdr.h
+@@ -29,7 +29,7 @@ struct svc_rqst;
+ /* Lock info passed via NLM */
+ struct nlm_lock {
+ 	char *			caller;
+-	int			len; 	/* length of "caller" */
++	unsigned int		len; 	/* length of "caller" */
+ 	struct nfs_fh		fh;
+ 	struct xdr_netobj	oh;
+ 	u32			svid;
+@@ -78,7 +78,7 @@ struct nlm_res {
+  */
+ struct nlm_reboot {
+ 	char *		mon;
+-	int		len;
++	unsigned int	len;
+ 	u32		state;
+ 	__be32		addr;
+ 	__be32		vers;
 diff --git a/include/linux/m41t00.h b/include/linux/m41t00.h
 deleted file mode 100644
 index b423360..0000000
@@ -811441,6 +859622,27 @@
  extern int net_msg_cost;
  extern int net_msg_burst;
  #endif
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index b0813c3..047d432 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1414,12 +1414,16 @@ extern void		dev_set_rx_mode(struct net_device *dev);
+ extern void		__dev_set_rx_mode(struct net_device *dev);
+ extern int		dev_unicast_delete(struct net_device *dev, void *addr, int alen);
+ extern int		dev_unicast_add(struct net_device *dev, void *addr, int alen);
++extern int		dev_unicast_sync(struct net_device *to, struct net_device *from);
++extern void		dev_unicast_unsync(struct net_device *to, struct net_device *from);
+ extern int 		dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
+ extern int		dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
+ extern int		dev_mc_sync(struct net_device *to, struct net_device *from);
+ extern void		dev_mc_unsync(struct net_device *to, struct net_device *from);
+ extern int 		__dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
+ extern int		__dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
++extern int		__dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
++extern void		__dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
+ extern void		dev_set_promiscuity(struct net_device *dev, int inc);
+ extern void		dev_set_allmulti(struct net_device *dev, int inc);
+ extern void		netdev_state_change(struct net_device *dev);
 diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
 index 16adac6..d74e79b 100644
 --- a/include/linux/netfilter.h
@@ -811764,6 +859966,19 @@
  				  __be16 port);
  extern int (*set_sig_addr_hook) (struct sk_buff *skb,
  				 struct nf_conn *ct,
+diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h
+index 2343549..3bbde0c 100644
+--- a/include/linux/netfilter/nf_conntrack_pptp.h
++++ b/include/linux/netfilter/nf_conntrack_pptp.h
+@@ -4,7 +4,7 @@
+ 
+ #include <linux/netfilter/nf_conntrack_common.h>
+ 
+-extern const char *pptp_msg_name[];
++extern const char *const pptp_msg_name[];
+ 
+ /* state of the control session */
+ enum pptp_ctrlsess_state {
 diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h
 index 5cf2c11..768f78c 100644
 --- a/include/linux/netfilter/nf_conntrack_sctp.h
@@ -811776,6 +859991,23 @@
  };
  
  #endif /* _NF_CONNTRACK_SCTP_H */
+diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
+index 9fff197..8e5ce1c 100644
+--- a/include/linux/netfilter/nf_conntrack_sip.h
++++ b/include/linux/netfilter/nf_conntrack_sip.h
+@@ -30,9 +30,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
+ 				       struct nf_conntrack_expect *exp,
+ 				       const char *dptr);
+ 
+-extern int ct_sip_get_info(struct nf_conn *ct, const char *dptr, size_t dlen,
+-			   unsigned int *matchoff, unsigned int *matchlen,
+-			   enum sip_header_pos pos);
++extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
++                           size_t dlen, unsigned int *matchoff,
++                           unsigned int *matchlen, enum sip_header_pos pos);
+ extern int ct_sip_lnlen(const char *line, const char *limit);
+ extern const char *ct_sip_search(const char *needle, const char *haystack,
+ 				 size_t needle_len, size_t haystack_len,
 diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
 index 4affa3f..e3e1533 100644
 --- a/include/linux/netfilter/nfnetlink_conntrack.h
@@ -811818,7 +860050,7 @@
  	__NFULA_MAX
  };
 diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
-index 03e6ce9..b99ede5 100644
+index 03e6ce9..b2c62cc 100644
 --- a/include/linux/netfilter/x_tables.h
 +++ b/include/linux/netfilter/x_tables.h
 @@ -126,6 +126,49 @@ struct xt_counters_info
@@ -811871,6 +860103,33 @@
  #ifdef __KERNEL__
  
  #include <linux/netdevice.h>
+@@ -171,7 +214,7 @@ struct xt_match
+ 	/* Free to use by each match */
+ 	unsigned long data;
+ 
+-	char *table;
++	const char *table;
+ 	unsigned int matchsize;
+ 	unsigned int compatsize;
+ 	unsigned int hooks;
+@@ -218,7 +261,7 @@ struct xt_target
+ 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ 	struct module *me;
+ 
+-	char *table;
++	const char *table;
+ 	unsigned int targetsize;
+ 	unsigned int compatsize;
+ 	unsigned int hooks;
+@@ -234,7 +277,7 @@ struct xt_table
+ 	struct list_head list;
+ 
+ 	/* A unique name... */
+-	char name[XT_TABLE_MAXNAMELEN];
++	const char name[XT_TABLE_MAXNAMELEN];
+ 
+ 	/* What hooks you will enter on */
+ 	unsigned int valid_hooks;
 @@ -265,13 +308,16 @@ struct xt_table_info
  	unsigned int initial_entries;
  
@@ -811891,7 +860150,37 @@
  extern int xt_register_target(struct xt_target *target);
  extern void xt_unregister_target(struct xt_target *target);
  extern int xt_register_targets(struct xt_target *target, unsigned int n);
-@@ -378,9 +424,13 @@ struct compat_xt_counters_info
+@@ -289,9 +335,10 @@ extern int xt_check_target(const struct xt_target *target, unsigned short family
+ 			   unsigned int size, const char *table, unsigned int hook,
+ 			   unsigned short proto, int inv_proto);
+ 
+-extern int xt_register_table(struct xt_table *table,
+-			     struct xt_table_info *bootstrap,
+-			     struct xt_table_info *newinfo);
++extern struct xt_table *xt_register_table(struct net *net,
++					  struct xt_table *table,
++					  struct xt_table_info *bootstrap,
++					  struct xt_table_info *newinfo);
+ extern void *xt_unregister_table(struct xt_table *table);
+ 
+ extern struct xt_table_info *xt_replace_table(struct xt_table *table,
+@@ -306,11 +353,12 @@ extern struct xt_target *xt_request_find_target(int af, const char *name,
+ extern int xt_find_revision(int af, const char *name, u8 revision, int target,
+ 			    int *err);
+ 
+-extern struct xt_table *xt_find_table_lock(int af, const char *name);
++extern struct xt_table *xt_find_table_lock(struct net *net, int af,
++					   const char *name);
+ extern void xt_table_unlock(struct xt_table *t);
+ 
+-extern int xt_proto_init(int af);
+-extern void xt_proto_fini(int af);
++extern int xt_proto_init(struct net *net, int af);
++extern void xt_proto_fini(struct net *net, int af);
+ 
+ extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
+ extern void xt_free_table_info(struct xt_table_info *info);
+@@ -378,17 +426,21 @@ struct compat_xt_counters_info
  extern void xt_compat_lock(int af);
  extern void xt_compat_unlock(int af);
  
@@ -811903,10 +860192,21 @@
 -extern void xt_compat_match_from_user(struct xt_entry_match *m,
 -				      void **dstptr, int *size);
 +extern int xt_compat_match_from_user(struct xt_entry_match *m,
-+				     void **dstptr, int *size);
++				     void **dstptr, unsigned int *size);
  extern int xt_compat_match_to_user(struct xt_entry_match *m,
- 				   void __user **dstptr, int *size);
+-				   void __user **dstptr, int *size);
++				   void __user **dstptr, unsigned int *size);
  
+ extern int xt_compat_target_offset(struct xt_target *target);
+ extern void xt_compat_target_from_user(struct xt_entry_target *t,
+-				       void **dstptr, int *size);
++				       void **dstptr, unsigned int *size);
+ extern int xt_compat_target_to_user(struct xt_entry_target *t,
+-				    void __user **dstptr, int *size);
++				    void __user **dstptr, unsigned int *size);
+ 
+ #endif /* CONFIG_COMPAT */
+ #endif /* __KERNEL__ */
 diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/linux/netfilter/xt_CONNMARK.h
 index 9f74468..4e58ba4 100644
 --- a/include/linux/netfilter/xt_CONNMARK.h
@@ -812026,21 +860326,48 @@
 +
  #endif /*_XT_CONNMARK_H*/
 diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h
-index 70b6f71..d2492a3 100644
+index 70b6f71..f3fd83e 100644
 --- a/include/linux/netfilter/xt_conntrack.h
 +++ b/include/linux/netfilter/xt_conntrack.h
-@@ -6,7 +6,9 @@
+@@ -6,7 +6,6 @@
  #define _XT_CONNTRACK_H
  
  #include <linux/netfilter/nf_conntrack_tuple_common.h>
 -#include <linux/in.h>
-+#ifdef __KERNEL__
-+#	include <linux/in.h>
-+#endif
  
  #define XT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
  #define XT_CONNTRACK_STATE_INVALID (1 << 0)
-@@ -60,4 +62,16 @@ struct xt_conntrack_info
+@@ -16,14 +15,21 @@
+ #define XT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+ 
+ /* flags, invflags: */
+-#define XT_CONNTRACK_STATE	0x01
+-#define XT_CONNTRACK_PROTO	0x02
+-#define XT_CONNTRACK_ORIGSRC	0x04
+-#define XT_CONNTRACK_ORIGDST	0x08
+-#define XT_CONNTRACK_REPLSRC	0x10
+-#define XT_CONNTRACK_REPLDST	0x20
+-#define XT_CONNTRACK_STATUS	0x40
+-#define XT_CONNTRACK_EXPIRES	0x80
++enum {
++	XT_CONNTRACK_STATE        = 1 << 0,
++	XT_CONNTRACK_PROTO        = 1 << 1,
++	XT_CONNTRACK_ORIGSRC      = 1 << 2,
++	XT_CONNTRACK_ORIGDST      = 1 << 3,
++	XT_CONNTRACK_REPLSRC      = 1 << 4,
++	XT_CONNTRACK_REPLDST      = 1 << 5,
++	XT_CONNTRACK_STATUS       = 1 << 6,
++	XT_CONNTRACK_EXPIRES      = 1 << 7,
++	XT_CONNTRACK_ORIGSRC_PORT = 1 << 8,
++	XT_CONNTRACK_ORIGDST_PORT = 1 << 9,
++	XT_CONNTRACK_REPLSRC_PORT = 1 << 10,
++	XT_CONNTRACK_REPLDST_PORT = 1 << 11,
++	XT_CONNTRACK_DIRECTION    = 1 << 12,
++};
+ 
+ /* This is exposed to userspace, so remains frozen in time. */
+ struct ip_conntrack_old_tuple
+@@ -60,4 +66,18 @@ struct xt_conntrack_info
  	/* Inverse flags */
  	u_int8_t invflags;
  };
@@ -812052,8 +860379,10 @@
 +	union nf_inet_addr repldst_addr, repldst_mask;
 +	u_int32_t expires_min, expires_max;
 +	u_int16_t l4proto;
++	__be16 origsrc_port, origdst_port;
++	__be16 replsrc_port, repldst_port;
++	u_int16_t match_flags, invert_flags;
 +	u_int8_t state_mask, status_mask;
-+	u_int8_t match_flags, invert_flags;
 +};
 +
  #endif /*_XT_CONNTRACK_H*/
@@ -812073,10 +860402,32 @@
 +
  #endif /* _XT_DSCP_H */
 diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h
-index b4556b8..c19972e 100644
+index b4556b8..58b818e 100644
 --- a/include/linux/netfilter/xt_hashlimit.h
 +++ b/include/linux/netfilter/xt_hashlimit.h
-@@ -29,9 +29,9 @@ struct hashlimit_cfg {
+@@ -9,13 +9,16 @@
+ /* details of this structure hidden by the implementation */
+ struct xt_hashlimit_htable;
+ 
+-#define XT_HASHLIMIT_HASH_DIP	0x0001
+-#define XT_HASHLIMIT_HASH_DPT	0x0002
+-#define XT_HASHLIMIT_HASH_SIP	0x0004
+-#define XT_HASHLIMIT_HASH_SPT	0x0008
++enum {
++	XT_HASHLIMIT_HASH_DIP = 1 << 0,
++	XT_HASHLIMIT_HASH_DPT = 1 << 1,
++	XT_HASHLIMIT_HASH_SIP = 1 << 2,
++	XT_HASHLIMIT_HASH_SPT = 1 << 3,
++	XT_HASHLIMIT_INVERT   = 1 << 4,
++};
+ 
+ struct hashlimit_cfg {
+-	u_int32_t mode;	  /* bitmask of IPT_HASHLIMIT_HASH_* */
++	u_int32_t mode;	  /* bitmask of XT_HASHLIMIT_HASH_* */
+ 	u_int32_t avg;    /* Average secs between packets * scale */
+ 	u_int32_t burst;  /* Period multiplier for upper limit. */
+ 
+@@ -29,12 +32,36 @@ struct hashlimit_cfg {
  struct xt_hashlimit_info {
  	char name [IFNAMSIZ];		/* name */
  	struct hashlimit_cfg cfg;
@@ -812087,6 +860438,33 @@
  	union {
  		void *ptr;
  		struct xt_hashlimit_info *master;
+ 	} u;
+ };
++
++struct hashlimit_cfg1 {
++	u_int32_t mode;	  /* bitmask of XT_HASHLIMIT_HASH_* */
++	u_int32_t avg;    /* Average secs between packets * scale */
++	u_int32_t burst;  /* Period multiplier for upper limit. */
++
++	/* user specified */
++	u_int32_t size;		/* how many buckets */
++	u_int32_t max;		/* max number of entries */
++	u_int32_t gc_interval;	/* gc interval */
++	u_int32_t expire;	/* when do entries expire? */
++
++	u_int8_t srcmask, dstmask;
++};
++
++struct xt_hashlimit_mtinfo1 {
++	char name[IFNAMSIZ];
++	struct hashlimit_cfg1 cfg;
++
++	/* Used internally by the kernel */
++	struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
++	struct xt_hashlimit_mtinfo1 *master __attribute__((aligned(8)));
++};
++
+ #endif /*_XT_HASHLIMIT_H*/
 diff --git a/include/linux/netfilter/xt_iprange.h b/include/linux/netfilter/xt_iprange.h
 new file mode 100644
 index 0000000..a4299c7
@@ -812126,7 +860504,7 @@
  #endif /*_XT_MARK_H*/
 diff --git a/include/linux/netfilter/xt_owner.h b/include/linux/netfilter/xt_owner.h
 new file mode 100644
-index 0000000..eacd34e
+index 0000000..c84e52c
 --- /dev/null
 +++ b/include/linux/netfilter/xt_owner.h
 @@ -0,0 +1,16 @@
@@ -812140,8 +860518,8 @@
 +};
 +
 +struct xt_owner_match_info {
-+	u_int32_t uid;
-+	u_int32_t gid;
++	u_int32_t uid_min, uid_max;
++	u_int32_t gid_min, gid_max;
 +	u_int8_t match, invert;
 +};
 +
@@ -812268,7 +860646,7 @@
  };
  
 diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
-index 2fc73fa..53dd4df 100644
+index 2fc73fa..db223ca 100644
 --- a/include/linux/netfilter_arp/arp_tables.h
 +++ b/include/linux/netfilter_arp/arp_tables.h
 @@ -217,21 +217,8 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
@@ -812295,7 +860673,19 @@
  
  /*
   *	Main firewall chains definitions and global var's definitions.
-@@ -293,6 +280,37 @@ extern unsigned int arpt_do_table(struct sk_buff *skb,
+@@ -284,8 +271,9 @@ struct arpt_error
+  	xt_register_target(tgt); })
+ #define arpt_unregister_target(tgt) xt_unregister_target(tgt)
+ 
+-extern int arpt_register_table(struct arpt_table *table,
+-			       const struct arpt_replace *repl);
++extern struct arpt_table *arpt_register_table(struct net *net,
++					      struct arpt_table *table,
++					      const struct arpt_replace *repl);
+ extern void arpt_unregister_table(struct arpt_table *table);
+ extern unsigned int arpt_do_table(struct sk_buff *skb,
+ 				  unsigned int hook,
+@@ -293,6 +281,37 @@ extern unsigned int arpt_do_table(struct sk_buff *skb,
  				  const struct net_device *out,
  				  struct arpt_table *table);
  
@@ -812355,7 +860745,7 @@
  enum nf_ip_hook_priorities {
  	NF_IP_PRI_FIRST = INT_MIN,
 diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
-index d79ed69..45fcad9 100644
+index d79ed69..bfc889f 100644
 --- a/include/linux/netfilter_ipv4/ip_tables.h
 +++ b/include/linux/netfilter_ipv4/ip_tables.h
 @@ -156,10 +156,10 @@ struct ipt_getinfo
@@ -812449,7 +860839,19 @@
  
  /*
   *	Main firewall chains definitions and global var's definitions.
-@@ -359,8 +311,28 @@ struct compat_ipt_entry
+@@ -292,8 +244,9 @@ ipt_get_target(struct ipt_entry *e)
+ #include <linux/init.h>
+ extern void ipt_init(void) __init;
+ 
+-extern int ipt_register_table(struct xt_table *table,
+-			      const struct ipt_replace *repl);
++extern struct xt_table *ipt_register_table(struct net *net,
++					   struct xt_table *table,
++					   const struct ipt_replace *repl);
+ extern void ipt_unregister_table(struct xt_table *table);
+ 
+ /* Standard entry. */
+@@ -359,8 +312,28 @@ struct compat_ipt_entry
  	unsigned char elems[0];
  };
  
@@ -812554,7 +860956,7 @@
  
  enum nf_ip6_hook_priorities {
 diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
-index 7dc481c..110801d 100644
+index 7dc481c..f2507dc 100644
 --- a/include/linux/netfilter_ipv6/ip6_tables.h
 +++ b/include/linux/netfilter_ipv6/ip6_tables.h
 @@ -216,10 +216,10 @@ struct ip6t_getinfo
@@ -812628,7 +861030,19 @@
  
  /*
   *	Main firewall chains definitions and global var's definitions.
-@@ -352,7 +324,42 @@ extern int ip6_masked_addrcmp(const struct in6_addr *addr1,
+@@ -333,8 +305,9 @@ ip6t_get_target(struct ip6t_entry *e)
+ #include <linux/init.h>
+ extern void ip6t_init(void) __init;
+ 
+-extern int ip6t_register_table(struct xt_table *table,
+-			       const struct ip6t_replace *repl);
++extern struct xt_table *ip6t_register_table(struct net *net,
++					    struct xt_table *table,
++					    const struct ip6t_replace *repl);
+ extern void ip6t_unregister_table(struct xt_table *table);
+ extern unsigned int ip6t_do_table(struct sk_buff *skb,
+ 				  unsigned int hook,
+@@ -352,7 +325,42 @@ extern int ip6_masked_addrcmp(const struct in6_addr *addr1,
  			      const struct in6_addr *mask,
  			      const struct in6_addr *addr2);
  
@@ -812673,7 +861087,7 @@
  #endif /*__KERNEL__*/
  #endif /* _IP6_TABLES_H */
 diff --git a/include/linux/netlink.h b/include/linux/netlink.h
-index d5bfaba..bd13b6f 100644
+index d5bfaba..fb0713b 100644
 --- a/include/linux/netlink.h
 +++ b/include/linux/netlink.h
 @@ -178,6 +178,7 @@ extern struct sock *netlink_kernel_create(struct net *net,
@@ -812684,6 +861098,15 @@
  extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
  extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group);
  extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+@@ -218,7 +219,7 @@ struct netlink_callback
+ 	int		(*dump)(struct sk_buff * skb, struct netlink_callback *cb);
+ 	int		(*done)(struct netlink_callback *cb);
+ 	int		family;
+-	long		args[5];
++	long		args[6];
+ };
+ 
+ struct netlink_notify
 @@ -245,7 +246,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
  }
  
@@ -813012,6 +861435,265 @@
  	int	(*commit_done) (struct rpc_task *, struct nfs_write_data *);
  	int	(*file_open)   (struct inode *, struct file *);
  	int	(*file_release) (struct inode *, struct file *);
+diff --git a/include/linux/nfsd/Kbuild b/include/linux/nfsd/Kbuild
+index d9c5455..e726fc3 100644
+--- a/include/linux/nfsd/Kbuild
++++ b/include/linux/nfsd/Kbuild
+@@ -4,4 +4,3 @@ unifdef-y += stats.h
+ unifdef-y += syscall.h
+ unifdef-y += nfsfh.h
+ unifdef-y += debug.h
+-unifdef-y += auth.h
+diff --git a/include/linux/nfsd/auth.h b/include/linux/nfsd/auth.h
+deleted file mode 100644
+index 0fb9f72..0000000
+--- a/include/linux/nfsd/auth.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * include/linux/nfsd/auth.h
+- *
+- * nfsd-specific authentication stuff.
+- * uid/gid mapping not yet implemented.
+- *
+- * Copyright (C) 1995, 1996 Olaf Kirch <okir at monad.swb.de>
+- */
+-
+-#ifndef LINUX_NFSD_AUTH_H
+-#define LINUX_NFSD_AUTH_H
+-
+-#ifdef __KERNEL__
+-
+-#define nfsd_luid(rq, uid)	((u32)(uid))
+-#define nfsd_lgid(rq, gid)	((u32)(gid))
+-#define nfsd_ruid(rq, uid)	((u32)(uid))
+-#define nfsd_rgid(rq, gid)	((u32)(gid))
+-
+-/*
+- * Set the current process's fsuid/fsgid etc to those of the NFS
+- * client user
+- */
+-int nfsd_setuser(struct svc_rqst *, struct svc_export *);
+-
+-#endif /* __KERNEL__ */
+-#endif /* LINUX_NFSD_AUTH_H */
+diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
+index 007480c..7b5d784 100644
+--- a/include/linux/nfsd/cache.h
++++ b/include/linux/nfsd/cache.h
+@@ -72,8 +72,8 @@ enum {
+  */
+ #define RC_DELAY		(HZ/5)
+ 
+-void	nfsd_cache_init(void);
+-void	nfsd_cache_shutdown(void);
++int	nfsd_reply_cache_init(void);
++void	nfsd_reply_cache_shutdown(void);
+ int	nfsd_cache_lookup(struct svc_rqst *, int);
+ void	nfsd_cache_update(struct svc_rqst *, int, __be32 *);
+ 
+diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
+index bcb7aba..3a16872 100644
+--- a/include/linux/nfsd/export.h
++++ b/include/linux/nfsd/export.h
+@@ -122,7 +122,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
+ /*
+  * Function declarations
+  */
+-void			nfsd_export_init(void);
++int			nfsd_export_init(void);
+ void			nfsd_export_shutdown(void);
+ void			nfsd_export_flush(void);
+ void			exp_readlock(void);
+diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
+index 604a0d7..8caf4c4 100644
+--- a/include/linux/nfsd/nfsd.h
++++ b/include/linux/nfsd/nfsd.h
+@@ -20,7 +20,6 @@
+ #include <linux/nfsd/debug.h>
+ #include <linux/nfsd/nfsfh.h>
+ #include <linux/nfsd/export.h>
+-#include <linux/nfsd/auth.h>
+ #include <linux/nfsd/stats.h>
+ /*
+  * nfsd version
+@@ -70,9 +69,9 @@ void		nfsd_racache_shutdown(void);
+ int		nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
+ 		                struct svc_export **expp);
+ __be32		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
+-				const char *, int, struct svc_fh *);
++				const char *, unsigned int, struct svc_fh *);
+ __be32		 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
+-				const char *, int,
++				const char *, unsigned int,
+ 				struct svc_export **, struct dentry **);
+ __be32		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
+ 				struct iattr *, int, time_t);
+diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
+index 8bcddcc..4e43976 100644
+--- a/include/linux/nfsd/syscall.h
++++ b/include/linux/nfsd/syscall.h
+@@ -18,7 +18,6 @@
+ #include <linux/nfsd/const.h>
+ #include <linux/nfsd/export.h>
+ #include <linux/nfsd/nfsfh.h>
+-#include <linux/nfsd/auth.h>
+ 
+ /*
+  * Version of the syscall interface
+diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
+index 67885d5..a0132ef 100644
+--- a/include/linux/nfsd/xdr.h
++++ b/include/linux/nfsd/xdr.h
+@@ -23,7 +23,7 @@ struct nfsd_sattrargs {
+ struct nfsd_diropargs {
+ 	struct svc_fh		fh;
+ 	char *			name;
+-	int			len;
++	unsigned int		len;
+ };
+ 
+ struct nfsd_readargs {
+@@ -43,17 +43,17 @@ struct nfsd_writeargs {
+ struct nfsd_createargs {
+ 	struct svc_fh		fh;
+ 	char *			name;
+-	int			len;
++	unsigned int		len;
+ 	struct iattr		attrs;
+ };
+ 
+ struct nfsd_renameargs {
+ 	struct svc_fh		ffh;
+ 	char *			fname;
+-	int			flen;
++	unsigned int		flen;
+ 	struct svc_fh		tfh;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ };
+ 
+ struct nfsd_readlinkargs {
+@@ -65,15 +65,15 @@ struct nfsd_linkargs {
+ 	struct svc_fh		ffh;
+ 	struct svc_fh		tfh;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ };
+ 
+ struct nfsd_symlinkargs {
+ 	struct svc_fh		ffh;
+ 	char *			fname;
+-	int			flen;
++	unsigned int		flen;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ 	struct iattr		attrs;
+ };
+ 
+diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
+index 89d9d60..421eddd 100644
+--- a/include/linux/nfsd/xdr3.h
++++ b/include/linux/nfsd/xdr3.h
+@@ -21,7 +21,7 @@ struct nfsd3_sattrargs {
+ struct nfsd3_diropargs {
+ 	struct svc_fh		fh;
+ 	char *			name;
+-	int			len;
++	unsigned int		len;
+ };
+ 
+ struct nfsd3_accessargs {
+@@ -48,7 +48,7 @@ struct nfsd3_writeargs {
+ struct nfsd3_createargs {
+ 	struct svc_fh		fh;
+ 	char *			name;
+-	int			len;
++	unsigned int		len;
+ 	int			createmode;
+ 	struct iattr		attrs;
+ 	__be32 *		verf;
+@@ -57,7 +57,7 @@ struct nfsd3_createargs {
+ struct nfsd3_mknodargs {
+ 	struct svc_fh		fh;
+ 	char *			name;
+-	int			len;
++	unsigned int		len;
+ 	__u32			ftype;
+ 	__u32			major, minor;
+ 	struct iattr		attrs;
+@@ -66,10 +66,10 @@ struct nfsd3_mknodargs {
+ struct nfsd3_renameargs {
+ 	struct svc_fh		ffh;
+ 	char *			fname;
+-	int			flen;
++	unsigned int		flen;
+ 	struct svc_fh		tfh;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ };
+ 
+ struct nfsd3_readlinkargs {
+@@ -81,15 +81,15 @@ struct nfsd3_linkargs {
+ 	struct svc_fh		ffh;
+ 	struct svc_fh		tfh;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ };
+ 
+ struct nfsd3_symlinkargs {
+ 	struct svc_fh		ffh;
+ 	char *			fname;
+-	int			flen;
++	unsigned int		flen;
+ 	char *			tname;
+-	int			tlen;
++	unsigned int		tlen;
+ 	struct iattr		attrs;
+ };
+ 
+diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
+index b0ddfb4..27bd3e3 100644
+--- a/include/linux/nfsd/xdr4.h
++++ b/include/linux/nfsd/xdr4.h
+@@ -441,7 +441,7 @@ void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
+ void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
+ __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+ 		       struct dentry *dentry, __be32 *buffer, int *countp,
+-		       u32 *bmval, struct svc_rqst *);
++		       u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
+ extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
+ 		struct nfsd4_compound_state *,
+ 		struct nfsd4_setclientid *setclid);
+diff --git a/include/linux/nfsd_idmap.h b/include/linux/nfsd_idmap.h
+index e82746f..d4a2ac1 100644
+--- a/include/linux/nfsd_idmap.h
++++ b/include/linux/nfsd_idmap.h
+@@ -44,11 +44,16 @@
+ #define IDMAP_NAMESZ 128
+ 
+ #ifdef CONFIG_NFSD_V4
+-void nfsd_idmap_init(void);
++int nfsd_idmap_init(void);
+ void nfsd_idmap_shutdown(void);
+ #else
+-static inline void nfsd_idmap_init(void) {};
+-static inline void nfsd_idmap_shutdown(void) {};
++static inline int nfsd_idmap_init(void)
++{
++	return 0;
++}
++static inline void nfsd_idmap_shutdown(void)
++{
++}
+ #endif
+ 
+ int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
 diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
 index 538ee1d..9fecf90 100644
 --- a/include/linux/nl80211.h
@@ -813217,7 +861899,7 @@
 +
  #endif /* __LINUX_NL80211_H */
 diff --git a/include/linux/notifier.h b/include/linux/notifier.h
-index 0c40cc0..5dfbc68 100644
+index 0c40cc0..f4df400 100644
 --- a/include/linux/notifier.h
 +++ b/include/linux/notifier.h
 @@ -207,9 +207,7 @@ static inline int notifier_to_errno(int ret)
@@ -813231,6 +861913,15 @@
  				        * not handling interrupts, soon dead */
  
  /* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
+@@ -230,6 +228,8 @@ static inline int notifier_to_errno(int ret)
+ #define PM_POST_HIBERNATION	0x0002 /* Hibernation finished */
+ #define PM_SUSPEND_PREPARE	0x0003 /* Going to suspend the system */
+ #define PM_POST_SUSPEND		0x0004 /* Suspend finished */
++#define PM_RESTORE_PREPARE	0x0005 /* Going to restore a saved image */
++#define PM_POST_RESTORE		0x0006 /* Restore failed */
+ 
+ /* Console keyboard events.
+  * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
 diff --git a/include/linux/of.h b/include/linux/of.h
 index 5c39b92..b5f33ef 100644
 --- a/include/linux/of.h
@@ -813335,11 +862026,646 @@
 +extern int __devexit __pata_platform_remove(struct device *dev);
 +
  #endif /* __LINUX_PATA_PLATFORM_H */
+diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
+index 936ef82..3ba2506 100644
+--- a/include/linux/pci-acpi.h
++++ b/include/linux/pci-acpi.h
+@@ -48,7 +48,15 @@
+ 
+ #ifdef CONFIG_ACPI
+ extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
+-extern acpi_status pci_osc_support_set(u32 flags);
++extern acpi_status __pci_osc_support_set(u32 flags, const char *hid);
++static inline acpi_status pci_osc_support_set(u32 flags)
++{
++	return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING);
++}
++static inline acpi_status pcie_osc_support_set(u32 flags)
++{
++	return __pci_osc_support_set(flags, PCI_EXPRESS_ROOT_HID_STRING);
++}
+ #else
+ #if !defined(AE_ERROR)
+ typedef u32 		acpi_status;
+@@ -57,6 +65,7 @@ typedef u32 		acpi_status;
+ static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
+ {return AE_ERROR;}
+ static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} 
++static inline acpi_status pcie_osc_support_set(u32 flags) {return AE_ERROR;}
+ #endif
+ 
+ #endif	/* _PCI_ACPI_H_ */
 diff --git a/include/linux/pci.h b/include/linux/pci.h
-index 0dd93bb..ae10063 100644
+index 0dd93bb..4f96f1d 100644
 --- a/include/linux/pci.h
 +++ b/include/linux/pci.h
-@@ -867,7 +867,7 @@ enum pci_fixup_pass {
+@@ -28,7 +28,7 @@
+  *	7:3 = slot
+  *	2:0 = function
+  */
+-#define PCI_DEVFN(slot,func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
++#define PCI_DEVFN(slot, func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
+ #define PCI_SLOT(devfn)		(((devfn) >> 3) & 0x1f)
+ #define PCI_FUNC(devfn)		((devfn) & 0x07)
+ 
+@@ -66,7 +66,6 @@ enum pci_mmap_state {
+ #define PCI_DMA_FROMDEVICE	2
+ #define PCI_DMA_NONE		3
+ 
+-#define DEVICE_COUNT_COMPATIBLE	4
+ #define DEVICE_COUNT_RESOURCE	12
+ 
+ typedef int __bitwise pci_power_t;
+@@ -129,6 +128,7 @@ struct pci_cap_saved_state {
+ 	u32 data[0];
+ };
+ 
++struct pcie_link_state;
+ /*
+  * The pci_dev structure is used to describe PCI devices.
+  */
+@@ -164,13 +164,13 @@ struct pci_dev {
+ 					   this is D0-D3, D0 being fully functional,
+ 					   and D3 being off. */
+ 
++#ifdef CONFIG_PCIEASPM
++	struct pcie_link_state	*link_state;	/* ASPM link state. */
++#endif
++
+ 	pci_channel_state_t error_state;	/* current connectivity state */
+ 	struct	device	dev;		/* Generic device interface */
+ 
+-	/* device is compatible with these IDs */
+-	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
+-	unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
+-
+ 	int		cfg_size;	/* Size of configuration space */
+ 
+ 	/*
+@@ -219,7 +219,7 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
+ }
+ 
+ static inline struct pci_cap_saved_state *pci_find_saved_cap(
+-	struct pci_dev *pci_dev,char cap)
++	struct pci_dev *pci_dev, char cap)
+ {
+ 	struct pci_cap_saved_state *tmp;
+ 	struct hlist_node *pos;
+@@ -278,13 +278,13 @@ struct pci_bus {
+ 	unsigned short  bridge_ctl;	/* manage NO_ISA/FBB/et al behaviors */
+ 	pci_bus_flags_t bus_flags;	/* Inherited by child busses */
+ 	struct device		*bridge;
+-	struct class_device	class_dev;
++	struct device		dev;
+ 	struct bin_attribute	*legacy_io; /* legacy I/O for this bus */
+ 	struct bin_attribute	*legacy_mem; /* legacy mem */
+ };
+ 
+ #define pci_bus_b(n)	list_entry(n, struct pci_bus, node)
+-#define to_pci_bus(n)	container_of(n, struct pci_bus, class_dev)
++#define to_pci_bus(n)	container_of(n, struct pci_bus, dev)
+ 
+ /*
+  * Error values that may be returned by PCI functions.
+@@ -314,8 +314,8 @@ struct pci_raw_ops {
+ extern struct pci_raw_ops *raw_pci_ops;
+ 
+ struct pci_bus_region {
+-	unsigned long start;
+-	unsigned long end;
++	resource_size_t start;
++	resource_size_t end;
+ };
+ 
+ struct pci_dynids {
+@@ -351,11 +351,10 @@ enum pci_ers_result {
+ };
+ 
+ /* PCI bus error event callbacks */
+-struct pci_error_handlers
+-{
++struct pci_error_handlers {
+ 	/* PCI bus error detected on this device */
+ 	pci_ers_result_t (*error_detected)(struct pci_dev *dev,
+-	                      enum pci_channel_state error);
++					   enum pci_channel_state error);
+ 
+ 	/* MMIO has been re-enabled, but not DMA */
+ 	pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
+@@ -390,7 +389,7 @@ struct pci_driver {
+ 	struct pci_dynids dynids;
+ };
+ 
+-#define	to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
++#define	to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
+ 
+ /**
+  * PCI_DEVICE - macro used to describe a specific pci device
+@@ -448,7 +447,7 @@ extern int no_pci_devices(void);
+ 
+ void pcibios_fixup_bus(struct pci_bus *);
+ int __must_check pcibios_enable_device(struct pci_dev *, int mask);
+-char *pcibios_setup (char *str);
++char *pcibios_setup(char *str);
+ 
+ /* Used only when drivers/pci/setup.c is used */
+ void pcibios_align_resource(void *, struct resource *, resource_size_t,
+@@ -459,8 +458,10 @@ void pcibios_update_irq(struct pci_dev *, int irq);
+ 
+ extern struct pci_bus *pci_find_bus(int domain, int busnr);
+ void pci_bus_add_devices(struct pci_bus *bus);
+-struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
+-static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
++struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
++				      struct pci_ops *ops, void *sysdata);
++static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
++					   void *sysdata)
+ {
+ 	struct pci_bus *root_bus;
+ 	root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
+@@ -468,15 +469,18 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s
+ 		pci_bus_add_devices(root_bus);
+ 	return root_bus;
+ }
+-struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
+-struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
++struct pci_bus *pci_create_bus(struct device *parent, int bus,
++			       struct pci_ops *ops, void *sysdata);
++struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
++				int busnr);
+ int pci_scan_slot(struct pci_bus *bus, int devfn);
+-struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
++struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
+ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
+ unsigned int pci_scan_child_bus(struct pci_bus *bus);
+ int __must_check pci_bus_add_device(struct pci_dev *dev);
+ void pci_read_bridge_bases(struct pci_bus *child);
+-struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res);
++struct resource *pci_find_parent_resource(const struct pci_dev *dev,
++					  struct resource *res);
+ int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
+ extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
+ extern void pci_dev_put(struct pci_dev *dev);
+@@ -489,15 +493,19 @@ extern void pci_sort_breadthfirst(void);
+ /* Generic PCI functions exported to card drivers */
+ 
+ #ifdef CONFIG_PCI_LEGACY
+-struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
+-struct pci_dev __deprecated *pci_find_slot (unsigned int bus, unsigned int devfn);
++struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
++					     unsigned int device,
++					     const struct pci_dev *from);
++struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
++					   unsigned int devfn);
+ #endif /* CONFIG_PCI_LEGACY */
+ 
+-int pci_find_capability (struct pci_dev *dev, int cap);
+-int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
+-int pci_find_ext_capability (struct pci_dev *dev, int cap);
+-int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
+-int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
++int pci_find_capability(struct pci_dev *dev, int cap);
++int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
++int pci_find_ext_capability(struct pci_dev *dev, int cap);
++int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
++int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
++void pcie_wait_pending_transaction(struct pci_dev *dev);
+ struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
+ 
+ struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
+@@ -505,49 +513,58 @@ struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
+ struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
+ 				struct pci_dev *from);
+ 
+-struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
++struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
+ 				unsigned int ss_vendor, unsigned int ss_device,
+ 				struct pci_dev *from);
+-struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
+-struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
+-struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
++struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
++struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);
++struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
+ int pci_dev_present(const struct pci_device_id *ids);
+ const struct pci_device_id *pci_find_present(const struct pci_device_id *ids);
+ 
+-int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
+-int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
+-int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
+-int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val);
+-int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val);
+-int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val);
++int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
++			     int where, u8 *val);
++int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn,
++			     int where, u16 *val);
++int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn,
++			      int where, u32 *val);
++int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn,
++			      int where, u8 val);
++int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
++			      int where, u16 val);
++int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
++			       int where, u32 val);
+ 
+ static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
+ {
+-	return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val);
++	return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
+ }
+ static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
+ {
+-	return pci_bus_read_config_word (dev->bus, dev->devfn, where, val);
++	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
+ }
+-static inline int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val)
++static inline int pci_read_config_dword(struct pci_dev *dev, int where,
++					u32 *val)
+ {
+-	return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val);
++	return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
+ }
+ static inline int pci_write_config_byte(struct pci_dev *dev, int where, u8 val)
+ {
+-	return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val);
++	return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
+ }
+ static inline int pci_write_config_word(struct pci_dev *dev, int where, u16 val)
+ {
+-	return pci_bus_write_config_word (dev->bus, dev->devfn, where, val);
++	return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
+ }
+-static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val)
++static inline int pci_write_config_dword(struct pci_dev *dev, int where,
++					 u32 val)
+ {
+-	return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val);
++	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
+ }
+ 
+ int __must_check pci_enable_device(struct pci_dev *dev);
+-int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask);
++int __must_check pci_enable_device_io(struct pci_dev *dev);
++int __must_check pci_enable_device_mem(struct pci_dev *dev);
+ int __must_check pci_reenable_device(struct pci_dev *);
+ int __must_check pcim_enable_device(struct pci_dev *pdev);
+ void pcim_pin_device(struct pci_dev *pdev);
+@@ -576,14 +593,11 @@ int pcie_set_readrq(struct pci_dev *dev, int rq);
+ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
+ int __must_check pci_assign_resource(struct pci_dev *dev, int i);
+ int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
+-void pci_restore_bars(struct pci_dev *dev);
+ int pci_select_bars(struct pci_dev *dev, unsigned long flags);
+ 
+ /* ROM control related routines */
+ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
+-void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size);
+ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
+-void pci_remove_rom(struct pci_dev *pdev);
+ size_t pci_get_rom_size(void __iomem *rom, size_t size);
+ 
+ /* Power management related routines */
+@@ -594,7 +608,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
+ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
+ 
+ /* Functions for PCI Hotplug drivers to use */
+-int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
++int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
+ 
+ /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
+ void pci_bus_assign_resources(struct pci_bus *bus);
+@@ -631,16 +645,18 @@ static inline int __must_check pci_register_driver(struct pci_driver *driver)
+ 	return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
+ }
+ 
+-void pci_unregister_driver(struct pci_driver *);
+-void pci_remove_behind_bridge(struct pci_dev *);
+-struct pci_driver *pci_dev_driver(const struct pci_dev *);
+-const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
+-int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
++void pci_unregister_driver(struct pci_driver *dev);
++void pci_remove_behind_bridge(struct pci_dev *dev);
++struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
++const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
++					 struct pci_dev *dev);
++int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
++		    int pass);
+ 
+ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
+ 		  void *userdata);
+ int pci_cfg_space_size(struct pci_dev *dev);
+-unsigned char pci_bus_max_busnr(struct pci_bus* bus);
++unsigned char pci_bus_max_busnr(struct pci_bus *bus);
+ 
+ /* kmem_cache style wrapper around pci_alloc_consistent() */
+ 
+@@ -669,19 +685,36 @@ struct msix_entry {
+ 
+ 
+ #ifndef CONFIG_PCI_MSI
+-static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
+-static inline void pci_disable_msi(struct pci_dev *dev) {}
+-static inline int pci_enable_msix(struct pci_dev* dev,
+-	struct msix_entry *entries, int nvec) {return -1;}
+-static inline void pci_disable_msix(struct pci_dev *dev) {}
+-static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
++static inline int pci_enable_msi(struct pci_dev *dev)
++{
++	return -1;
++}
++
++static inline void pci_disable_msi(struct pci_dev *dev)
++{ }
++
++static inline int pci_enable_msix(struct pci_dev *dev,
++				  struct msix_entry *entries, int nvec)
++{
++	return -1;
++}
++
++static inline void pci_disable_msix(struct pci_dev *dev)
++{ }
++
++static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev)
++{ }
++
++static inline void pci_restore_msi_state(struct pci_dev *dev)
++{ }
+ #else
+ extern int pci_enable_msi(struct pci_dev *dev);
+ extern void pci_disable_msi(struct pci_dev *dev);
+-extern int pci_enable_msix(struct pci_dev* dev,
++extern int pci_enable_msix(struct pci_dev *dev,
+ 	struct msix_entry *entries, int nvec);
+ extern void pci_disable_msix(struct pci_dev *dev);
+ extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
++extern void pci_restore_msi_state(struct pci_dev *dev);
+ #endif
+ 
+ #ifdef CONFIG_HT_IRQ
+@@ -702,7 +735,11 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
+ extern int pci_domains_supported;
+ #else
+ enum { pci_domains_supported = 0 };
+-static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
++static inline int pci_domain_nr(struct pci_bus *bus)
++{
++	return 0;
++}
++
+ static inline int pci_proc_domain(struct pci_bus *bus)
+ {
+ 	return 0;
+@@ -716,67 +753,161 @@ static inline int pci_proc_domain(struct pci_bus *bus)
+  *  these as simple inline functions to avoid hair in drivers.
+  */
+ 
+-#define _PCI_NOP(o,s,t) \
+-	static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \
++#define _PCI_NOP(o, s, t) \
++	static inline int pci_##o##_config_##s(struct pci_dev *dev, \
++						int where, t val) \
+ 		{ return PCIBIOS_FUNC_NOT_SUPPORTED; }
+-#define _PCI_NOP_ALL(o,x)	_PCI_NOP(o,byte,u8 x) \
+-				_PCI_NOP(o,word,u16 x) \
+-				_PCI_NOP(o,dword,u32 x)
++
++#define _PCI_NOP_ALL(o, x)	_PCI_NOP(o, byte, u8 x) \
++				_PCI_NOP(o, word, u16 x) \
++				_PCI_NOP(o, dword, u32 x)
+ _PCI_NOP_ALL(read, *)
+ _PCI_NOP_ALL(write,)
+ 
+-static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+-{ return NULL; }
++static inline struct pci_dev *pci_find_device(unsigned int vendor,
++					      unsigned int device,
++					      const struct pci_dev *from)
++{
++	return NULL;
++}
+ 
+-static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
+-{ return NULL; }
++static inline struct pci_dev *pci_find_slot(unsigned int bus,
++					    unsigned int devfn)
++{
++	return NULL;
++}
+ 
+ static inline struct pci_dev *pci_get_device(unsigned int vendor,
+-				unsigned int device, struct pci_dev *from)
+-{ return NULL; }
++					     unsigned int device,
++					     struct pci_dev *from)
++{
++	return NULL;
++}
+ 
+ static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
+-				unsigned int device, struct pci_dev *from)
+-{ return NULL; }
++						     unsigned int device,
++						     struct pci_dev *from)
++{
++	return NULL;
++}
+ 
+-static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
+-unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
+-{ return NULL; }
++static inline struct pci_dev *pci_get_subsys(unsigned int vendor,
++					     unsigned int device,
++					     unsigned int ss_vendor,
++					     unsigned int ss_device,
++					     struct pci_dev *from)
++{
++	return NULL;
++}
+ 
+-static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
+-{ return NULL; }
++static inline struct pci_dev *pci_get_class(unsigned int class,
++					    struct pci_dev *from)
++{
++	return NULL;
++}
+ 
+ #define pci_dev_present(ids)	(0)
+ #define no_pci_devices()	(1)
+ #define pci_find_present(ids)	(NULL)
+ #define pci_dev_put(dev)	do { } while (0)
+ 
+-static inline void pci_set_master(struct pci_dev *dev) { }
+-static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
+-static inline void pci_disable_device(struct pci_dev *dev) { }
+-static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
+-static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
+-static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;}
+-static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
+-static inline void pci_unregister_driver(struct pci_driver *drv) { }
+-static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
+-static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
+-static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
++static inline void pci_set_master(struct pci_dev *dev)
++{ }
++
++static inline int pci_enable_device(struct pci_dev *dev)
++{
++	return -EIO;
++}
++
++static inline void pci_disable_device(struct pci_dev *dev)
++{ }
++
++static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
++{
++	return -EIO;
++}
++
++static inline int pci_assign_resource(struct pci_dev *dev, int i)
++{
++	return -EBUSY;
++}
++
++static inline int __pci_register_driver(struct pci_driver *drv,
++					struct module *owner)
++{
++	return 0;
++}
++
++static inline int pci_register_driver(struct pci_driver *drv)
++{
++	return 0;
++}
++
++static inline void pci_unregister_driver(struct pci_driver *drv)
++{ }
++
++static inline int pci_find_capability(struct pci_dev *dev, int cap)
++{
++	return 0;
++}
++
++static inline int pci_find_next_capability(struct pci_dev *dev, u8 post,
++					   int cap)
++{
++	return 0;
++}
++
++static inline int pci_find_ext_capability(struct pci_dev *dev, int cap)
++{
++	return 0;
++}
++
++static inline void pcie_wait_pending_transaction(struct pci_dev *dev)
++{ }
+ 
+ /* Power management related routines */
+-static inline int pci_save_state(struct pci_dev *dev) { return 0; }
+-static inline int pci_restore_state(struct pci_dev *dev) { return 0; }
+-static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { return 0; }
+-static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
+-static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
++static inline int pci_save_state(struct pci_dev *dev)
++{
++	return 0;
++}
++
++static inline int pci_restore_state(struct pci_dev *dev)
++{
++	return 0;
++}
++
++static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
++{
++	return 0;
++}
++
++static inline pci_power_t pci_choose_state(struct pci_dev *dev,
++					   pm_message_t state)
++{
++	return PCI_D0;
++}
++
++static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
++				  int enable)
++{
++	return 0;
++}
++
++static inline int pci_request_regions(struct pci_dev *dev, const char *res_name)
++{
++	return -EIO;
++}
+ 
+-static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; }
+-static inline void pci_release_regions(struct pci_dev *dev) { }
++static inline void pci_release_regions(struct pci_dev *dev)
++{ }
+ 
+ #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
+ 
+-static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
+-static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { }
++static inline void pci_block_user_cfg_access(struct pci_dev *dev)
++{ }
++
++static inline void pci_unblock_user_cfg_access(struct pci_dev *dev)
++{ }
+ 
+ static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
+ { return NULL; }
+@@ -797,27 +928,27 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
+ 
+ /* these helpers provide future and backwards compatibility
+  * for accessing popular PCI BAR info */
+-#define pci_resource_start(dev,bar)   ((dev)->resource[(bar)].start)
+-#define pci_resource_end(dev,bar)     ((dev)->resource[(bar)].end)
+-#define pci_resource_flags(dev,bar)   ((dev)->resource[(bar)].flags)
++#define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
++#define pci_resource_end(dev, bar)	((dev)->resource[(bar)].end)
++#define pci_resource_flags(dev, bar)	((dev)->resource[(bar)].flags)
+ #define pci_resource_len(dev,bar) \
+-	((pci_resource_start((dev),(bar)) == 0 &&	\
+-	  pci_resource_end((dev),(bar)) ==		\
+-	  pci_resource_start((dev),(bar))) ? 0 :	\
+-	  						\
+-	 (pci_resource_end((dev),(bar)) -		\
+-	  pci_resource_start((dev),(bar)) + 1))
++	((pci_resource_start((dev), (bar)) == 0 &&	\
++	  pci_resource_end((dev), (bar)) ==		\
++	  pci_resource_start((dev), (bar))) ? 0 :	\
++							\
++	 (pci_resource_end((dev), (bar)) -		\
++	  pci_resource_start((dev), (bar)) + 1))
+ 
+ /* Similar to the helpers above, these manipulate per-pci_dev
+  * driver-specific data.  They are really just a wrapper around
+  * the generic device structure functions of these calls.
+  */
+-static inline void *pci_get_drvdata (struct pci_dev *pdev)
++static inline void *pci_get_drvdata(struct pci_dev *pdev)
+ {
+ 	return dev_get_drvdata(&pdev->dev);
+ }
+ 
+-static inline void pci_set_drvdata (struct pci_dev *pdev, void *data)
++static inline void pci_set_drvdata(struct pci_dev *pdev, void *data)
+ {
+ 	dev_set_drvdata(&pdev->dev, data);
+ }
+@@ -836,7 +967,7 @@ static inline char *pci_name(struct pci_dev *pdev)
+  */
+ #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
+ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
+-                const struct resource *rsrc, resource_size_t *start,
++		const struct resource *rsrc, resource_size_t *start,
+ 		resource_size_t *end)
+ {
+ 	*start = rsrc->start;
+@@ -867,7 +998,7 @@ enum pci_fixup_pass {
  
  /* Anonymous variables would be nice... */
  #define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook)	\
@@ -813348,6 +862674,18 @@
  	__attribute__((__section__(#section))) = { vendor, device, hook };
  #define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook)			\
  	DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early,			\
+@@ -888,9 +1019,9 @@ enum pci_fixup_pass {
+ 
+ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
+ 
+-void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
++void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
+ void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
+-void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
++void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
+ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
+ void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
+ 
 diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
 index ab4cb6e..8f67e8f 100644
 --- a/include/linux/pci_hotplug.h
@@ -813409,6 +862747,28 @@
  #define PCI_VENDOR_ID_SITECOM		0x182d
  #define PCI_DEVICE_ID_SITECOM_DC105V2	0x3069
  
+diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
+index c1914a8..c0c1223 100644
+--- a/include/linux/pci_regs.h
++++ b/include/linux/pci_regs.h
+@@ -395,9 +395,17 @@
+ #define  PCI_EXP_DEVSTA_AUXPD	0x10	/* AUX Power Detected */
+ #define  PCI_EXP_DEVSTA_TRPND	0x20	/* Transactions Pending */
+ #define PCI_EXP_LNKCAP		12	/* Link Capabilities */
++#define  PCI_EXP_LNKCAP_ASPMS	0xc00	/* ASPM Support */
++#define  PCI_EXP_LNKCAP_L0SEL	0x7000	/* L0s Exit Latency */
++#define  PCI_EXP_LNKCAP_L1EL	0x38000	/* L1 Exit Latency */
++#define  PCI_EXP_LNKCAP_CLKPM	0x40000	/* L1 Clock Power Management */
+ #define PCI_EXP_LNKCTL		16	/* Link Control */
++#define  PCI_EXP_LNKCTL_RL	0x20	/* Retrain Link */
++#define  PCI_EXP_LNKCTL_CCC	0x40	/* Common Clock COnfiguration */
+ #define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100	/* Enable clkreq */
+ #define PCI_EXP_LNKSTA		18	/* Link Status */
++#define  PCI_EXP_LNKSTA_LT	0x800	/* Link Training */
++#define  PCI_EXP_LNKSTA_SLC	0x1000	/* Slot Clock Configuration */
+ #define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
+ #define PCI_EXP_SLTCTL		24	/* Slot Control */
+ #define PCI_EXP_SLTSTA		26	/* Slot Status */
 diff --git a/include/linux/pcounter.h b/include/linux/pcounter.h
 new file mode 100644
 index 0000000..a82d9f2
@@ -813489,6 +862849,18 @@
 +#endif /* CONFIG_SMP */
 +
 +#endif /* __LINUX_PCOUNTER_H */
+diff --git a/include/linux/pda_power.h b/include/linux/pda_power.h
+index 1375f15..225beb1 100644
+--- a/include/linux/pda_power.h
++++ b/include/linux/pda_power.h
+@@ -26,6 +26,7 @@ struct pda_power_pdata {
+ 
+ 	unsigned int wait_for_status; /* msecs, default is 500 */
+ 	unsigned int wait_for_charger; /* msecs, default is 500 */
++	unsigned int polling_interval; /* msecs, default is 2000 */
+ };
+ 
+ #endif /* __PDA_POWER_H__ */
 diff --git a/include/linux/percpu.h b/include/linux/percpu.h
 index 926adaa..50faa0e 100644
 --- a/include/linux/percpu.h
@@ -813520,6 +862892,23 @@
  /* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */
  #ifndef PERCPU_ENOUGH_ROOM
  #ifdef CONFIG_MODULES
+diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
+index d9db5f6..6db69ff 100644
+--- a/include/linux/pfkeyv2.h
++++ b/include/linux/pfkeyv2.h
+@@ -298,6 +298,12 @@ struct sadb_x_sec_ctx {
+ #define SADB_X_EALG_BLOWFISHCBC		7
+ #define SADB_EALG_NULL			11
+ #define SADB_X_EALG_AESCBC		12
++#define SADB_X_EALG_AES_CCM_ICV8	14
++#define SADB_X_EALG_AES_CCM_ICV12	15
++#define SADB_X_EALG_AES_CCM_ICV16	16
++#define SADB_X_EALG_AES_GCM_ICV8	18
++#define SADB_X_EALG_AES_GCM_ICV12	19
++#define SADB_X_EALG_AES_GCM_ICV16	20
+ #define SADB_X_EALG_CAMELLIACBC		22
+ #define SADB_EALG_MAX                   253 /* last EALG */
+ /* private allocations should use 249-255 (RFC2407) */
 diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
 index 04ba70d..509d8f5 100644
 --- a/include/linux/phy_fixed.h
@@ -813585,8 +862974,69 @@
 +					   struct fixed_phy_status *));
  
  #endif /* __PHY_FIXED_H */
+diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
+index 30b8571..1c1dba9 100644
+--- a/include/linux/pkt_cls.h
++++ b/include/linux/pkt_cls.h
+@@ -328,6 +328,56 @@ enum
+ 
+ #define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
+ 
++/* Flow filter */
++
++enum
++{
++	FLOW_KEY_SRC,
++	FLOW_KEY_DST,
++	FLOW_KEY_PROTO,
++	FLOW_KEY_PROTO_SRC,
++	FLOW_KEY_PROTO_DST,
++	FLOW_KEY_IIF,
++	FLOW_KEY_PRIORITY,
++	FLOW_KEY_MARK,
++	FLOW_KEY_NFCT,
++	FLOW_KEY_NFCT_SRC,
++	FLOW_KEY_NFCT_DST,
++	FLOW_KEY_NFCT_PROTO_SRC,
++	FLOW_KEY_NFCT_PROTO_DST,
++	FLOW_KEY_RTCLASSID,
++	FLOW_KEY_SKUID,
++	FLOW_KEY_SKGID,
++	__FLOW_KEY_MAX,
++};
++
++#define FLOW_KEY_MAX	(__FLOW_KEY_MAX - 1)
++
++enum
++{
++	FLOW_MODE_MAP,
++	FLOW_MODE_HASH,
++};
++
++enum
++{
++	TCA_FLOW_UNSPEC,
++	TCA_FLOW_KEYS,
++	TCA_FLOW_MODE,
++	TCA_FLOW_BASECLASS,
++	TCA_FLOW_RSHIFT,
++	TCA_FLOW_ADDEND,
++	TCA_FLOW_MASK,
++	TCA_FLOW_XOR,
++	TCA_FLOW_DIVISOR,
++	TCA_FLOW_ACT,
++	TCA_FLOW_POLICE,
++	TCA_FLOW_EMATCHES,
++	__TCA_FLOW_MAX
++};
++
++#define TCA_FLOW_MAX	(__TCA_FLOW_MAX - 1)
++
+ /* Basic filter */
+ 
+ enum
 diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
-index 919af93..3276135 100644
+index 919af93..dbb7ac3 100644
 --- a/include/linux/pkt_sched.h
 +++ b/include/linux/pkt_sched.h
 @@ -83,6 +83,8 @@ struct tc_ratespec
@@ -813598,6 +863048,18 @@
  /* FIFO section */
  
  struct tc_fifo_qopt
+@@ -148,6 +150,11 @@ struct tc_sfq_qopt
+ 	unsigned	flows;		/* Maximal number of flows  */
+ };
+ 
++struct tc_sfq_xstats
++{
++	__s32		allot;
++};
++
+ /*
+  *  NOTE: limit, divisor and flows are hardwired to code at the moment.
+  *
 diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
 index 5ea4f05..04b4d73 100644
 --- a/include/linux/pktcdvd.h
@@ -813671,6 +863133,44 @@
  
  #define PMU_MAX_BATTERIES	2
  
+diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
+index 606c095..5cbf3e3 100644
+--- a/include/linux/power_supply.h
++++ b/include/linux/power_supply.h
+@@ -54,15 +54,7 @@ enum {
+ 	POWER_SUPPLY_TECHNOLOGY_LIPO,
+ 	POWER_SUPPLY_TECHNOLOGY_LiFe,
+ 	POWER_SUPPLY_TECHNOLOGY_NiCd,
+-};
+-
+-enum {
+-	POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
+-	POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
+-	POWER_SUPPLY_CAPACITY_LEVEL_LOW,
+-	POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
+-	POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
+-	POWER_SUPPLY_CAPACITY_LEVEL_FULL,
++	POWER_SUPPLY_TECHNOLOGY_LiMn,
+ };
+ 
+ enum power_supply_property {
+@@ -72,6 +64,8 @@ enum power_supply_property {
+ 	POWER_SUPPLY_PROP_PRESENT,
+ 	POWER_SUPPLY_PROP_ONLINE,
+ 	POWER_SUPPLY_PROP_TECHNOLOGY,
++	POWER_SUPPLY_PROP_VOLTAGE_MAX,
++	POWER_SUPPLY_PROP_VOLTAGE_MIN,
+ 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+@@ -91,7 +85,6 @@ enum power_supply_property {
+ 	POWER_SUPPLY_PROP_ENERGY_NOW,
+ 	POWER_SUPPLY_PROP_ENERGY_AVG,
+ 	POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
+-	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ 	POWER_SUPPLY_PROP_TEMP,
+ 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
 index a531682..8f92546 100644
 --- a/include/linux/proc_fs.h
@@ -814752,6 +864252,24 @@
 +
 +
 +#endif	/* <linux/regset.h> */
+diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
+index 0ce5e0b..e3ab21d 100644
+--- a/include/linux/rfkill.h
++++ b/include/linux/rfkill.h
+@@ -33,11 +33,13 @@
+  * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
+  * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
+  * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
++ * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
+  */
+ enum rfkill_type {
+ 	RFKILL_TYPE_WLAN ,
+ 	RFKILL_TYPE_BLUETOOTH,
+ 	RFKILL_TYPE_UWB,
++	RFKILL_TYPE_WIMAX,
+ 	RFKILL_TYPE_MAX,
+ };
+ 
 diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
 index 4e81836..b014f6b 100644
 --- a/include/linux/rtnetlink.h
@@ -814950,7 +864468,7 @@
 +
  #endif /* _LINUX_SCATTERLIST_H */
 diff --git a/include/linux/sched.h b/include/linux/sched.h
-index cc14656..6c33357 100644
+index cc14656..af6947e 100644
 --- a/include/linux/sched.h
 +++ b/include/linux/sched.h
 @@ -27,6 +27,7 @@
@@ -815189,7 +864707,18 @@
  /* CPU-specific state of this task */
  	struct thread_struct thread;
  /* filesystem information */
-@@ -1178,6 +1246,10 @@ struct task_struct {
+@@ -1071,6 +1139,10 @@ struct task_struct {
+ 	void *security;
+ #endif
+ 	struct audit_context *audit_context;
++#ifdef CONFIG_AUDITSYSCALL
++	uid_t loginuid;
++	unsigned int sessionid;
++#endif
+ 	seccomp_t seccomp;
+ 
+ /* Thread group tracking */
+@@ -1178,6 +1250,10 @@ struct task_struct {
  	int make_it_fail;
  #endif
  	struct prop_local_single dirties;
@@ -815200,7 +864729,7 @@
  };
  
  /*
-@@ -1458,6 +1530,12 @@ extern unsigned int sysctl_sched_child_runs_first;
+@@ -1458,6 +1534,12 @@ extern unsigned int sysctl_sched_child_runs_first;
  extern unsigned int sysctl_sched_features;
  extern unsigned int sysctl_sched_migration_cost;
  extern unsigned int sysctl_sched_nr_migrate;
@@ -815213,7 +864742,7 @@
  
  int sched_nr_latency_handler(struct ctl_table *table, int write,
  		struct file *file, void __user *buffer, size_t *length,
-@@ -1837,7 +1915,14 @@ static inline int signal_pending(struct task_struct *p)
+@@ -1837,7 +1919,14 @@ static inline int signal_pending(struct task_struct *p)
  {
  	return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING));
  }
@@ -815229,7 +864758,7 @@
  static inline int need_resched(void)
  {
  	return unlikely(test_thread_flag(TIF_NEED_RESCHED));
-@@ -1850,29 +1935,33 @@ static inline int need_resched(void)
+@@ -1850,29 +1939,33 @@ static inline int need_resched(void)
   * cond_resched_lock() will drop the spinlock before scheduling,
   * cond_resched_softirq() will enable bhs before scheduling.
   */
@@ -815521,7 +865050,7 @@
  #endif
  #endif
 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
-index bddd50b..c618fbf 100644
+index bddd50b..dfe975a 100644
 --- a/include/linux/skbuff.h
 +++ b/include/linux/skbuff.h
 @@ -95,6 +95,7 @@
@@ -815532,7 +865061,17 @@
  
  #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
  struct nf_conntrack {
-@@ -287,6 +288,7 @@ struct sk_buff {
+@@ -107,9 +108,6 @@ struct nf_bridge_info {
+ 	atomic_t use;
+ 	struct net_device *physindev;
+ 	struct net_device *physoutdev;
+-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+-	struct net_device *netoutdev;
+-#endif
+ 	unsigned int mask;
+ 	unsigned long data[32 / sizeof(unsigned long)];
+ };
+@@ -287,6 +285,7 @@ struct sk_buff {
  	__u8			pkt_type:3,
  				fclone:2,
  				ipvs_property:1,
@@ -815540,7 +865079,7 @@
  				nf_trace:1;
  	__be16			protocol;
  
-@@ -1537,6 +1539,8 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
+@@ -1537,6 +1536,8 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
  		     skb = skb->prev)
  
  
@@ -815549,7 +865088,7 @@
  extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
  					 int noblock, int *err);
  extern unsigned int    datagram_poll(struct file *file, struct socket *sock,
-@@ -1548,7 +1552,7 @@ extern int	       skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
+@@ -1548,7 +1549,7 @@ extern int	       skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
  							int hlen,
  							struct iovec *iov);
  extern void	       skb_free_datagram(struct sock *sk, struct sk_buff *skb);
@@ -815558,7 +865097,7 @@
  					 unsigned int flags);
  extern __wsum	       skb_checksum(const struct sk_buff *skb, int offset,
  				    int len, __wsum csum);
-@@ -1559,6 +1563,11 @@ extern int	       skb_store_bits(struct sk_buff *skb, int offset,
+@@ -1559,6 +1560,11 @@ extern int	       skb_store_bits(struct sk_buff *skb, int offset,
  extern __wsum	       skb_copy_and_csum_bits(const struct sk_buff *skb,
  					      int offset, u8 *to, int len,
  					      __wsum csum);
@@ -815612,10 +865151,10 @@
  }
  
 diff --git a/include/linux/snmp.h b/include/linux/snmp.h
-index 89f0c2b..86d3eff 100644
+index 89f0c2b..5df62ef 100644
 --- a/include/linux/snmp.h
 +++ b/include/linux/snmp.h
-@@ -217,4 +217,35 @@ enum
+@@ -217,4 +217,36 @@ enum
  	__LINUX_MIB_MAX
  };
  
@@ -815629,7 +865168,7 @@
 +	LINUX_MIB_XFRMINNOSTATES,		/* XfrmInNoStates */
 +	LINUX_MIB_XFRMINSTATEPROTOERROR,	/* XfrmInStateProtoError */
 +	LINUX_MIB_XFRMINSTATEMODEERROR,		/* XfrmInStateModeError */
-+	LINUX_MIB_XFRMINSEQOUTOFWINDOW,		/* XfrmInSeqOutOfWindow */
++	LINUX_MIB_XFRMINSTATESEQERROR,		/* XfrmInStateSeqError */
 +	LINUX_MIB_XFRMINSTATEEXPIRED,		/* XfrmInStateExpired */
 +	LINUX_MIB_XFRMINSTATEMISMATCH,		/* XfrmInStateMismatch */
 +	LINUX_MIB_XFRMINSTATEINVALID,		/* XfrmInStateInvalid */
@@ -815643,6 +865182,7 @@
 +	LINUX_MIB_XFRMOUTNOSTATES,		/* XfrmOutNoStates */
 +	LINUX_MIB_XFRMOUTSTATEPROTOERROR,	/* XfrmOutStateProtoError */
 +	LINUX_MIB_XFRMOUTSTATEMODEERROR,	/* XfrmOutStateModeError */
++	LINUX_MIB_XFRMOUTSTATESEQERROR,		/* XfrmOutStateSeqError */
 +	LINUX_MIB_XFRMOUTSTATEEXPIRED,		/* XfrmOutStateExpired */
 +	LINUX_MIB_XFRMOUTPOLBLOCK,		/* XfrmOutPolBlock */
 +	LINUX_MIB_XFRMOUTPOLDEAD,		/* XfrmOutPolDead */
@@ -816040,6 +865580,21 @@
  # define print_stack_trace(trace, spaces)		do { } while (0)
  #endif
  
+diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
+index bd7a6b0..03547d6 100644
+--- a/include/linux/sunrpc/cache.h
++++ b/include/linux/sunrpc/cache.h
+@@ -169,8 +169,8 @@ extern int cache_check(struct cache_detail *detail,
+ extern void cache_flush(void);
+ extern void cache_purge(struct cache_detail *detail);
+ #define NEVER (0x7FFFFFFF)
+-extern void cache_register(struct cache_detail *cd);
+-extern int cache_unregister(struct cache_detail *cd);
++extern int cache_register(struct cache_detail *cd);
++extern void cache_unregister(struct cache_detail *cd);
+ 
+ extern void qword_add(char **bpp, int *lp, char *str);
+ extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
 diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
 index d9d5c5a..129a86e 100644
 --- a/include/linux/sunrpc/clnt.h
@@ -816111,6 +865666,19 @@
  
  #endif /* __KERNEL__ */
  #endif /* _LINUX_SUNRPC_CLNT_H */
+diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
+index 3912cf1..10709cb 100644
+--- a/include/linux/sunrpc/debug.h
++++ b/include/linux/sunrpc/debug.h
+@@ -20,7 +20,7 @@
+ #define RPCDBG_BIND		0x0020
+ #define RPCDBG_SCHED		0x0040
+ #define RPCDBG_TRANS		0x0080
+-#define RPCDBG_SVCSOCK		0x0100
++#define RPCDBG_SVCXPRT		0x0100
+ #define RPCDBG_SVCDSP		0x0200
+ #define RPCDBG_MISC		0x0400
+ #define RPCDBG_CACHE		0x0800
 diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
 index c4beb57..70df4f1 100644
 --- a/include/linux/sunrpc/msg_prot.h
@@ -816291,6 +865859,582 @@
  void		rpc_put_task(struct rpc_task *);
  void		rpc_exit_task(struct rpc_task *);
  void		rpc_release_calldata(const struct rpc_call_ops *, void *);
+diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
+index 8531a70..64c7710 100644
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -204,7 +204,7 @@ union svc_addr_u {
+ struct svc_rqst {
+ 	struct list_head	rq_list;	/* idle list */
+ 	struct list_head	rq_all;		/* all threads list */
+-	struct svc_sock *	rq_sock;	/* socket */
++	struct svc_xprt *	rq_xprt;	/* transport ptr */
+ 	struct sockaddr_storage	rq_addr;	/* peer address */
+ 	size_t			rq_addrlen;
+ 
+@@ -214,9 +214,10 @@ struct svc_rqst {
+ 	struct auth_ops *	rq_authop;	/* authentication flavour */
+ 	u32			rq_flavor;	/* pseudoflavor */
+ 	struct svc_cred		rq_cred;	/* auth info */
+-	struct sk_buff *	rq_skbuff;	/* fast recv inet buffer */
++	void *			rq_xprt_ctxt;	/* transport specific context ptr */
+ 	struct svc_deferred_req*rq_deferred;	/* deferred request we are replaying */
+ 
++	size_t			rq_xprt_hlen;	/* xprt header len */
+ 	struct xdr_buf		rq_arg;
+ 	struct xdr_buf		rq_res;
+ 	struct page *		rq_pages[RPCSVC_MAXPAGES];
+@@ -317,11 +318,12 @@ static inline void svc_free_res_pages(struct svc_rqst *rqstp)
+ 
+ struct svc_deferred_req {
+ 	u32			prot;	/* protocol (UDP or TCP) */
+-	struct svc_sock		*svsk;
++	struct svc_xprt		*xprt;
+ 	struct sockaddr_storage	addr;	/* where reply must go */
+ 	size_t			addrlen;
+ 	union svc_addr_u	daddr;	/* where reply must come from */
+ 	struct cache_deferred_req handle;
++	size_t			xprt_hlen;
+ 	int			argslen;
+ 	__be32			args[0];
+ };
+@@ -382,6 +384,8 @@ struct svc_procedure {
+  */
+ struct svc_serv *  svc_create(struct svc_program *, unsigned int,
+ 			      void (*shutdown)(struct svc_serv*));
++struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
++					struct svc_pool *pool);
+ int		   svc_create_thread(svc_thread_fn, struct svc_serv *);
+ void		   svc_exit_thread(struct svc_rqst *);
+ struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
+diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
+new file mode 100644
+index 0000000..c11bbcc
+--- /dev/null
++++ b/include/linux/sunrpc/svc_rdma.h
+@@ -0,0 +1,262 @@
++/*
++ * Copyright (c) 2005-2006 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#ifndef SVC_RDMA_H
++#define SVC_RDMA_H
++#include <linux/sunrpc/xdr.h>
++#include <linux/sunrpc/svcsock.h>
++#include <linux/sunrpc/rpc_rdma.h>
++#include <rdma/ib_verbs.h>
++#include <rdma/rdma_cm.h>
++#define SVCRDMA_DEBUG
++
++/* RPC/RDMA parameters and stats */
++extern unsigned int svcrdma_ord;
++extern unsigned int svcrdma_max_requests;
++extern unsigned int svcrdma_max_req_size;
++
++extern atomic_t rdma_stat_recv;
++extern atomic_t rdma_stat_read;
++extern atomic_t rdma_stat_write;
++extern atomic_t rdma_stat_sq_starve;
++extern atomic_t rdma_stat_rq_starve;
++extern atomic_t rdma_stat_rq_poll;
++extern atomic_t rdma_stat_rq_prod;
++extern atomic_t rdma_stat_sq_poll;
++extern atomic_t rdma_stat_sq_prod;
++
++#define RPCRDMA_VERSION 1
++
++/*
++ * Contexts are built when an RDMA request is created and are a
++ * record of the resources that can be recovered when the request
++ * completes.
++ */
++struct svc_rdma_op_ctxt {
++	struct svc_rdma_op_ctxt *next;
++	struct xdr_buf arg;
++	struct list_head dto_q;
++	enum ib_wr_opcode wr_op;
++	enum ib_wc_status wc_status;
++	u32 byte_len;
++	struct svcxprt_rdma *xprt;
++	unsigned long flags;
++	enum dma_data_direction direction;
++	int count;
++	struct ib_sge sge[RPCSVC_MAXPAGES];
++	struct page *pages[RPCSVC_MAXPAGES];
++};
++
++#define RDMACTXT_F_READ_DONE	1
++#define RDMACTXT_F_LAST_CTXT	2
++
++struct svcxprt_rdma {
++	struct svc_xprt      sc_xprt;		/* SVC transport structure */
++	struct rdma_cm_id    *sc_cm_id;		/* RDMA connection id */
++	struct list_head     sc_accept_q;	/* Conn. waiting accept */
++	int		     sc_ord;		/* RDMA read limit */
++	wait_queue_head_t    sc_read_wait;
++	int                  sc_max_sge;
++
++	int                  sc_sq_depth;	/* Depth of SQ */
++	atomic_t             sc_sq_count;	/* Number of SQ WR on queue */
++
++	int                  sc_max_requests;	/* Depth of RQ */
++	int                  sc_max_req_size;	/* Size of each RQ WR buf */
++
++	struct ib_pd         *sc_pd;
++
++	struct svc_rdma_op_ctxt  *sc_ctxt_head;
++	int		     sc_ctxt_cnt;
++	int		     sc_ctxt_bump;
++	int		     sc_ctxt_max;
++	spinlock_t	     sc_ctxt_lock;
++	struct list_head     sc_rq_dto_q;
++	spinlock_t	     sc_rq_dto_lock;
++	struct ib_qp         *sc_qp;
++	struct ib_cq         *sc_rq_cq;
++	struct ib_cq         *sc_sq_cq;
++	struct ib_mr         *sc_phys_mr;	/* MR for server memory */
++
++	spinlock_t	     sc_lock;		/* transport lock */
++
++	wait_queue_head_t    sc_send_wait;	/* SQ exhaustion waitlist */
++	unsigned long	     sc_flags;
++	struct list_head     sc_dto_q;		/* DTO tasklet I/O pending Q */
++	struct list_head     sc_read_complete_q;
++	spinlock_t           sc_read_complete_lock;
++};
++/* sc_flags */
++#define RDMAXPRT_RQ_PENDING	1
++#define RDMAXPRT_SQ_PENDING	2
++#define RDMAXPRT_CONN_PENDING	3
++
++#define RPCRDMA_LISTEN_BACKLOG  10
++/* The default ORD value is based on two outstanding full-size writes with a
++ * page size of 4k, or 32k * 2 ops / 4k = 16 outstanding RDMA_READ.  */
++#define RPCRDMA_ORD             (64/4)
++#define RPCRDMA_SQ_DEPTH_MULT   8
++#define RPCRDMA_MAX_THREADS     16
++#define RPCRDMA_MAX_REQUESTS    16
++#define RPCRDMA_MAX_REQ_SIZE    4096
++
++/* svc_rdma_marshal.c */
++extern void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *,
++				      int *, int *);
++extern int svc_rdma_xdr_decode_req(struct rpcrdma_msg **, struct svc_rqst *);
++extern int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *);
++extern int svc_rdma_xdr_encode_error(struct svcxprt_rdma *,
++				     struct rpcrdma_msg *,
++				     enum rpcrdma_errcode, u32 *);
++extern void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *, int);
++extern void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *, int);
++extern void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *, int,
++					    u32, u64, u32);
++extern void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *,
++					     struct rpcrdma_msg *,
++					     struct rpcrdma_msg *,
++					     enum rpcrdma_proc);
++extern int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *);
++
++/* svc_rdma_recvfrom.c */
++extern int svc_rdma_recvfrom(struct svc_rqst *);
++
++/* svc_rdma_sendto.c */
++extern int svc_rdma_sendto(struct svc_rqst *);
++
++/* svc_rdma_transport.c */
++extern int svc_rdma_send(struct svcxprt_rdma *, struct ib_send_wr *);
++extern int svc_rdma_send_error(struct svcxprt_rdma *, struct rpcrdma_msg *,
++			       enum rpcrdma_errcode);
++struct page *svc_rdma_get_page(void);
++extern int svc_rdma_post_recv(struct svcxprt_rdma *);
++extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
++extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
++extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
++extern void svc_sq_reap(struct svcxprt_rdma *);
++extern void svc_rq_reap(struct svcxprt_rdma *);
++extern struct svc_xprt_class svc_rdma_class;
++extern void svc_rdma_prep_reply_hdr(struct svc_rqst *);
++
++/* svc_rdma.c */
++extern int svc_rdma_init(void);
++extern void svc_rdma_cleanup(void);
++
++/*
++ * Returns the address of the first read chunk or <nul> if no read chunk is
++ * present
++ */
++static inline struct rpcrdma_read_chunk *
++svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp)
++{
++	struct rpcrdma_read_chunk *ch =
++		(struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
++
++	if (ch->rc_discrim == 0)
++		return NULL;
++
++	return ch;
++}
++
++/*
++ * Returns the address of the first read write array element or <nul> if no
++ * write array list is present
++ */
++static inline struct rpcrdma_write_array *
++svc_rdma_get_write_array(struct rpcrdma_msg *rmsgp)
++{
++	if (rmsgp->rm_body.rm_chunks[0] != 0
++	    || rmsgp->rm_body.rm_chunks[1] == 0)
++		return NULL;
++
++	return (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[1];
++}
++
++/*
++ * Returns the address of the first reply array element or <nul> if no
++ * reply array is present
++ */
++static inline struct rpcrdma_write_array *
++svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp)
++{
++	struct rpcrdma_read_chunk *rch;
++	struct rpcrdma_write_array *wr_ary;
++	struct rpcrdma_write_array *rp_ary;
++
++	/* XXX: Need to fix when reply list may occur with read-list and/or
++	 * write list */
++	if (rmsgp->rm_body.rm_chunks[0] != 0 ||
++	    rmsgp->rm_body.rm_chunks[1] != 0)
++		return NULL;
++
++	rch = svc_rdma_get_read_chunk(rmsgp);
++	if (rch) {
++		while (rch->rc_discrim)
++			rch++;
++
++		/* The reply list follows an empty write array located
++		 * at 'rc_position' here. The reply array is at rc_target.
++		 */
++		rp_ary = (struct rpcrdma_write_array *)&rch->rc_target;
++
++		goto found_it;
++	}
++
++	wr_ary = svc_rdma_get_write_array(rmsgp);
++	if (wr_ary) {
++		rp_ary = (struct rpcrdma_write_array *)
++			&wr_ary->
++			wc_array[wr_ary->wc_nchunks].wc_target.rs_length;
++
++		goto found_it;
++	}
++
++	/* No read list, no write list */
++	rp_ary = (struct rpcrdma_write_array *)
++		&rmsgp->rm_body.rm_chunks[2];
++
++ found_it:
++	if (rp_ary->wc_discrim == 0)
++		return NULL;
++
++	return rp_ary;
++}
++#endif
+diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
+new file mode 100644
+index 0000000..6fd7b01
+--- /dev/null
++++ b/include/linux/sunrpc/svc_xprt.h
+@@ -0,0 +1,159 @@
++/*
++ * linux/include/linux/sunrpc/svc_xprt.h
++ *
++ * RPC server transport I/O
++ */
++
++#ifndef SUNRPC_SVC_XPRT_H
++#define SUNRPC_SVC_XPRT_H
++
++#include <linux/sunrpc/svc.h>
++#include <linux/module.h>
++
++struct svc_xprt_ops {
++	struct svc_xprt	*(*xpo_create)(struct svc_serv *,
++				       struct sockaddr *, int,
++				       int);
++	struct svc_xprt	*(*xpo_accept)(struct svc_xprt *);
++	int		(*xpo_has_wspace)(struct svc_xprt *);
++	int		(*xpo_recvfrom)(struct svc_rqst *);
++	void		(*xpo_prep_reply_hdr)(struct svc_rqst *);
++	int		(*xpo_sendto)(struct svc_rqst *);
++	void		(*xpo_release_rqst)(struct svc_rqst *);
++	void		(*xpo_detach)(struct svc_xprt *);
++	void		(*xpo_free)(struct svc_xprt *);
++};
++
++struct svc_xprt_class {
++	const char		*xcl_name;
++	struct module		*xcl_owner;
++	struct svc_xprt_ops	*xcl_ops;
++	struct list_head	xcl_list;
++	u32			xcl_max_payload;
++};
++
++struct svc_xprt {
++	struct svc_xprt_class	*xpt_class;
++	struct svc_xprt_ops	*xpt_ops;
++	struct kref		xpt_ref;
++	struct list_head	xpt_list;
++	struct list_head	xpt_ready;
++	unsigned long		xpt_flags;
++#define	XPT_BUSY	0		/* enqueued/receiving */
++#define	XPT_CONN	1		/* conn pending */
++#define	XPT_CLOSE	2		/* dead or dying */
++#define	XPT_DATA	3		/* data pending */
++#define	XPT_TEMP	4		/* connected transport */
++#define	XPT_DEAD	6		/* transport closed */
++#define	XPT_CHNGBUF	7		/* need to change snd/rcv buf sizes */
++#define	XPT_DEFERRED	8		/* deferred request pending */
++#define	XPT_OLD		9		/* used for xprt aging mark+sweep */
++#define	XPT_DETACHED	10		/* detached from tempsocks list */
++#define XPT_LISTENER	11		/* listening endpoint */
++#define XPT_CACHE_AUTH	12		/* cache auth info */
++
++	struct svc_pool		*xpt_pool;	/* current pool iff queued */
++	struct svc_serv		*xpt_server;	/* service for transport */
++	atomic_t    	    	xpt_reserved;	/* space on outq that is rsvd */
++	struct mutex		xpt_mutex;	/* to serialize sending data */
++	spinlock_t		xpt_lock;	/* protects sk_deferred
++						 * and xpt_auth_cache */
++	void			*xpt_auth_cache;/* auth cache */
++	struct list_head	xpt_deferred;	/* deferred requests that need
++						 * to be revisted */
++	struct sockaddr_storage	xpt_local;	/* local address */
++	size_t			xpt_locallen;	/* length of address */
++	struct sockaddr_storage	xpt_remote;	/* remote peer's address */
++	size_t			xpt_remotelen;	/* length of address */
++};
++
++int	svc_reg_xprt_class(struct svc_xprt_class *);
++void	svc_unreg_xprt_class(struct svc_xprt_class *);
++void	svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
++		      struct svc_serv *);
++int	svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
++void	svc_xprt_enqueue(struct svc_xprt *xprt);
++void	svc_xprt_received(struct svc_xprt *);
++void	svc_xprt_put(struct svc_xprt *xprt);
++void	svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
++void	svc_close_xprt(struct svc_xprt *xprt);
++void	svc_delete_xprt(struct svc_xprt *xprt);
++int	svc_port_is_privileged(struct sockaddr *sin);
++int	svc_print_xprts(char *buf, int maxlen);
++struct	svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int);
++int	svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
++
++static inline void svc_xprt_get(struct svc_xprt *xprt)
++{
++	kref_get(&xprt->xpt_ref);
++}
++static inline void svc_xprt_set_local(struct svc_xprt *xprt,
++				      struct sockaddr *sa, int salen)
++{
++	memcpy(&xprt->xpt_local, sa, salen);
++	xprt->xpt_locallen = salen;
++}
++static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
++				       struct sockaddr *sa, int salen)
++{
++	memcpy(&xprt->xpt_remote, sa, salen);
++	xprt->xpt_remotelen = salen;
++}
++static inline unsigned short svc_addr_port(struct sockaddr *sa)
++{
++	unsigned short ret = 0;
++	switch (sa->sa_family) {
++	case AF_INET:
++		ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
++		break;
++	case AF_INET6:
++		ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
++		break;
++	}
++	return ret;
++}
++
++static inline size_t svc_addr_len(struct sockaddr *sa)
++{
++	switch (sa->sa_family) {
++	case AF_INET:
++		return sizeof(struct sockaddr_in);
++	case AF_INET6:
++		return sizeof(struct sockaddr_in6);
++	}
++	return -EAFNOSUPPORT;
++}
++
++static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
++{
++	return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
++}
++
++static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
++{
++	return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
++}
++
++static inline char *__svc_print_addr(struct sockaddr *addr,
++				     char *buf, size_t len)
++{
++	switch (addr->sa_family) {
++	case AF_INET:
++		snprintf(buf, len, "%u.%u.%u.%u, port=%u",
++			NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
++			ntohs(((struct sockaddr_in *) addr)->sin_port));
++		break;
++
++	case AF_INET6:
++		snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
++			NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
++			ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
++		break;
++
++	default:
++		snprintf(buf, len, "unknown address type: %d", addr->sa_family);
++		break;
++	}
++	return buf;
++}
++#endif /* SUNRPC_SVC_XPRT_H */
+diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
+index a53e0fa..206f092 100644
+--- a/include/linux/sunrpc/svcsock.h
++++ b/include/linux/sunrpc/svcsock.h
+@@ -10,42 +10,16 @@
+ #define SUNRPC_SVCSOCK_H
+ 
+ #include <linux/sunrpc/svc.h>
++#include <linux/sunrpc/svc_xprt.h>
+ 
+ /*
+  * RPC server socket.
+  */
+ struct svc_sock {
+-	struct list_head	sk_ready;	/* list of ready sockets */
+-	struct list_head	sk_list;	/* list of all sockets */
++	struct svc_xprt		sk_xprt;
+ 	struct socket *		sk_sock;	/* berkeley socket layer */
+ 	struct sock *		sk_sk;		/* INET layer */
+ 
+-	struct svc_pool *	sk_pool;	/* current pool iff queued */
+-	struct svc_serv *	sk_server;	/* service for this socket */
+-	atomic_t		sk_inuse;	/* use count */
+-	unsigned long		sk_flags;
+-#define	SK_BUSY		0			/* enqueued/receiving */
+-#define	SK_CONN		1			/* conn pending */
+-#define	SK_CLOSE	2			/* dead or dying */
+-#define	SK_DATA		3			/* data pending */
+-#define	SK_TEMP		4			/* temp (TCP) socket */
+-#define	SK_DEAD		6			/* socket closed */
+-#define	SK_CHNGBUF	7			/* need to change snd/rcv buffer sizes */
+-#define	SK_DEFERRED	8			/* request on sk_deferred */
+-#define	SK_OLD		9			/* used for temp socket aging mark+sweep */
+-#define	SK_DETACHED	10			/* detached from tempsocks list */
+-
+-	atomic_t    	    	sk_reserved;	/* space on outq that is reserved */
+-
+-	spinlock_t		sk_lock;	/* protects sk_deferred and
+-						 * sk_info_authunix */
+-	struct list_head	sk_deferred;	/* deferred requests that need to
+-						 * be revisted */
+-	struct mutex		sk_mutex;	/* to serialize sending data */
+-
+-	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
+-	int			(*sk_sendto)(struct svc_rqst *rqstp);
+-
+ 	/* We keep the old state_change and data_ready CB's here */
+ 	void			(*sk_ostate)(struct sock *);
+ 	void			(*sk_odata)(struct sock *, int bytes);
+@@ -54,21 +28,12 @@ struct svc_sock {
+ 	/* private TCP part */
+ 	int			sk_reclen;	/* length of record */
+ 	int			sk_tcplen;	/* current read length */
+-	time_t			sk_lastrecv;	/* time of last received request */
+-
+-	/* cache of various info for TCP sockets */
+-	void			*sk_info_authunix;
+-
+-	struct sockaddr_storage	sk_local;	/* local address */
+-	struct sockaddr_storage	sk_remote;	/* remote peer's address */
+-	int			sk_remotelen;	/* length of address */
+ };
+ 
+ /*
+  * Function prototypes.
+  */
+-int		svc_makesock(struct svc_serv *, int, unsigned short, int flags);
+-void		svc_force_close_socket(struct svc_sock *);
++void		svc_close_all(struct list_head *);
+ int		svc_recv(struct svc_rqst *, long);
+ int		svc_send(struct svc_rqst *);
+ void		svc_drop(struct svc_rqst *);
+@@ -78,6 +43,8 @@ int		svc_addsock(struct svc_serv *serv,
+ 			    int fd,
+ 			    char *name_return,
+ 			    int *proto);
++void		svc_init_xprt_sock(void);
++void		svc_cleanup_xprt_sock(void);
+ 
+ /*
+  * svc_makesock socket characteristics
+diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
+index 0751c94..e4057d7 100644
+--- a/include/linux/sunrpc/xdr.h
++++ b/include/linux/sunrpc/xdr.h
+@@ -112,7 +112,8 @@ struct xdr_buf {
+ __be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
+ __be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
+ __be32 *xdr_encode_string(__be32 *p, const char *s);
+-__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
++__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
++			unsigned int maxlen);
+ __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
+ __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
+ 
 diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
 index 30b17b3..b3ff9a8 100644
 --- a/include/linux/sunrpc/xprt.h
@@ -816352,10 +866496,102 @@
  static inline void xprt_set_connected(struct rpc_xprt *xprt)
  {
 diff --git a/include/linux/suspend.h b/include/linux/suspend.h
-index 4360e08..40280df 100644
+index 4360e08..646ce2d 100644
 --- a/include/linux/suspend.h
 +++ b/include/linux/suspend.h
-@@ -211,9 +211,6 @@ static inline int hibernate(void) { return -ENOSYS; }
+@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t;
+  *	There is the %suspend_valid_only_mem function available that can be
+  *	assigned to this if the platform only supports mem sleep.
+  *
+- * @set_target: Tell the platform which system sleep state is going to be
+- *	entered.
+- *	@set_target() is executed right prior to suspending devices.  The
+- *	information conveyed to the platform code by @set_target() should be
+- *	disregarded by the platform as soon as @finish() is executed and if
+- *	@prepare() fails.  If @set_target() fails (ie. returns nonzero),
++ * @begin: Initialise a transition to given system sleep state.
++ *	@begin() is executed right prior to suspending devices.  The information
++ *	conveyed to the platform code by @begin() should be disregarded by it as
++ *	soon as @end() is executed.  If @begin() fails (ie. returns nonzero),
+  *	@prepare(), @enter() and @finish() will not be called by the PM core.
+  *	This callback is optional.  However, if it is implemented, the argument
+- *	passed to @enter() is meaningless and should be ignored.
++ *	passed to @enter() is redundant and should be ignored.
+  *
+  * @prepare: Prepare the platform for entering the system sleep state indicated
+- *	by @set_target().
++ *	by @begin().
+  *	@prepare() is called right after devices have been suspended (ie. the
+  *	appropriate .suspend() method has been executed for each device) and
+  *	before the nonboot CPUs are disabled (it is executed with IRQs enabled).
+@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t;
+  *	error code otherwise, in which case the system cannot enter the desired
+  *	sleep state (@enter() and @finish() will not be called in that case).
+  *
+- * @enter: Enter the system sleep state indicated by @set_target() or
+- *	represented by the argument if @set_target() is not implemented.
++ * @enter: Enter the system sleep state indicated by @begin() or represented by
++ *	the argument if @begin() is not implemented.
+  *	This callback is mandatory.  It returns 0 on success or a negative
+  *	error code otherwise, in which case the system cannot enter the desired
+  *	sleep state.
+@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t;
+  *	This callback is optional, but should be implemented by the platforms
+  *	that implement @prepare().  If implemented, it is always called after
+  *	@enter() (even if @enter() fails).
++ *
++ * @end: Called by the PM core right after resuming devices, to indicate to
++ *	the platform that the system has returned to the working state or
++ *	the transition to the sleep state has been aborted.
++ *	This callback is optional, but should be implemented by the platforms
++ *	that implement @begin(), but platforms implementing @begin() should
++ *	also provide a @end() which cleans up transitions aborted before
++ *	@enter().
+  */
+ struct platform_suspend_ops {
+ 	int (*valid)(suspend_state_t state);
+-	int (*set_target)(suspend_state_t state);
++	int (*begin)(suspend_state_t state);
+ 	int (*prepare)(void);
+ 	int (*enter)(suspend_state_t state);
+ 	void (*finish)(void);
++	void (*end)(void);
+ };
+ 
+ #ifdef CONFIG_SUSPEND
+@@ -129,14 +136,17 @@ extern void mark_free_pages(struct zone *zone);
+ /**
+  * struct platform_hibernation_ops - hibernation platform support
+  *
+- * The methods in this structure allow a platform to override the default
+- * mechanism of shutting down the machine during a hibernation transition.
++ * The methods in this structure allow a platform to carry out special
++ * operations required by it during a hibernation transition.
+  *
+- * All three methods must be assigned.
++ * All the methods below must be implemented.
+  *
+- * @start: Tell the platform driver that we're starting hibernation.
++ * @begin: Tell the platform driver that we're starting hibernation.
+  *	Called right after shrinking memory and before freezing devices.
+  *
++ * @end: Called by the PM core right after resuming devices, to indicate to
++ *	the platform that the system has returned to the working state.
++ *
+  * @pre_snapshot: Prepare the platform for creating the hibernation image.
+  *	Called right after devices have been frozen and before the nonboot
+  *	CPUs are disabled (runs with IRQs on).
+@@ -171,7 +181,8 @@ extern void mark_free_pages(struct zone *zone);
+  *	thawing devices (runs with IRQs on).
+  */
+ struct platform_hibernation_ops {
+-	int (*start)(void);
++	int (*begin)(void);
++	void (*end)(void);
+ 	int (*pre_snapshot)(void);
+ 	void (*finish)(void);
+ 	int (*prepare)(void);
+@@ -211,22 +222,10 @@ static inline int hibernate(void) { return -ENOSYS; }
  #ifdef CONFIG_PM_SLEEP
  void save_processor_state(void);
  void restore_processor_state(void);
@@ -816364,11 +866600,75 @@
 -void __restore_processor_state(struct saved_context *ctxt);
  
  /* kernel/power/main.c */
- extern struct blocking_notifier_head pm_chain_head;
+-extern struct blocking_notifier_head pm_chain_head;
+-
+-static inline int register_pm_notifier(struct notifier_block *nb)
+-{
+-	return blocking_notifier_chain_register(&pm_chain_head, nb);
+-}
+-
+-static inline int unregister_pm_notifier(struct notifier_block *nb)
+-{
+-	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+-}
++extern int register_pm_notifier(struct notifier_block *nb);
++extern int unregister_pm_notifier(struct notifier_block *nb);
+ 
+ #define pm_notifier(fn, pri) {				\
+ 	static struct notifier_block fn##_nb =			\
+diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
+new file mode 100644
+index 0000000..2c6faec
+--- /dev/null
++++ b/include/linux/suspend_ioctls.h
+@@ -0,0 +1,32 @@
++#ifndef _LINUX_SUSPEND_IOCTLS_H
++#define _LINUX_SUSPEND_IOCTLS_H
++
++/*
++ * This structure is used to pass the values needed for the identification
++ * of the resume swap area from a user space to the kernel via the
++ * SNAPSHOT_SET_SWAP_AREA ioctl
++ */
++struct resume_swap_area {
++	loff_t offset;
++	u_int32_t dev;
++} __attribute__((packed));
++
++#define SNAPSHOT_IOC_MAGIC	'3'
++#define SNAPSHOT_FREEZE			_IO(SNAPSHOT_IOC_MAGIC, 1)
++#define SNAPSHOT_UNFREEZE		_IO(SNAPSHOT_IOC_MAGIC, 2)
++#define SNAPSHOT_ATOMIC_RESTORE		_IO(SNAPSHOT_IOC_MAGIC, 4)
++#define SNAPSHOT_FREE			_IO(SNAPSHOT_IOC_MAGIC, 5)
++#define SNAPSHOT_FREE_SWAP_PAGES	_IO(SNAPSHOT_IOC_MAGIC, 9)
++#define SNAPSHOT_S2RAM			_IO(SNAPSHOT_IOC_MAGIC, 11)
++#define SNAPSHOT_SET_SWAP_AREA		_IOW(SNAPSHOT_IOC_MAGIC, 13, \
++							struct resume_swap_area)
++#define SNAPSHOT_GET_IMAGE_SIZE		_IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
++#define SNAPSHOT_PLATFORM_SUPPORT	_IO(SNAPSHOT_IOC_MAGIC, 15)
++#define SNAPSHOT_POWER_OFF		_IO(SNAPSHOT_IOC_MAGIC, 16)
++#define SNAPSHOT_CREATE_IMAGE		_IOW(SNAPSHOT_IOC_MAGIC, 17, int)
++#define SNAPSHOT_PREF_IMAGE_SIZE	_IO(SNAPSHOT_IOC_MAGIC, 18)
++#define SNAPSHOT_AVAIL_SWAP_SIZE	_IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
++#define SNAPSHOT_ALLOC_SWAP_PAGE	_IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
++#define SNAPSHOT_IOC_MAXNR	20
++
++#endif /* _LINUX_SUSPEND_IOCTLS_H */
 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
-index 4f5047d..89faebf 100644
+index 4f5047d..bf4ae4e 100644
 --- a/include/linux/sysctl.h
 +++ b/include/linux/sysctl.h
+@@ -440,8 +440,8 @@ enum
+ 
+ enum {
+ 	NET_IPV4_ROUTE_FLUSH=1,
+-	NET_IPV4_ROUTE_MIN_DELAY=2,
+-	NET_IPV4_ROUTE_MAX_DELAY=3,
++	NET_IPV4_ROUTE_MIN_DELAY=2, /* obsolete since 2.6.25 */
++	NET_IPV4_ROUTE_MAX_DELAY=3, /* obsolete since 2.6.25 */
+ 	NET_IPV4_ROUTE_GC_THRESH=4,
+ 	NET_IPV4_ROUTE_MAX_SIZE=5,
+ 	NET_IPV4_ROUTE_GC_MIN_INTERVAL=6,
 @@ -945,7 +945,10 @@ enum
  
  /* For the /proc/sys support */
@@ -816479,10 +866779,18 @@
  	int     retransmit_cnt_hint;
  
 diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
-index 9c4ad75..dfbdfb9 100644
+index 9c4ad75..421323e 100644
 --- a/include/linux/thread_info.h
 +++ b/include/linux/thread_info.h
-@@ -42,27 +42,27 @@ extern long do_no_restart_syscall(struct restart_block *parm);
+@@ -23,6 +23,7 @@ struct restart_block {
+ 			u32 *uaddr;
+ 			u32 val;
+ 			u32 flags;
++			u32 bitset;
+ 			u64 time;
+ 		} futex;
+ 	};
+@@ -42,27 +43,27 @@ extern long do_no_restart_syscall(struct restart_block *parm);
  
  static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
  {
@@ -816516,21 +866824,32 @@
  
  #define set_thread_flag(flag) \
 diff --git a/include/linux/tick.h b/include/linux/tick.h
-index f4a1395..0fadf95 100644
+index f4a1395..a881c65 100644
 --- a/include/linux/tick.h
 +++ b/include/linux/tick.h
-@@ -51,8 +51,10 @@ struct tick_sched {
+@@ -39,6 +39,8 @@ enum tick_nohz_mode {
+  * @idle_calls:		Total number of idle calls
+  * @idle_sleeps:	Number of idle calls, where the sched tick was stopped
+  * @idle_entrytime:	Time when the idle call was entered
++ * @idle_waketime:	Time when the idle was interrupted
++ * @idle_exittime:	Time when the idle state was left
+  * @idle_sleeptime:	Sum of the time slept in idle with sched tick stopped
+  * @sleep_length:	Duration of the current idle sleep
+  */
+@@ -51,8 +53,12 @@ struct tick_sched {
  	unsigned long			idle_jiffies;
  	unsigned long			idle_calls;
  	unsigned long			idle_sleeps;
 +	int				idle_active;
  	ktime_t				idle_entrytime;
++	ktime_t				idle_waketime;
++	ktime_t				idle_exittime;
  	ktime_t				idle_sleeptime;
 +	ktime_t				idle_lastupdate;
  	ktime_t				sleep_length;
  	unsigned long			last_jiffies;
  	unsigned long			next_jiffies;
-@@ -103,6 +105,8 @@ extern void tick_nohz_stop_sched_tick(void);
+@@ -103,6 +109,8 @@ extern void tick_nohz_stop_sched_tick(void);
  extern void tick_nohz_restart_sched_tick(void);
  extern void tick_nohz_update_jiffies(void);
  extern ktime_t tick_nohz_get_sleep_length(void);
@@ -816539,7 +866858,7 @@
  # else
  static inline void tick_nohz_stop_sched_tick(void) { }
  static inline void tick_nohz_restart_sched_tick(void) { }
-@@ -113,6 +117,8 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
+@@ -113,6 +121,8 @@ static inline ktime_t tick_nohz_get_sleep_length(void)
  
  	return len;
  }
@@ -816561,6 +866880,18 @@
  
  	void                (*eject)(struct tifm_adapter *fm,
  				     struct tifm_dev *sock);
+diff --git a/include/linux/time.h b/include/linux/time.h
+index b04136d..ceaab9f 100644
+--- a/include/linux/time.h
++++ b/include/linux/time.h
+@@ -122,6 +122,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
+ extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
+ extern int timekeeping_is_continuous(void);
+ extern void update_wall_time(void);
++extern void update_xtime_cache(u64 nsec);
+ 
+ /**
+  * timespec_to_ns - Convert timespec to nanoseconds
 diff --git a/include/linux/timer.h b/include/linux/timer.h
 index 78cf899..de0e713 100644
 --- a/include/linux/timer.h
@@ -816650,6 +866981,19 @@
  
  /*
   * This character is the same as _POSIX_VDISABLE: it cannot be used as
+diff --git a/include/linux/types.h b/include/linux/types.h
+index f4f8d19..b94c0e4 100644
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -126,7 +126,7 @@ typedef		__s64		int64_t;
+ #endif
+ 
+ /* this is a special 64bit data type that is 8-byte aligned */
+-#define aligned_u64 unsigned long long __attribute__((aligned(8)))
++#define aligned_u64 __u64 __attribute__((aligned(8)))
+ #define aligned_be64 __be64 __attribute__((aligned(8)))
+ #define aligned_le64 __le64 __attribute__((aligned(8)))
+ 
 diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
 index 44c28e9..973386d 100644
 --- a/include/linux/uio_driver.h
@@ -816679,6 +867023,2139 @@
  };
  
  #define MAX_UIO_MAPS 	5
+diff --git a/include/linux/usb.h b/include/linux/usb.h
+index 5fc8ff7..2372e2e 100644
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -162,19 +162,19 @@ struct usb_interface {
+ 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
+ 
+ 	struct device dev;		/* interface specific device info */
+-	struct device *usb_dev;		/* pointer to the usb class's device, if any */
++	struct device *usb_dev;
+ 	int pm_usage_cnt;		/* usage counter for autosuspend */
+ };
+ #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
+ #define	interface_to_usbdev(intf) \
+ 	container_of(intf->dev.parent, struct usb_device, dev)
+ 
+-static inline void *usb_get_intfdata (struct usb_interface *intf)
++static inline void *usb_get_intfdata(struct usb_interface *intf)
+ {
+-	return dev_get_drvdata (&intf->dev);
++	return dev_get_drvdata(&intf->dev);
+ }
+ 
+-static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
++static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
+ {
+ 	dev_set_drvdata(&intf->dev, data);
+ }
+@@ -275,9 +275,10 @@ struct usb_host_config {
+ 
+ int __usb_get_extra_descriptor(char *buffer, unsigned size,
+ 	unsigned char type, void **ptr);
+-#define usb_get_extra_descriptor(ifpoint,type,ptr)\
+-	__usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\
+-		type,(void**)ptr)
++#define usb_get_extra_descriptor(ifpoint, type, ptr) \
++				__usb_get_extra_descriptor((ifpoint)->extra, \
++				(ifpoint)->extralen, \
++				type, (void **)ptr)
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+@@ -318,7 +319,7 @@ struct usb_bus {
+ #ifdef CONFIG_USB_DEVICEFS
+ 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
+ #endif
+-	struct class_device *class_dev;	/* class device for this bus */
++	struct device *dev;		/* device for this bus */
+ 
+ #if defined(CONFIG_USB_MON)
+ 	struct mon_bus *mon_bus;	/* non-null when associated */
+@@ -388,7 +389,7 @@ struct usb_device {
+ 	unsigned can_submit:1;		/* URBs may be submitted */
+ 	unsigned discon_suspended:1;	/* Disconnected while suspended */
+ 	unsigned have_langid:1;		/* whether string_langid is valid */
+-	unsigned authorized:1;		/* Policy has determined we can use it */
++	unsigned authorized:1;		/* Policy has said we can use it */
+ 	unsigned wusb:1;		/* Device is Wireless USB */
+ 	int string_langid;		/* language ID for strings */
+ 
+@@ -417,7 +418,10 @@ struct usb_device {
+ 
+ 	int pm_usage_cnt;		/* usage counter for autosuspend */
+ 	u32 quirks;			/* quirks of the whole device */
+-	atomic_t urbnum;		/* number of URBs submitted for the whole device */
++	atomic_t urbnum;		/* number of URBs submitted for
++					   the whole device */
++
++	unsigned long active_duration;	/* total time device is not suspended */
+ 
+ #ifdef CONFIG_PM
+ 	struct delayed_work autosuspend; /* for delayed autosuspends */
+@@ -425,6 +429,7 @@ struct usb_device {
+ 
+ 	unsigned long last_busy;	/* time of last use */
+ 	int autosuspend_delay;		/* in jiffies */
++	unsigned long connect_time;	/* time device was first connected */
+ 
+ 	unsigned auto_pm:1;		/* autosuspend/resume in progress */
+ 	unsigned do_remote_wakeup:1;	/* remote wakeup should be enabled */
+@@ -498,11 +503,11 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
+ /*-------------------------------------------------------------------------*/
+ 
+ /* for drivers using iso endpoints */
+-extern int usb_get_current_frame_number (struct usb_device *usb_dev);
++extern int usb_get_current_frame_number(struct usb_device *usb_dev);
+ 
+ /* used these for multi-interface device registration */
+ extern int usb_driver_claim_interface(struct usb_driver *driver,
+-			struct usb_interface *iface, void* priv);
++			struct usb_interface *iface, void *priv);
+ 
+ /**
+  * usb_interface_claimed - returns true iff an interface is claimed
+@@ -514,7 +519,8 @@ extern int usb_driver_claim_interface(struct usb_driver *driver,
+  * may need to explicitly claim that lock.
+  *
+  */
+-static inline int usb_interface_claimed(struct usb_interface *iface) {
++static inline int usb_interface_claimed(struct usb_interface *iface)
++{
+ 	return (iface->dev.driver != NULL);
+ }
+ 
+@@ -557,12 +563,11 @@ extern struct usb_host_interface *usb_altnum_to_altsetting(
+  * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
+  * high speed, and a different one if they are full or low speed.
+  */
+-static inline int usb_make_path (struct usb_device *dev, char *buf,
+-		size_t size)
++static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
+ {
+ 	int actual;
+-	actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name,
+-			dev->devpath);
++	actual = snprintf(buf, size, "usb-%s-%s", dev->bus->bus_name,
++			  dev->devpath);
+ 	return (actual >= (int)size) ? -1 : actual;
+ }
+ 
+@@ -608,7 +613,8 @@ static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+  *
+  * Returns true if the endpoint is of type OUT, otherwise it returns false.
+  */
+-static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_dir_out(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+ }
+@@ -619,7 +625,8 @@ static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd
+  *
+  * Returns true if the endpoint is of type bulk, otherwise it returns false.
+  */
+-static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_xfer_bulk(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ 		USB_ENDPOINT_XFER_BULK);
+@@ -631,7 +638,8 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e
+  *
+  * Returns true if the endpoint is of type control, otherwise it returns false.
+  */
+-static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_xfer_control(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ 		USB_ENDPOINT_XFER_CONTROL);
+@@ -644,7 +652,8 @@ static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor
+  * Returns true if the endpoint is of type interrupt, otherwise it returns
+  * false.
+  */
+-static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_xfer_int(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ 		USB_ENDPOINT_XFER_INT);
+@@ -657,7 +666,8 @@ static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *ep
+  * Returns true if the endpoint is of type isochronous, otherwise it returns
+  * false.
+  */
+-static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_xfer_isoc(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ 		USB_ENDPOINT_XFER_ISOC);
+@@ -670,7 +680,8 @@ static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *e
+  * Returns true if the endpoint has bulk transfer type and IN direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_bulk_in(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
+ }
+@@ -682,7 +693,8 @@ static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *
+  * Returns true if the endpoint has bulk transfer type and OUT direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_bulk_out(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
+ }
+@@ -694,7 +706,8 @@ static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor
+  * Returns true if the endpoint has interrupt transfer type and IN direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_int_in(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+ }
+@@ -706,7 +719,8 @@ static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *e
+  * Returns true if the endpoint has interrupt transfer type and OUT direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_int_out(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+ }
+@@ -718,7 +732,8 @@ static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *
+  * Returns true if the endpoint has isochronous transfer type and IN direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_isoc_in(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
+ }
+@@ -730,7 +745,8 @@ static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *
+  * Returns true if the endpoint has isochronous transfer type and OUT direction,
+  * otherwise it returns false.
+  */
+-static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
++static inline int usb_endpoint_is_isoc_out(
++				const struct usb_endpoint_descriptor *epd)
+ {
+ 	return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
+ }
+@@ -761,8 +777,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * specific device.
+  */
+ #define USB_DEVICE(vend,prod) \
+-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
+-			.idProduct = (prod)
++	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
++	.idVendor = (vend), \
++	.idProduct = (prod)
+ /**
+  * USB_DEVICE_VER - macro used to describe a specific usb device with a
+  *		version range
+@@ -774,10 +791,12 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * This macro is used to create a struct usb_device_id that matches a
+  * specific device, with a version range.
+  */
+-#define USB_DEVICE_VER(vend,prod,lo,hi) \
++#define USB_DEVICE_VER(vend, prod, lo, hi) \
+ 	.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
+-	.idVendor = (vend), .idProduct = (prod), \
+-	.bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
++	.idVendor = (vend), \
++	.idProduct = (prod), \
++	.bcdDevice_lo = (lo), \
++	.bcdDevice_hi = (hi)
+ 
+ /**
+  * USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb
+@@ -789,8 +808,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * This macro is used to create a struct usb_device_id that matches a
+  * specific interface protocol of devices.
+  */
+-#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \
+-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
++#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
++	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
++		       USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
+ 	.idVendor = (vend), \
+ 	.idProduct = (prod), \
+ 	.bInterfaceProtocol = (pr)
+@@ -804,12 +824,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * This macro is used to create a struct usb_device_id that matches a
+  * specific class of devices.
+  */
+-#define USB_DEVICE_INFO(cl,sc,pr) \
+-	.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \
+-	.bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
++#define USB_DEVICE_INFO(cl, sc, pr) \
++	.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
++	.bDeviceClass = (cl), \
++	.bDeviceSubClass = (sc), \
++	.bDeviceProtocol = (pr)
+ 
+ /**
+- * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces 
++ * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
+  * @cl: bInterfaceClass value
+  * @sc: bInterfaceSubClass value
+  * @pr: bInterfaceProtocol value
+@@ -817,9 +839,11 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * This macro is used to create a struct usb_device_id that matches a
+  * specific class of interfaces.
+  */
+-#define USB_INTERFACE_INFO(cl,sc,pr) \
+-	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
+-	.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
++#define USB_INTERFACE_INFO(cl, sc, pr) \
++	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
++	.bInterfaceClass = (cl), \
++	.bInterfaceSubClass = (sc), \
++	.bInterfaceProtocol = (pr)
+ 
+ /**
+  * USB_DEVICE_AND_INTERFACE_INFO - macro used to describe a specific usb device
+@@ -836,12 +860,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
+  * This is especially useful when explicitly matching devices that have
+  * vendor specific bDeviceClass values, but standards-compliant interfaces.
+  */
+-#define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
++#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
+ 	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+ 		| USB_DEVICE_ID_MATCH_DEVICE, \
+-	.idVendor = (vend), .idProduct = (prod), \
++	.idVendor = (vend), \
++	.idProduct = (prod), \
+ 	.bInterfaceClass = (cl), \
+-	.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
++	.bInterfaceSubClass = (sc), \
++	.bInterfaceProtocol = (pr)
+ 
+ /* ----------------------------------------------------------------------- */
+ 
+@@ -1119,7 +1145,7 @@ typedef void (*usb_complete_t)(struct urb *);
+  *	transferred.  It will normally be the same as requested, unless
+  *	either an error was reported or a short read was performed.
+  *	The URB_SHORT_NOT_OK transfer flag may be used to make such
+- *	short reads be reported as errors. 
++ *	short reads be reported as errors.
+  * @setup_packet: Only used for control transfers, this points to eight bytes
+  *	of setup data.  Control transfers always start by sending this data
+  *	to the device.  Then transfer_buffer is read or written, if needed.
+@@ -1138,7 +1164,7 @@ typedef void (*usb_complete_t)(struct urb *);
+  * @complete: Completion handler. This URB is passed as the parameter to the
+  *	completion function.  The completion function may then do what
+  *	it likes with the URB, including resubmitting or freeing it.
+- * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to 
++ * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to
+  *	collect the transfer status for each buffer.
+  *
+  * This structure identifies USB transfer requests.  URBs must be allocated by
+@@ -1242,8 +1268,7 @@ typedef void (*usb_complete_t)(struct urb *);
+  * when the urb is owned by the hcd, that is, since the call to
+  * usb_submit_urb() till the entry into the completion routine.
+  */
+-struct urb
+-{
++struct urb {
+ 	/* private: usb core and host controller only fields in the urb */
+ 	struct kref kref;		/* reference count of the URB */
+ 	void *hcpriv;			/* private data for host controller */
+@@ -1254,10 +1279,10 @@ struct urb
+ 	/* public: documented fields in the urb that can be used by drivers */
+ 	struct list_head urb_list;	/* list head for use by the urb's
+ 					 * current owner */
+-	struct list_head anchor_list;	/* the URB may be anchored by the driver */
++	struct list_head anchor_list;	/* the URB may be anchored */
+ 	struct usb_anchor *anchor;
+ 	struct usb_device *dev; 	/* (in) pointer to associated device */
+-	struct usb_host_endpoint *ep;	/* (internal) pointer to endpoint struct */
++	struct usb_host_endpoint *ep;	/* (internal) pointer to endpoint */
+ 	unsigned int pipe;		/* (in) pipe information */
+ 	int status;			/* (return) non-ISO status */
+ 	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
+@@ -1294,14 +1319,14 @@ struct urb
+  * Initializes a control urb with the proper information needed to submit
+  * it to a device.
+  */
+-static inline void usb_fill_control_urb (struct urb *urb,
+-					 struct usb_device *dev,
+-					 unsigned int pipe,
+-					 unsigned char *setup_packet,
+-					 void *transfer_buffer,
+-					 int buffer_length,
+-					 usb_complete_t complete_fn,
+-					 void *context)
++static inline void usb_fill_control_urb(struct urb *urb,
++					struct usb_device *dev,
++					unsigned int pipe,
++					unsigned char *setup_packet,
++					void *transfer_buffer,
++					int buffer_length,
++					usb_complete_t complete_fn,
++					void *context)
+ {
+ 	urb->dev = dev;
+ 	urb->pipe = pipe;
+@@ -1325,13 +1350,13 @@ static inline void usb_fill_control_urb (struct urb *urb,
+  * Initializes a bulk urb with the proper information needed to submit it
+  * to a device.
+  */
+-static inline void usb_fill_bulk_urb (struct urb *urb,
+-				      struct usb_device *dev,
+-				      unsigned int pipe,
+-				      void *transfer_buffer,
+-				      int buffer_length,
+-				      usb_complete_t complete_fn,
+-				      void *context)
++static inline void usb_fill_bulk_urb(struct urb *urb,
++				     struct usb_device *dev,
++				     unsigned int pipe,
++				     void *transfer_buffer,
++				     int buffer_length,
++				     usb_complete_t complete_fn,
++				     void *context)
+ {
+ 	urb->dev = dev;
+ 	urb->pipe = pipe;
+@@ -1359,14 +1384,14 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
+  * the endpoint interval, and express polling intervals in microframes
+  * (eight per millisecond) rather than in frames (one per millisecond).
+  */
+-static inline void usb_fill_int_urb (struct urb *urb,
+-				     struct usb_device *dev,
+-				     unsigned int pipe,
+-				     void *transfer_buffer,
+-				     int buffer_length,
+-				     usb_complete_t complete_fn,
+-				     void *context,
+-				     int interval)
++static inline void usb_fill_int_urb(struct urb *urb,
++				    struct usb_device *dev,
++				    unsigned int pipe,
++				    void *transfer_buffer,
++				    int buffer_length,
++				    usb_complete_t complete_fn,
++				    void *context,
++				    int interval)
+ {
+ 	urb->dev = dev;
+ 	urb->pipe = pipe;
+@@ -1419,15 +1444,15 @@ static inline int usb_urb_dir_out(struct urb *urb)
+ 	return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
+ }
+ 
+-void *usb_buffer_alloc (struct usb_device *dev, size_t size,
++void *usb_buffer_alloc(struct usb_device *dev, size_t size,
+ 	gfp_t mem_flags, dma_addr_t *dma);
+-void usb_buffer_free (struct usb_device *dev, size_t size,
++void usb_buffer_free(struct usb_device *dev, size_t size,
+ 	void *addr, dma_addr_t dma);
+ 
+ #if 0
+-struct urb *usb_buffer_map (struct urb *urb);
+-void usb_buffer_dmasync (struct urb *urb);
+-void usb_buffer_unmap (struct urb *urb);
++struct urb *usb_buffer_map(struct urb *urb);
++void usb_buffer_dmasync(struct urb *urb);
++void usb_buffer_unmap(struct urb *urb);
+ #endif
+ 
+ struct scatterlist;
+@@ -1499,7 +1524,7 @@ struct usb_sg_request {
+ 	int			status;
+ 	size_t			bytes;
+ 
+-	/* 
++	/*
+ 	 * members below are private: to usbcore,
+ 	 * and are not provided for driver access!
+ 	 */
+@@ -1517,18 +1542,18 @@ struct usb_sg_request {
+ 	struct completion	complete;
+ };
+ 
+-int usb_sg_init (
++int usb_sg_init(
+ 	struct usb_sg_request	*io,
+ 	struct usb_device	*dev,
+-	unsigned		pipe, 
++	unsigned		pipe,
+ 	unsigned		period,
+ 	struct scatterlist	*sg,
+ 	int			nents,
+ 	size_t			length,
+ 	gfp_t			mem_flags
+ );
+-void usb_sg_cancel (struct usb_sg_request *io);
+-void usb_sg_wait (struct usb_sg_request *io);
++void usb_sg_cancel(struct usb_sg_request *io);
++void usb_sg_wait(struct usb_sg_request *io);
+ 
+ 
+ /* ----------------------------------------------------------------------- */
+@@ -1585,21 +1610,21 @@ static inline unsigned int __create_pipe(struct usb_device *dev,
+ 
+ /* Create various pipes... */
+ #define usb_sndctrlpipe(dev,endpoint)	\
+-	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
++	((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
+ #define usb_rcvctrlpipe(dev,endpoint)	\
+-	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
++	((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
+ #define usb_sndisocpipe(dev,endpoint)	\
+-	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
++	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
+ #define usb_rcvisocpipe(dev,endpoint)	\
+-	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
++	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
+ #define usb_sndbulkpipe(dev,endpoint)	\
+-	((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
++	((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
+ #define usb_rcvbulkpipe(dev,endpoint)	\
+-	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
++	((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
+ #define usb_sndintpipe(dev,endpoint)	\
+-	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
++	((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
+ #define usb_rcvintpipe(dev,endpoint)	\
+-	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
++	((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
+index 6ce42bf..b8cba1d 100644
+--- a/include/linux/usb/Kbuild
++++ b/include/linux/usb/Kbuild
+@@ -1,6 +1,7 @@
+-unifdef-y += audio.h
+-unifdef-y += cdc.h
+-unifdef-y += ch9.h
+-unifdef-y += gadgetfs.h
+-unifdef-y += midi.h
++header-y += audio.h
++header-y += cdc.h
++header-y += ch9.h
++header-y += gadgetfs.h
++header-y += midi.h
++unifdef-y += g_printer.h
+ 
+diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
+index 6bd2359..2dfeef1 100644
+--- a/include/linux/usb/audio.h
++++ b/include/linux/usb/audio.h
+@@ -27,13 +27,13 @@
+ 
+ /* 4.3.2  Class-Specific AC Interface Descriptor */
+ struct usb_ac_header_descriptor {
+-	__u8  bLength;			// 8+n
+-	__u8  bDescriptorType;		// USB_DT_CS_INTERFACE
+-	__u8  bDescriptorSubtype;	// USB_MS_HEADER
+-	__le16 bcdADC;			// 0x0100
+-	__le16 wTotalLength;		// includes Unit and Terminal desc.
+-	__u8  bInCollection;		// n
+-	__u8  baInterfaceNr[];		// [n]
++	__u8  bLength;			/* 8+n */
++	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
++	__u8  bDescriptorSubtype;	/* USB_MS_HEADER */
++	__le16 bcdADC;			/* 0x0100 */
++	__le16 wTotalLength;		/* includes Unit and Terminal desc. */
++	__u8  bInCollection;		/* n */
++	__u8  baInterfaceNr[];		/* [n] */
+ } __attribute__ ((packed));
+ 
+ #define USB_DT_AC_HEADER_SIZE(n)	(8+(n))
+diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
+index 2204ae2..94ee4ec 100644
+--- a/include/linux/usb/cdc.h
++++ b/include/linux/usb/cdc.h
+@@ -29,16 +29,16 @@
+  * Class-Specific descriptors ... there are a couple dozen of them
+  */
+ 
+-#define USB_CDC_HEADER_TYPE		0x00		/* header_desc */
+-#define USB_CDC_CALL_MANAGEMENT_TYPE	0x01		/* call_mgmt_descriptor */
+-#define USB_CDC_ACM_TYPE		0x02		/* acm_descriptor */
+-#define USB_CDC_UNION_TYPE		0x06		/* union_desc */
++#define USB_CDC_HEADER_TYPE		0x00	/* header_desc */
++#define USB_CDC_CALL_MANAGEMENT_TYPE	0x01	/* call_mgmt_descriptor */
++#define USB_CDC_ACM_TYPE		0x02	/* acm_descriptor */
++#define USB_CDC_UNION_TYPE		0x06	/* union_desc */
+ #define USB_CDC_COUNTRY_TYPE		0x07
+-#define USB_CDC_NETWORK_TERMINAL_TYPE	0x0a		/* network_terminal_desc */
+-#define USB_CDC_ETHERNET_TYPE		0x0f		/* ether_desc */
++#define USB_CDC_NETWORK_TERMINAL_TYPE	0x0a	/* network_terminal_desc */
++#define USB_CDC_ETHERNET_TYPE		0x0f	/* ether_desc */
+ #define USB_CDC_WHCM_TYPE		0x11
+-#define USB_CDC_MDLM_TYPE		0x12		/* mdlm_desc */
+-#define USB_CDC_MDLM_DETAIL_TYPE	0x13		/* mdlm_detail_desc */
++#define USB_CDC_MDLM_TYPE		0x12	/* mdlm_desc */
++#define USB_CDC_MDLM_DETAIL_TYPE	0x13	/* mdlm_detail_desc */
+ #define USB_CDC_DMM_TYPE		0x14
+ #define USB_CDC_OBEX_TYPE		0x15
+ 
+diff --git a/include/linux/usb/g_printer.h b/include/linux/usb/g_printer.h
+new file mode 100644
+index 0000000..0c5ea1e
+--- /dev/null
++++ b/include/linux/usb/g_printer.h
+@@ -0,0 +1,31 @@
++/*
++ * g_printer.h -- Header file for USB Printer gadget driver
++ *
++ * Copyright (C) 2007 Craig W. Nadler
++ *
++ * 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
++ */
++
++
++#define PRINTER_NOT_ERROR	0x08
++#define PRINTER_SELECTED	0x10
++#define PRINTER_PAPER_EMPTY	0x20
++
++/* The 'g' code is also used by gadgetfs ioctl requests.
++ * Don't add any colliding codes to either driver, and keep
++ * them in unique ranges (size 0x20 for now).
++ */
++#define GADGET_GET_PRINTER_STATUS	_IOR('g', 0x21, unsigned char)
++#define GADGET_SET_PRINTER_STATUS	_IOWR('g', 0x22, unsigned char)
+diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
+index c1527c2..aa3047f 100644
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -70,9 +70,10 @@ struct usb_ep;
+  *
+  * Bulk endpoints can use any size buffers, and can also be used for interrupt
+  * transfers. interrupt-only endpoints can be much less functional.
++ *
++ * NOTE:  this is analagous to 'struct urb' on the host side, except that
++ * it's thinner and promotes more pre-allocation.
+  */
+-	// NOTE this is analagous to 'struct urb' on the host side,
+-	// except that it's thinner and promotes more pre-allocation.
+ 
+ struct usb_request {
+ 	void			*buf;
+@@ -168,10 +169,10 @@ struct usb_ep {
+  *
+  * returns zero, or a negative error code.
+  */
+-static inline int
+-usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
++static inline int usb_ep_enable(struct usb_ep *ep,
++				const struct usb_endpoint_descriptor *desc)
+ {
+-	return ep->ops->enable (ep, desc);
++	return ep->ops->enable(ep, desc);
+ }
+ 
+ /**
+@@ -186,10 +187,9 @@ usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+  *
+  * returns zero, or a negative error code.
+  */
+-static inline int
+-usb_ep_disable (struct usb_ep *ep)
++static inline int usb_ep_disable(struct usb_ep *ep)
+ {
+-	return ep->ops->disable (ep);
++	return ep->ops->disable(ep);
+ }
+ 
+ /**
+@@ -206,10 +206,10 @@ usb_ep_disable (struct usb_ep *ep)
+  *
+  * Returns the request, or null if one could not be allocated.
+  */
+-static inline struct usb_request *
+-usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
++static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
++						       gfp_t gfp_flags)
+ {
+-	return ep->ops->alloc_request (ep, gfp_flags);
++	return ep->ops->alloc_request(ep, gfp_flags);
+ }
+ 
+ /**
+@@ -221,10 +221,10 @@ usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
+  * Caller guarantees the request is not queued, and that it will
+  * no longer be requeued (or otherwise used).
+  */
+-static inline void
+-usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
++static inline void usb_ep_free_request(struct usb_ep *ep,
++				       struct usb_request *req)
+ {
+-	ep->ops->free_request (ep, req);
++	ep->ops->free_request(ep, req);
+ }
+ 
+ /**
+@@ -281,10 +281,10 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+  * report errors; errors will also be
+  * reported when the usb peripheral is disconnected.
+  */
+-static inline int
+-usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
++static inline int usb_ep_queue(struct usb_ep *ep,
++			       struct usb_request *req, gfp_t gfp_flags)
+ {
+-	return ep->ops->queue (ep, req, gfp_flags);
++	return ep->ops->queue(ep, req, gfp_flags);
+ }
+ 
+ /**
+@@ -301,9 +301,9 @@ usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
+  * restrictions prevent drivers from supporting configuration changes,
+  * even to configuration zero (a "chapter 9" requirement).
+  */
+-static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
++static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+ {
+-	return ep->ops->dequeue (ep, req);
++	return ep->ops->dequeue(ep, req);
+ }
+ 
+ /**
+@@ -327,10 +327,9 @@ static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+  * transfer requests are still queued, or if the controller hardware
+  * (usually a FIFO) still holds bytes that the host hasn't collected.
+  */
+-static inline int
+-usb_ep_set_halt (struct usb_ep *ep)
++static inline int usb_ep_set_halt(struct usb_ep *ep)
+ {
+-	return ep->ops->set_halt (ep, 1);
++	return ep->ops->set_halt(ep, 1);
+ }
+ 
+ /**
+@@ -346,10 +345,9 @@ usb_ep_set_halt (struct usb_ep *ep)
+  * Note that some hardware can't support this request (like pxa2xx_udc),
+  * and accordingly can't correctly implement interface altsettings.
+  */
+-static inline int
+-usb_ep_clear_halt (struct usb_ep *ep)
++static inline int usb_ep_clear_halt(struct usb_ep *ep)
+ {
+-	return ep->ops->set_halt (ep, 0);
++	return ep->ops->set_halt(ep, 0);
+ }
+ 
+ /**
+@@ -367,11 +365,10 @@ usb_ep_clear_halt (struct usb_ep *ep)
+  * errno if the endpoint doesn't use a FIFO or doesn't support such
+  * precise handling.
+  */
+-static inline int
+-usb_ep_fifo_status (struct usb_ep *ep)
++static inline int usb_ep_fifo_status(struct usb_ep *ep)
+ {
+ 	if (ep->ops->fifo_status)
+-		return ep->ops->fifo_status (ep);
++		return ep->ops->fifo_status(ep);
+ 	else
+ 		return -EOPNOTSUPP;
+ }
+@@ -385,11 +382,10 @@ usb_ep_fifo_status (struct usb_ep *ep)
+  * must never be used except when endpoint is not being used for any
+  * protocol translation.
+  */
+-static inline void
+-usb_ep_fifo_flush (struct usb_ep *ep)
++static inline void usb_ep_fifo_flush(struct usb_ep *ep)
+ {
+ 	if (ep->ops->fifo_flush)
+-		ep->ops->fifo_flush (ep);
++		ep->ops->fifo_flush(ep);
+ }
+ 
+ 
+@@ -469,10 +465,10 @@ struct usb_gadget {
+ 	struct device			dev;
+ };
+ 
+-static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
+-	{ dev_set_drvdata (&gadget->dev, data); }
+-static inline void *get_gadget_data (struct usb_gadget *gadget)
+-	{ return dev_get_drvdata (&gadget->dev); }
++static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
++	{ dev_set_drvdata(&gadget->dev, data); }
++static inline void *get_gadget_data(struct usb_gadget *gadget)
++	{ return dev_get_drvdata(&gadget->dev); }
+ 
+ /* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
+ #define gadget_for_each_ep(tmp,gadget) \
+@@ -511,7 +507,6 @@ static inline int gadget_is_otg(struct usb_gadget *g)
+ #endif
+ }
+ 
+-
+ /**
+  * usb_gadget_frame_number - returns the current frame number
+  * @gadget: controller that reports the frame number
+@@ -519,9 +514,9 @@ static inline int gadget_is_otg(struct usb_gadget *g)
+  * Returns the usb frame number, normally eleven bits from a SOF packet,
+  * or negative errno if this device doesn't support this capability.
+  */
+-static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
++static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
+ {
+-	return gadget->ops->get_frame (gadget);
++	return gadget->ops->get_frame(gadget);
+ }
+ 
+ /**
+@@ -537,11 +532,11 @@ static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+  * even if OTG isn't otherwise in use.  OTG devices may also start
+  * remote wakeup even when hosts don't explicitly enable it.
+  */
+-static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
++static inline int usb_gadget_wakeup(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->wakeup)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->wakeup (gadget);
++	return gadget->ops->wakeup(gadget);
+ }
+ 
+ /**
+@@ -553,12 +548,11 @@ static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+  *
+  * returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_set_selfpowered (struct usb_gadget *gadget)
++static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->set_selfpowered)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->set_selfpowered (gadget, 1);
++	return gadget->ops->set_selfpowered(gadget, 1);
+ }
+ 
+ /**
+@@ -571,12 +565,11 @@ usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+  *
+  * returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
++static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->set_selfpowered)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->set_selfpowered (gadget, 0);
++	return gadget->ops->set_selfpowered(gadget, 0);
+ }
+ 
+ /**
+@@ -591,12 +584,11 @@ usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+  *
+  * Returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_vbus_connect(struct usb_gadget *gadget)
++static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->vbus_session)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->vbus_session (gadget, 1);
++	return gadget->ops->vbus_session(gadget, 1);
+ }
+ 
+ /**
+@@ -611,12 +603,11 @@ usb_gadget_vbus_connect(struct usb_gadget *gadget)
+  *
+  * Returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
++static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+ {
+ 	if (!gadget->ops->vbus_draw)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->vbus_draw (gadget, mA);
++	return gadget->ops->vbus_draw(gadget, mA);
+ }
+ 
+ /**
+@@ -629,12 +620,11 @@ usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+  *
+  * Returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
++static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->vbus_session)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->vbus_session (gadget, 0);
++	return gadget->ops->vbus_session(gadget, 0);
+ }
+ 
+ /**
+@@ -648,12 +638,11 @@ usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+  *
+  * Returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_connect (struct usb_gadget *gadget)
++static inline int usb_gadget_connect(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->pullup)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->pullup (gadget, 1);
++	return gadget->ops->pullup(gadget, 1);
+ }
+ 
+ /**
+@@ -671,16 +660,14 @@ usb_gadget_connect (struct usb_gadget *gadget)
+  *
+  * Returns zero on success, else negative errno.
+  */
+-static inline int
+-usb_gadget_disconnect (struct usb_gadget *gadget)
++static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
+ {
+ 	if (!gadget->ops->pullup)
+ 		return -EOPNOTSUPP;
+-	return gadget->ops->pullup (gadget, 0);
++	return gadget->ops->pullup(gadget, 0);
+ }
+ 
+ 
+-
+ /*-------------------------------------------------------------------------*/
+ 
+ /**
+@@ -764,7 +751,7 @@ struct usb_gadget_driver {
+ 	void			(*suspend)(struct usb_gadget *);
+ 	void			(*resume)(struct usb_gadget *);
+ 
+-	// FIXME support safe rmmod
++	/* FIXME support safe rmmod */
+ 	struct device_driver	driver;
+ };
+ 
+@@ -790,7 +777,7 @@ struct usb_gadget_driver {
+  * the bind() functions will be in init sections.
+  * This function must be called in a context that can sleep.
+  */
+-int usb_gadget_register_driver (struct usb_gadget_driver *driver);
++int usb_gadget_register_driver(struct usb_gadget_driver *driver);
+ 
+ /**
+  * usb_gadget_unregister_driver - unregister a gadget driver
+@@ -805,7 +792,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+  * will in in exit sections, so may not be linked in some kernels.
+  * This function must be called in a context that can sleep.
+  */
+-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -838,7 +825,7 @@ struct usb_gadget_strings {
+ };
+ 
+ /* put descriptor for string with that id into buf (buflen >= 256) */
+-int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
++int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf);
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -856,10 +843,10 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
+ 
+ /* utility wrapping a simple endpoint selection policy */
+ 
+-extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
++extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
+ 			struct usb_endpoint_descriptor *) __devinit;
+ 
+-extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
++extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit;
+ 
+ #endif  /* __KERNEL__ */
+ 
+diff --git a/include/linux/usb/gadgetfs.h b/include/linux/usb/gadgetfs.h
+index e8654c3..c291ab1 100644
+--- a/include/linux/usb/gadgetfs.h
++++ b/include/linux/usb/gadgetfs.h
+@@ -36,7 +36,7 @@ enum usb_gadgetfs_event_type {
+ 	GADGETFS_DISCONNECT,
+ 	GADGETFS_SETUP,
+ 	GADGETFS_SUSPEND,
+-	// and likely more !
++	/* and likely more ! */
+ };
+ 
+ /* NOTE:  this structure must stay the same size and layout on
+@@ -44,21 +44,28 @@ enum usb_gadgetfs_event_type {
+  */
+ struct usb_gadgetfs_event {
+ 	union {
+-		// NOP, DISCONNECT, SUSPEND: nothing
+-		// ... some hardware can't report disconnection
++		/* NOP, DISCONNECT, SUSPEND: nothing
++		 * ... some hardware can't report disconnection
++		 */
+ 
+-		// CONNECT: just the speed
++		/* CONNECT: just the speed */
+ 		enum usb_device_speed	speed;
+ 
+-		// SETUP: packet; DATA phase i/o precedes next event
+-		// (setup.bmRequestType & USB_DIR_IN) flags direction
+-		// ... includes SET_CONFIGURATION, SET_INTERFACE
++		/* SETUP: packet; DATA phase i/o precedes next event
++		 *(setup.bmRequestType & USB_DIR_IN) flags direction
++		 * ... includes SET_CONFIGURATION, SET_INTERFACE
++		 */
+ 		struct usb_ctrlrequest	setup;
+ 	} u;
+ 	enum usb_gadgetfs_event_type	type;
+ };
+ 
+ 
++/* The 'g' code is also used by printer gadget ioctl requests.
++ * Don't add any colliding codes to either driver, and keep
++ * them in unique ranges (size 0x20 for now).
++ */
++
+ /* endpoint ioctls */
+ 
+ /* IN transfers may be reported to the gadget driver as complete
+@@ -68,14 +75,14 @@ struct usb_gadgetfs_event {
+  * THIS returns how many bytes are "unclaimed" in the endpoint fifo
+  * (needed for precise fault handling, when the hardware allows it)
+  */
+-#define	GADGETFS_FIFO_STATUS	_IO('g',1)
++#define	GADGETFS_FIFO_STATUS	_IO('g', 1)
+ 
+ /* discards any unclaimed data in the fifo. */
+-#define	GADGETFS_FIFO_FLUSH	_IO('g',2)
++#define	GADGETFS_FIFO_FLUSH	_IO('g', 2)
+ 
+ /* resets endpoint halt+toggle; used to implement set_interface.
+  * some hardware (like pxa2xx) can't support this.
+  */
+-#define	GADGETFS_CLEAR_HALT	_IO('g',3)
++#define	GADGETFS_CLEAR_HALT	_IO('g', 3)
+ 
+ #endif /* __LINUX_USB_GADGETFS_H */
+diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h
+index cbbe020..de6f380 100644
+--- a/include/linux/usb/iowarrior.h
++++ b/include/linux/usb/iowarrior.h
+@@ -14,14 +14,23 @@
+    this information.
+ */
+ struct iowarrior_info {
+-	__u32 vendor;		/* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
+-	__u32 product;		/* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */
+-	__u8 serial[9];		/* the serial number of our chip (if a serial-number is not available this is empty string) */
+-	__u32 revision;		/* revision number of the chip */
+-	__u32 speed;		/* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
+-	__u32 power;		/* power consumption of the device in mA */
+-	__u32 if_num;		/* the number of the endpoint */
+-	__u32 report_size;	/* size of the data-packets on this interface */
++	/* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
++	__u32 vendor;
++	/* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_X) */
++	__u32 product;
++	/* the serial number of our chip (if a serial-number is not available
++	 * this is empty string) */
++	__u8 serial[9];
++	/* revision number of the chip */
++	__u32 revision;
++	/* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
++	__u32 speed;
++	/* power consumption of the device in mA */
++	__u32 power;
++	/* the number of the endpoint */
++	__u32 if_num;
++	/* size of the data-packets on this interface */
++	__u32 report_size;
+ };
+ 
+ /*
+diff --git a/include/linux/usb/isp116x.h b/include/linux/usb/isp116x.h
+index 436dd8a..67d2826 100644
+--- a/include/linux/usb/isp116x.h
++++ b/include/linux/usb/isp116x.h
+@@ -25,5 +25,5 @@ struct isp116x_platform_data {
+ 	   300ns delay between access to ADDR_REG and DATA_REG
+ 	   OE, WE MUST NOT be changed during these intervals
+ 	 */
+-	void (*delay) (struct device * dev, int delay);
++	void (*delay) (struct device *dev, int delay);
+ };
+diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h
+index 11a97d5..80624c5 100644
+--- a/include/linux/usb/midi.h
++++ b/include/linux/usb/midi.h
+@@ -47,9 +47,9 @@ struct usb_ms_header_descriptor {
+ /* 6.1.2.2  MIDI IN Jack Descriptor */
+ struct usb_midi_in_jack_descriptor {
+ 	__u8  bLength;
+-	__u8  bDescriptorType;		// USB_DT_CS_INTERFACE
+-	__u8  bDescriptorSubtype;	// USB_MS_MIDI_IN_JACK
+-	__u8  bJackType;		// USB_MS_EMBEDDED/EXTERNAL
++	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
++	__u8  bDescriptorSubtype;	/* USB_MS_MIDI_IN_JACK */
++	__u8  bJackType;		/* USB_MS_EMBEDDED/EXTERNAL */
+ 	__u8  bJackID;
+ 	__u8  iJack;
+ } __attribute__ ((packed));
+@@ -64,12 +64,12 @@ struct usb_midi_source_pin {
+ /* 6.1.2.3  MIDI OUT Jack Descriptor */
+ struct usb_midi_out_jack_descriptor {
+ 	__u8  bLength;
+-	__u8  bDescriptorType;		// USB_DT_CS_INTERFACE
+-	__u8  bDescriptorSubtype;	// USB_MS_MIDI_OUT_JACK
+-	__u8  bJackType;		// USB_MS_EMBEDDED/EXTERNAL
++	__u8  bDescriptorType;		/* USB_DT_CS_INTERFACE */
++	__u8  bDescriptorSubtype;	/* USB_MS_MIDI_OUT_JACK */
++	__u8  bJackType;		/* USB_MS_EMBEDDED/EXTERNAL */
+ 	__u8  bJackID;
+-	__u8  bNrInputPins;		// p
+-	struct usb_midi_source_pin pins[]; // [p]
++	__u8  bNrInputPins;		/* p */
++	struct usb_midi_source_pin pins[]; /* [p] */
+ 	/*__u8  iJack;  -- ommitted due to variable-sized pins[] */
+ } __attribute__ ((packed));
+ 
+@@ -90,11 +90,11 @@ struct usb_midi_out_jack_descriptor_##p {			\
+ 
+ /* 6.2.2  Class-Specific MS Bulk Data Endpoint Descriptor */
+ struct usb_ms_endpoint_descriptor {
+-	__u8  bLength;			// 4+n
+-	__u8  bDescriptorType;		// USB_DT_CS_ENDPOINT
+-	__u8  bDescriptorSubtype;	// USB_MS_GENERAL
+-	__u8  bNumEmbMIDIJack;		// n
+-	__u8  baAssocJackID[];		// [n]
++	__u8  bLength;			/* 4+n */
++	__u8  bDescriptorType;		/* USB_DT_CS_ENDPOINT */
++	__u8  bDescriptorSubtype;	/* USB_MS_GENERAL */
++	__u8  bNumEmbMIDIJack;		/* n */
++	__u8  baAssocJackID[];		/* [n] */
+ } __attribute__ ((packed));
+ 
+ #define USB_DT_MS_ENDPOINT_SIZE(n)	(4 + (n))
+diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h
+index c602f88..ec897cb 100644
+--- a/include/linux/usb/net2280.h
++++ b/include/linux/usb/net2280.h
+@@ -37,7 +37,7 @@
+ 
+ /* main registers, BAR0 + 0x0000 */
+ struct net2280_regs {
+-	// offset 0x0000
++	/* offset 0x0000 */
+ 	u32		devinit;
+ #define     LOCAL_CLOCK_FREQUENCY                               8
+ #define     FORCE_PCI_RESET                                     7
+@@ -61,7 +61,7 @@ struct net2280_regs {
+ #define     EEPROM_WRITE_DATA                                   0
+ 	u32		eeclkfreq;
+ 	u32		_unused0;
+-	// offset 0x0010
++	/* offset 0x0010 */
+ 
+ 	u32		pciirqenb0;		/* interrupt PCI master ... */
+ #define     SETUP_PACKET_INTERRUPT_ENABLE                       7
+@@ -131,7 +131,7 @@ struct net2280_regs {
+ #define     RESUME_INTERRUPT_ENABLE                             1
+ #define     SOF_INTERRUPT_ENABLE                                0
+ 
+-	// offset 0x0020
++	/* offset 0x0020 */
+ 	u32		_unused1;
+ 	u32		usbirqenb1;
+ #define     USB_INTERRUPT_ENABLE                                31
+@@ -195,7 +195,7 @@ struct net2280_regs {
+ #define     SUSPEND_REQUEST_CHANGE_INTERRUPT                    2
+ #define     RESUME_INTERRUPT                                    1
+ #define     SOF_INTERRUPT                                       0
+-	// offset 0x0030
++	/* offset 0x0030 */
+ 	u32		idxaddr;
+ 	u32		idxdata;
+ 	u32		fifoctl;
+@@ -204,7 +204,7 @@ struct net2280_regs {
+ #define     PCI_BASE2_SELECT                                    2
+ #define     FIFO_CONFIGURATION_SELECT                           0
+ 	u32		_unused2;
+-	// offset 0x0040
++	/* offset 0x0040 */
+ 	u32		memaddr;
+ #define     START                                               28
+ #define     DIRECTION                                           27
+@@ -213,7 +213,7 @@ struct net2280_regs {
+ 	u32		memdata0;
+ 	u32		memdata1;
+ 	u32		_unused3;
+-	// offset 0x0050
++	/* offset 0x0050 */
+ 	u32		gpioctl;
+ #define     GPIO3_LED_SELECT                                    12
+ #define     GPIO3_INTERRUPT_ENABLE                              11
+@@ -237,7 +237,7 @@ struct net2280_regs {
+ 
+ /* usb control, BAR0 + 0x0080 */
+ struct net2280_usb_regs {
+-	// offset 0x0080
++	/* offset 0x0080 */
+ 	u32		stdrsp;
+ #define     STALL_UNSUPPORTED_REQUESTS                          31
+ #define     SET_TEST_MODE                                       16
+@@ -275,7 +275,7 @@ struct net2280_usb_regs {
+ #define     PME_WAKEUP_ENABLE                                   2
+ #define     DEVICE_REMOTE_WAKEUP_ENABLE                         1
+ #define     SELF_POWERED_STATUS                                 0
+-	// offset 0x0090
++	/* offset 0x0090 */
+ 	u32		usbstat;
+ #define     HIGH_SPEED                                          7
+ #define     FULL_SPEED                                          6
+@@ -291,7 +291,7 @@ struct net2280_usb_regs {
+ #define     TERMINATION_SELECT                                  0
+ 	u32		setup0123;
+ 	u32		setup4567;
+-	// offset 0x0090
++	/* offset 0x0090 */
+ 	u32		_unused0;
+ 	u32		ouraddr;
+ #define     FORCE_IMMEDIATE                                     7
+@@ -301,7 +301,7 @@ struct net2280_usb_regs {
+ 
+ /* pci control, BAR0 + 0x0100 */
+ struct net2280_pci_regs {
+-	// offset 0x0100
++	/* offset 0x0100 */
+ 	u32		 pcimstctl;
+ #define     PCI_ARBITER_PARK_SELECT                             13
+ #define     PCI_MULTI LEVEL_ARBITER                             12
+@@ -331,7 +331,7 @@ struct net2280_pci_regs {
+  * that can be loaded into some of these registers.
+  */
+ struct net2280_dma_regs {	/* [11.7] */
+-	// offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
++	/* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */
+ 	u32		dmactl;
+ #define     DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE            25
+ #define     DMA_CLEAR_COUNT_ENABLE                              21
+@@ -355,7 +355,7 @@ struct net2280_dma_regs {	/* [11.7] */
+ #define     DMA_ABORT                                           1
+ #define     DMA_START                                           0
+ 	u32		_unused0 [2];
+-	// offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
++	/* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */
+ 	u32		dmacount;
+ #define     VALID_BIT                                           31
+ #define     DMA_DIRECTION                                       30
+@@ -371,9 +371,9 @@ struct net2280_dma_regs {	/* [11.7] */
+ /* dedicated endpoint registers, BAR0 + 0x0200 */
+ 
+ struct net2280_dep_regs {	/* [11.8] */
+-	// offset 0x0200, 0x0210, 0x220, 0x230, 0x240
++	/* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */
+ 	u32		dep_cfg;
+-	// offset 0x0204, 0x0214, 0x224, 0x234, 0x244
++	/* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
+ 	u32		dep_rsp;
+ 	u32		_unused [2];
+ } __attribute__ ((packed));
+@@ -383,7 +383,7 @@ struct net2280_dep_regs {	/* [11.8] */
+  * ep0 reserved for control; E and F have only 64 bytes of fifo
+  */
+ struct net2280_ep_regs {	/* [11.9] */
+-	// offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
++	/* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */
+ 	u32		ep_cfg;
+ #define     ENDPOINT_BYTE_COUNT                                 16
+ #define     ENDPOINT_ENABLE                                     10
+@@ -435,7 +435,7 @@ struct net2280_ep_regs {	/* [11.9] */
+ #define     DATA_PACKET_TRANSMITTED_INTERRUPT                   2
+ #define     DATA_OUT_PING_TOKEN_INTERRUPT                       1
+ #define     DATA_IN_TOKEN_INTERRUPT                             0
+-	// offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
++	/* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */
+ 	u32		ep_avail;
+ 	u32		ep_data;
+ 	u32		_unused0 [2];
+diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
+index 9897f7a..e007074 100644
+--- a/include/linux/usb/otg.h
++++ b/include/linux/usb/otg.h
+@@ -1,4 +1,4 @@
+-// include/linux/usb/otg.h
++/* USB OTG (On The Go) defines */
+ 
+ /*
+  * These APIs may be used between USB controllers.  USB device drivers
+diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
+new file mode 100644
+index 0000000..edc1d4a
+--- /dev/null
++++ b/include/linux/usb/rndis_host.h
+@@ -0,0 +1,274 @@
++/*
++ * Host Side support for RNDIS Networking Links
++ * Copyright (C) 2005 by David Brownell
++ *
++ * 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	__RNDIS_HOST_H
++#define	__RNDIS_HOST_H
++
++
++/*
++ * CONTROL uses CDC "encapsulated commands" with funky notifications.
++ *  - control-out:  SEND_ENCAPSULATED
++ *  - interrupt-in:  RESPONSE_AVAILABLE
++ *  - control-in:  GET_ENCAPSULATED
++ *
++ * We'll try to ignore the RESPONSE_AVAILABLE notifications.
++ *
++ * REVISIT some RNDIS implementations seem to have curious issues still
++ * to be resolved.
++ */
++struct rndis_msg_hdr {
++	__le32	msg_type;			/* RNDIS_MSG_* */
++	__le32	msg_len;
++	// followed by data that varies between messages
++	__le32	request_id;
++	__le32	status;
++	// ... and more
++} __attribute__ ((packed));
++
++/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
++#define	CONTROL_BUFFER_SIZE		1025
++
++/* RNDIS defines an (absurdly huge) 10 second control timeout,
++ * but ActiveSync seems to use a more usual 5 second timeout
++ * (which matches the USB 2.0 spec).
++ */
++#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
++
++
++#define ccpu2 __constant_cpu_to_le32
++
++#define RNDIS_MSG_COMPLETION	ccpu2(0x80000000)
++
++/* codes for "msg_type" field of rndis messages;
++ * only the data channel uses packet messages (maybe batched);
++ * everything else goes on the control channel.
++ */
++#define RNDIS_MSG_PACKET	ccpu2(0x00000001)	/* 1-N packets */
++#define RNDIS_MSG_INIT		ccpu2(0x00000002)
++#define RNDIS_MSG_INIT_C	(RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
++#define RNDIS_MSG_HALT		ccpu2(0x00000003)
++#define RNDIS_MSG_QUERY		ccpu2(0x00000004)
++#define RNDIS_MSG_QUERY_C	(RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
++#define RNDIS_MSG_SET		ccpu2(0x00000005)
++#define RNDIS_MSG_SET_C		(RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
++#define RNDIS_MSG_RESET		ccpu2(0x00000006)
++#define RNDIS_MSG_RESET_C	(RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
++#define RNDIS_MSG_INDICATE	ccpu2(0x00000007)
++#define RNDIS_MSG_KEEPALIVE	ccpu2(0x00000008)
++#define RNDIS_MSG_KEEPALIVE_C	(RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
++
++/* codes for "status" field of completion messages */
++#define	RNDIS_STATUS_SUCCESS		ccpu2(0x00000000)
++#define	RNDIS_STATUS_FAILURE		ccpu2(0xc0000001)
++#define	RNDIS_STATUS_INVALID_DATA	ccpu2(0xc0010015)
++#define	RNDIS_STATUS_NOT_SUPPORTED	ccpu2(0xc00000bb)
++#define	RNDIS_STATUS_MEDIA_CONNECT	ccpu2(0x4001000b)
++#define	RNDIS_STATUS_MEDIA_DISCONNECT	ccpu2(0x4001000c)
++
++/* codes for OID_GEN_PHYSICAL_MEDIUM */
++#define	RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED	ccpu2(0x00000000)
++#define	RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN	ccpu2(0x00000001)
++#define	RNDIS_PHYSICAL_MEDIUM_CABLE_MODEM	ccpu2(0x00000002)
++#define	RNDIS_PHYSICAL_MEDIUM_PHONE_LINE	ccpu2(0x00000003)
++#define	RNDIS_PHYSICAL_MEDIUM_POWER_LINE	ccpu2(0x00000004)
++#define	RNDIS_PHYSICAL_MEDIUM_DSL		ccpu2(0x00000005)
++#define	RNDIS_PHYSICAL_MEDIUM_FIBRE_CHANNEL	ccpu2(0x00000006)
++#define	RNDIS_PHYSICAL_MEDIUM_1394		ccpu2(0x00000007)
++#define	RNDIS_PHYSICAL_MEDIUM_WIRELESS_WAN	ccpu2(0x00000008)
++#define	RNDIS_PHYSICAL_MEDIUM_MAX		ccpu2(0x00000009)
++
++struct rndis_data_hdr {
++	__le32	msg_type;		/* RNDIS_MSG_PACKET */
++	__le32	msg_len;		// rndis_data_hdr + data_len + pad
++	__le32	data_offset;		// 36 -- right after header
++	__le32	data_len;		// ... real packet size
++
++	__le32	oob_data_offset;	// zero
++	__le32	oob_data_len;		// zero
++	__le32	num_oob;		// zero
++	__le32	packet_data_offset;	// zero
++
++	__le32	packet_data_len;	// zero
++	__le32	vc_handle;		// zero
++	__le32	reserved;		// zero
++} __attribute__ ((packed));
++
++struct rndis_init {		/* OUT */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_INIT */
++	__le32	msg_len;			// 24
++	__le32	request_id;
++	__le32	major_version;			// of rndis (1.0)
++	__le32	minor_version;
++	__le32	max_transfer_size;
++} __attribute__ ((packed));
++
++struct rndis_init_c {		/* IN */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_INIT_C */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	status;
++	__le32	major_version;			// of rndis (1.0)
++	__le32	minor_version;
++	__le32	device_flags;
++	__le32	medium;				// zero == 802.3
++	__le32	max_packets_per_message;
++	__le32	max_transfer_size;
++	__le32	packet_alignment;		// max 7; (1<<n) bytes
++	__le32	af_list_offset;			// zero
++	__le32	af_list_size;			// zero
++} __attribute__ ((packed));
++
++struct rndis_halt {		/* OUT (no reply) */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_HALT */
++	__le32	msg_len;
++	__le32	request_id;
++} __attribute__ ((packed));
++
++struct rndis_query {		/* OUT */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_QUERY */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	oid;
++	__le32	len;
++	__le32	offset;
++/*?*/	__le32	handle;				// zero
++} __attribute__ ((packed));
++
++struct rndis_query_c {		/* IN */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_QUERY_C */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	status;
++	__le32	len;
++	__le32	offset;
++} __attribute__ ((packed));
++
++struct rndis_set {		/* OUT */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_SET */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	oid;
++	__le32	len;
++	__le32	offset;
++/*?*/	__le32	handle;				// zero
++} __attribute__ ((packed));
++
++struct rndis_set_c {		/* IN */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_SET_C */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	status;
++} __attribute__ ((packed));
++
++struct rndis_reset {		/* IN */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_RESET */
++	__le32	msg_len;
++	__le32	reserved;
++} __attribute__ ((packed));
++
++struct rndis_reset_c {		/* OUT */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_RESET_C */
++	__le32	msg_len;
++	__le32	status;
++	__le32	addressing_lost;
++} __attribute__ ((packed));
++
++struct rndis_indicate {		/* IN (unrequested) */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_INDICATE */
++	__le32	msg_len;
++	__le32	status;
++	__le32	length;
++	__le32	offset;
++/**/	__le32	diag_status;
++	__le32	error_offset;
++/**/	__le32	message;
++} __attribute__ ((packed));
++
++struct rndis_keepalive {	/* OUT (optionally IN) */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE */
++	__le32	msg_len;
++	__le32	request_id;
++} __attribute__ ((packed));
++
++struct rndis_keepalive_c {	/* IN (optionally OUT) */
++	// header and:
++	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE_C */
++	__le32	msg_len;
++	__le32	request_id;
++	__le32	status;
++} __attribute__ ((packed));
++
++/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
++ * there are gobs more that may optionally be supported.  We'll avoid as much
++ * of that mess as possible.
++ */
++#define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
++#define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
++#define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
++#define OID_GEN_PHYSICAL_MEDIUM		ccpu2(0x00010202)
++
++/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
++#define RNDIS_PACKET_TYPE_DIRECTED		ccpu2(0x00000001)
++#define RNDIS_PACKET_TYPE_MULTICAST		ccpu2(0x00000002)
++#define RNDIS_PACKET_TYPE_ALL_MULTICAST		ccpu2(0x00000004)
++#define RNDIS_PACKET_TYPE_BROADCAST		ccpu2(0x00000008)
++#define RNDIS_PACKET_TYPE_SOURCE_ROUTING	ccpu2(0x00000010)
++#define RNDIS_PACKET_TYPE_PROMISCUOUS		ccpu2(0x00000020)
++#define RNDIS_PACKET_TYPE_SMT			ccpu2(0x00000040)
++#define RNDIS_PACKET_TYPE_ALL_LOCAL		ccpu2(0x00000080)
++#define RNDIS_PACKET_TYPE_GROUP			ccpu2(0x00001000)
++#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL	ccpu2(0x00002000)
++#define RNDIS_PACKET_TYPE_FUNCTIONAL		ccpu2(0x00004000)
++#define RNDIS_PACKET_TYPE_MAC_FRAME		ccpu2(0x00008000)
++
++/* default filter used with RNDIS devices */
++#define RNDIS_DEFAULT_FILTER ( \
++	RNDIS_PACKET_TYPE_DIRECTED | \
++	RNDIS_PACKET_TYPE_BROADCAST | \
++	RNDIS_PACKET_TYPE_ALL_MULTICAST | \
++	RNDIS_PACKET_TYPE_PROMISCUOUS)
++
++/* Flags to require specific physical medium type for generic_rndis_bind() */
++#define FLAG_RNDIS_PHYM_NOT_WIRELESS	0x0001
++#define FLAG_RNDIS_PHYM_WIRELESS	0x0002
++
++
++extern void rndis_status(struct usbnet *dev, struct urb *urb);
++extern int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf);
++extern int
++generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags);
++extern void rndis_unbind(struct usbnet *dev, struct usb_interface *intf);
++extern int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
++extern struct sk_buff *
++rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags);
++
++#endif	/* __RNDIS_HOST_H */
++
+diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
+index 488ce12..21b4a1c 100644
+--- a/include/linux/usb/serial.h
++++ b/include/linux/usb/serial.h
+@@ -20,7 +20,8 @@
+ #define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
+ #define SERIAL_TTY_MINORS	255	/* loads of devices :) */
+ 
+-#define MAX_NUM_PORTS		8	/* The maximum number of ports one device can grab at once */
++/* The maximum number of ports one device can grab at once */
++#define MAX_NUM_PORTS		8
+ 
+ /* parity check flag */
+ #define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+@@ -61,29 +62,29 @@
+  * ports of a device.
+  */
+ struct usb_serial_port {
+-	struct usb_serial *	serial;
+-	struct tty_struct *	tty;
++	struct usb_serial	*serial;
++	struct tty_struct	*tty;
+ 	spinlock_t		lock;
+ 	struct mutex            mutex;
+ 	unsigned char		number;
+ 
+-	unsigned char *		interrupt_in_buffer;
+-	struct urb *		interrupt_in_urb;
++	unsigned char		*interrupt_in_buffer;
++	struct urb		*interrupt_in_urb;
+ 	__u8			interrupt_in_endpointAddress;
+ 
+-	unsigned char *		interrupt_out_buffer;
++	unsigned char		*interrupt_out_buffer;
+ 	int			interrupt_out_size;
+-	struct urb *		interrupt_out_urb;
++	struct urb		*interrupt_out_urb;
+ 	__u8			interrupt_out_endpointAddress;
+ 
+-	unsigned char *		bulk_in_buffer;
++	unsigned char		*bulk_in_buffer;
+ 	int			bulk_in_size;
+-	struct urb *		read_urb;
++	struct urb		*read_urb;
+ 	__u8			bulk_in_endpointAddress;
+ 
+-	unsigned char *		bulk_out_buffer;
++	unsigned char		*bulk_out_buffer;
+ 	int			bulk_out_size;
+-	struct urb *		write_urb;
++	struct urb		*write_urb;
+ 	int			write_urb_busy;
+ 	__u8			bulk_out_endpointAddress;
+ 
+@@ -92,17 +93,19 @@ struct usb_serial_port {
+ 	int			open_count;
+ 	char			throttled;
+ 	char			throttle_req;
++	char			console;
+ 	struct device		dev;
+ };
+ #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
+ 
+ /* get and set the port private data pointer helper functions */
+-static inline void *usb_get_serial_port_data (struct usb_serial_port *port)
++static inline void *usb_get_serial_port_data(struct usb_serial_port *port)
+ {
+ 	return dev_get_drvdata(&port->dev);
+ }
+ 
+-static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data)
++static inline void usb_set_serial_port_data(struct usb_serial_port *port,
++					    void *data)
+ {
+ 	dev_set_drvdata(&port->dev, data);
+ }
+@@ -125,9 +128,10 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void
+  *	usb_set_serial_data() to access this.
+  */
+ struct usb_serial {
+-	struct usb_device *		dev;
+-	struct usb_serial_driver *	type;
+-	struct usb_interface *		interface;
++	struct usb_device		*dev;
++	struct usb_serial_driver	*type;
++	struct usb_interface		*interface;
++	unsigned char			disconnected;
+ 	unsigned char			minor;
+ 	unsigned char			num_ports;
+ 	unsigned char			num_port_pointers;
+@@ -135,29 +139,30 @@ struct usb_serial {
+ 	char				num_interrupt_out;
+ 	char				num_bulk_in;
+ 	char				num_bulk_out;
+-	struct usb_serial_port *	port[MAX_NUM_PORTS];
++	struct usb_serial_port		*port[MAX_NUM_PORTS];
+ 	struct kref			kref;
+-	void *				private;
++	struct mutex			disc_mutex;
++	void				*private;
+ };
+ #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
+ 
+ #define NUM_DONT_CARE	99
+ 
+ /* get and set the serial private data pointer helper functions */
+-static inline void *usb_get_serial_data (struct usb_serial *serial)
++static inline void *usb_get_serial_data(struct usb_serial *serial)
+ {
+ 	return serial->private;
+ }
+ 
+-static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
++static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
+ {
+ 	serial->private = data;
+ }
+ 
+ /**
+  * usb_serial_driver - describes a usb serial driver
+- * @description: pointer to a string that describes this driver.  This string used
+- *	in the syslog messages when a device is inserted or removed.
++ * @description: pointer to a string that describes this driver.  This string
++ *	used in the syslog messages when a device is inserted or removed.
+  * @id_table: pointer to a list of usb_device_id structures that define all
+  *	of the devices this structure can support.
+  * @num_interrupt_in: If a device doesn't have this many interrupt-in
+@@ -218,82 +223,91 @@ struct usb_serial_driver {
+ 	struct usb_driver	*usb_driver;
+ 	struct usb_dynids	dynids;
+ 
+-	int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
+-	int (*attach) (struct usb_serial *serial);
++	int (*probe)(struct usb_serial *serial, const struct usb_device_id *id);
++	int (*attach)(struct usb_serial *serial);
+ 	int (*calc_num_ports) (struct usb_serial *serial);
+ 
+-	void (*shutdown) (struct usb_serial *serial);
++	void (*shutdown)(struct usb_serial *serial);
+ 
+-	int (*port_probe) (struct usb_serial_port *port);
+-	int (*port_remove) (struct usb_serial_port *port);
++	int (*port_probe)(struct usb_serial_port *port);
++	int (*port_remove)(struct usb_serial_port *port);
+ 
+-	int (*suspend) (struct usb_serial *serial, pm_message_t message);
+-	int (*resume) (struct usb_serial *serial);
++	int (*suspend)(struct usb_serial *serial, pm_message_t message);
++	int (*resume)(struct usb_serial *serial);
+ 
+ 	/* serial function calls */
+-	int  (*open)		(struct usb_serial_port *port, struct file * filp);
+-	void (*close)		(struct usb_serial_port *port, struct file * filp);
+-	int  (*write)		(struct usb_serial_port *port, const unsigned char *buf, int count);
+-	int  (*write_room)	(struct usb_serial_port *port);
+-	int  (*ioctl)		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+-	void (*set_termios)	(struct usb_serial_port *port, struct ktermios * old);
+-	void (*break_ctl)	(struct usb_serial_port *port, int break_state);
+-	int  (*chars_in_buffer)	(struct usb_serial_port *port);
+-	void (*throttle)	(struct usb_serial_port *port);
+-	void (*unthrottle)	(struct usb_serial_port *port);
+-	int  (*tiocmget)	(struct usb_serial_port *port, struct file *file);
+-	int  (*tiocmset)	(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
++	int  (*open)(struct usb_serial_port *port, struct file *filp);
++	void (*close)(struct usb_serial_port *port, struct file *filp);
++	int  (*write)(struct usb_serial_port *port, const unsigned char *buf,
++		      int count);
++	int  (*write_room)(struct usb_serial_port *port);
++	int  (*ioctl)(struct usb_serial_port *port, struct file *file,
++		      unsigned int cmd, unsigned long arg);
++	void (*set_termios)(struct usb_serial_port *port, struct ktermios *old);
++	void (*break_ctl)(struct usb_serial_port *port, int break_state);
++	int  (*chars_in_buffer)(struct usb_serial_port *port);
++	void (*throttle)(struct usb_serial_port *port);
++	void (*unthrottle)(struct usb_serial_port *port);
++	int  (*tiocmget)(struct usb_serial_port *port, struct file *file);
++	int  (*tiocmset)(struct usb_serial_port *port, struct file *file,
++			 unsigned int set, unsigned int clear);
+ 
+ 	void (*read_int_callback)(struct urb *urb);
+ 	void (*write_int_callback)(struct urb *urb);
+ 	void (*read_bulk_callback)(struct urb *urb);
+ 	void (*write_bulk_callback)(struct urb *urb);
+ };
+-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
++#define to_usb_serial_driver(d) \
++	container_of(d, struct usb_serial_driver, driver)
+ 
+ extern int  usb_serial_register(struct usb_serial_driver *driver);
+ extern void usb_serial_deregister(struct usb_serial_driver *driver);
+ extern void usb_serial_port_softint(struct usb_serial_port *port);
+ 
+-extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
++extern int usb_serial_probe(struct usb_interface *iface,
++			    const struct usb_device_id *id);
+ extern void usb_serial_disconnect(struct usb_interface *iface);
+ 
+ extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
+ extern int usb_serial_resume(struct usb_interface *intf);
+ 
+-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
++extern int ezusb_writememory(struct usb_serial *serial, int address,
++			     unsigned char *data, int length, __u8 bRequest);
++extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
+ 
+ /* USB Serial console functions */
+ #ifdef CONFIG_USB_SERIAL_CONSOLE
+-extern void usb_serial_console_init (int debug, int minor);
+-extern void usb_serial_console_exit (void);
++extern void usb_serial_console_init(int debug, int minor);
++extern void usb_serial_console_exit(void);
+ extern void usb_serial_console_disconnect(struct usb_serial *serial);
+ #else
+-static inline void usb_serial_console_init (int debug, int minor) { }
+-static inline void usb_serial_console_exit (void) { }
++static inline void usb_serial_console_init(int debug, int minor) { }
++static inline void usb_serial_console_exit(void) { }
+ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
+ #endif
+ 
+ /* Functions needed by other parts of the usbserial core */
+-extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
++extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
+ extern void usb_serial_put(struct usb_serial *serial);
+-extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
+-extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
+-extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
+-extern int usb_serial_generic_resume (struct usb_serial *serial);
+-extern int usb_serial_generic_write_room (struct usb_serial_port *port);
+-extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
+-extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
+-extern void usb_serial_generic_write_bulk_callback (struct urb *urb);
+-extern void usb_serial_generic_throttle (struct usb_serial_port *port);
+-extern void usb_serial_generic_unthrottle (struct usb_serial_port *port);
+-extern void usb_serial_generic_shutdown (struct usb_serial *serial);
+-extern int usb_serial_generic_register (int debug);
+-extern void usb_serial_generic_deregister (void);
+-
+-extern int usb_serial_bus_register (struct usb_serial_driver *device);
+-extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
++extern int usb_serial_generic_open(struct usb_serial_port *port,
++				   struct file *filp);
++extern int usb_serial_generic_write(struct usb_serial_port *port,
++				    const unsigned char *buf, int count);
++extern void usb_serial_generic_close(struct usb_serial_port *port,
++				     struct file *filp);
++extern int usb_serial_generic_resume(struct usb_serial *serial);
++extern int usb_serial_generic_write_room(struct usb_serial_port *port);
++extern int usb_serial_generic_chars_in_buffer(struct usb_serial_port *port);
++extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
++extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
++extern void usb_serial_generic_throttle(struct usb_serial_port *port);
++extern void usb_serial_generic_unthrottle(struct usb_serial_port *port);
++extern void usb_serial_generic_shutdown(struct usb_serial *serial);
++extern int usb_serial_generic_register(int debug);
++extern void usb_serial_generic_deregister(void);
++
++extern int usb_serial_bus_register(struct usb_serial_driver *device);
++extern void usb_serial_bus_deregister(struct usb_serial_driver *device);
+ 
+ extern struct usb_serial_driver usb_serial_generic_device;
+ extern struct bus_type usb_serial_bus_type;
+@@ -307,16 +321,22 @@ static inline void usb_serial_debug_data(int debug,
+ 	int i;
+ 
+ 	if (debug) {
+-		dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size);
++		dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ",
++			   function, size);
+ 		for (i = 0; i < size; ++i)
+-			printk ("%.2x ", data[i]);
+-		printk ("\n");
++			printk("%.2x ", data[i]);
++		printk("\n");
+ 	}
+ }
+ 
+ /* Use our own dbg macro */
+ #undef dbg
+-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0)
++#define dbg(format, arg...) \
++	do { \
++		if (debug) \
++			printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \
++				## arg); \
++	} while (0)
+ 
+ 
+ 
+diff --git a/include/linux/usb/sl811.h b/include/linux/usb/sl811.h
+index 397ee3b..877373d 100644
+--- a/include/linux/usb/sl811.h
++++ b/include/linux/usb/sl811.h
+@@ -19,8 +19,8 @@ struct sl811_platform_data {
+ 	/* pulse sl811 nRST (probably with a GPIO) */
+ 	void		(*reset)(struct device *dev);
+ 
+-	// some boards need something like these:
+-	// int		(*check_overcurrent)(struct device *dev);
+-	// void		(*clock_enable)(struct device *dev, int is_on);
++	/* some boards need something like these: */
++	/* int		(*check_overcurrent)(struct device *dev); */
++	/* void		(*clock_enable)(struct device *dev, int is_on); */
+ };
+ 
+diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
+new file mode 100644
+index 0000000..e0501da
+--- /dev/null
++++ b/include/linux/usb/usbnet.h
+@@ -0,0 +1,214 @@
++/*
++ * USB Networking Link Interface
++ *
++ * Copyright (C) 2000-2005 by David Brownell <dbrownell at users.sourceforge.net>
++ * Copyright (C) 2003-2005 David Hollis <dhollis at davehollis.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++
++#ifndef	__USBNET_H
++#define	__USBNET_H
++
++
++/* interface from usbnet core to each USB networking link we handle */
++struct usbnet {
++	/* housekeeping */
++	struct usb_device	*udev;
++	struct usb_interface	*intf;
++	struct driver_info	*driver_info;
++	const char		*driver_name;
++	void			*driver_priv;
++	wait_queue_head_t	*wait;
++	struct mutex		phy_mutex;
++	unsigned char		suspend_count;
++
++	/* i/o info: pipes etc */
++	unsigned		in, out;
++	struct usb_host_endpoint *status;
++	unsigned		maxpacket;
++	struct timer_list	delay;
++
++	/* protocol/interface state */
++	struct net_device	*net;
++	struct net_device_stats	stats;
++	int			msg_enable;
++	unsigned long		data [5];
++	u32			xid;
++	u32			hard_mtu;	/* count any extra framing */
++	size_t			rx_urb_size;	/* size for rx urbs */
++	struct mii_if_info	mii;
++
++	/* various kinds of pending driver work */
++	struct sk_buff_head	rxq;
++	struct sk_buff_head	txq;
++	struct sk_buff_head	done;
++	struct urb		*interrupt;
++	struct tasklet_struct	bh;
++
++	struct work_struct	kevent;
++	unsigned long		flags;
++#		define EVENT_TX_HALT	0
++#		define EVENT_RX_HALT	1
++#		define EVENT_RX_MEMORY	2
++#		define EVENT_STS_SPLIT	3
++#		define EVENT_LINK_RESET	4
++};
++
++static inline struct usb_driver *driver_of(struct usb_interface *intf)
++{
++	return to_usb_driver(intf->dev.driver);
++}
++
++/* interface from the device/framing level "minidriver" to core */
++struct driver_info {
++	char		*description;
++
++	int		flags;
++/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
++#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */
++#define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
++#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
++#define FLAG_FRAMING_RN	0x0008		/* RNDIS batches, plus huge header */
++
++#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
++#define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
++
++#define FLAG_FRAMING_AX 0x0040		/* AX88772/178 packets */
++#define FLAG_WLAN	0x0080		/* use "wlan%d" names */
++
++
++	/* init device ... can sleep, or cause probe() failure */
++	int	(*bind)(struct usbnet *, struct usb_interface *);
++
++	/* cleanup device ... can sleep, but can't fail */
++	void	(*unbind)(struct usbnet *, struct usb_interface *);
++
++	/* reset device ... can sleep */
++	int	(*reset)(struct usbnet *);
++
++	/* see if peer is connected ... can sleep */
++	int	(*check_connect)(struct usbnet *);
++
++	/* for status polling */
++	void	(*status)(struct usbnet *, struct urb *);
++
++	/* link reset handling, called from defer_kevent */
++	int	(*link_reset)(struct usbnet *);
++
++	/* fixup rx packet (strip framing) */
++	int	(*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
++
++	/* fixup tx packet (add framing) */
++	struct sk_buff	*(*tx_fixup)(struct usbnet *dev,
++				struct sk_buff *skb, gfp_t flags);
++
++	/* early initialization code, can sleep. This is for minidrivers
++	 * having 'subminidrivers' that need to do extra initialization
++	 * right after minidriver have initialized hardware. */
++	int	(*early_init)(struct usbnet *dev);
++
++	/* called by minidriver when link state changes, state: 0=disconnect,
++	 * 1=connect */
++	void	(*link_change)(struct usbnet *dev, int state);
++
++	/* for new devices, use the descriptor-reading code instead */
++	int		in;		/* rx endpoint */
++	int		out;		/* tx endpoint */
++
++	unsigned long	data;		/* Misc driver specific data */
++};
++
++/* Minidrivers are just drivers using the "usbnet" core as a powerful
++ * network-specific subroutine library ... that happens to do pretty
++ * much everything except custom framing and chip-specific stuff.
++ */
++extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
++extern int usbnet_suspend (struct usb_interface *, pm_message_t );
++extern int usbnet_resume (struct usb_interface *);
++extern void usbnet_disconnect(struct usb_interface *);
++
++
++/* Drivers that reuse some of the standard USB CDC infrastructure
++ * (notably, using multiple interfaces according to the CDC
++ * union descriptor) get some helper code.
++ */
++struct cdc_state {
++	struct usb_cdc_header_desc	*header;
++	struct usb_cdc_union_desc	*u;
++	struct usb_cdc_ether_desc	*ether;
++	struct usb_interface		*control;
++	struct usb_interface		*data;
++};
++
++extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
++extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
++
++/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
++#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
++			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
++			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
++			|USB_CDC_PACKET_TYPE_DIRECTED)
++
++
++/* we record the state for each of our queued skbs */
++enum skb_state {
++	illegal = 0,
++	tx_start, tx_done,
++	rx_start, rx_done, rx_cleanup
++};
++
++struct skb_data {	/* skb->cb is one of these */
++	struct urb		*urb;
++	struct usbnet		*dev;
++	enum skb_state		state;
++	size_t			length;
++};
++
++
++extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
++extern void usbnet_defer_kevent (struct usbnet *, int);
++extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
++extern void usbnet_unlink_rx_urbs(struct usbnet *);
++
++extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
++extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
++extern u32 usbnet_get_link (struct net_device *net);
++extern u32 usbnet_get_msglevel (struct net_device *);
++extern void usbnet_set_msglevel (struct net_device *, u32);
++extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
++extern int usbnet_nway_reset(struct net_device *net);
++
++/* messaging support includes the interface name, so it must not be
++ * used before it has one ... notably, in minidriver bind() calls.
++ */
++#ifdef DEBUG
++#define devdbg(usbnet, fmt, arg...) \
++	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++#else
++#define devdbg(usbnet, fmt, arg...) do {} while(0)
++#endif
++
++#define deverr(usbnet, fmt, arg...) \
++	printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++#define devwarn(usbnet, fmt, arg...) \
++	printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++
++#define devinfo(usbnet, fmt, arg...) \
++	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
++
++
++#endif	/* __USBNET_H */
+diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
+index a417b09..cee0623 100644
+--- a/include/linux/usb_usual.h
++++ b/include/linux/usb_usual.h
+@@ -80,10 +80,9 @@ enum { US_DO_ALL_FLAGS };
+ #define US_SC_UFI	0x04		/* Floppy */
+ #define US_SC_8070	0x05		/* Removable media */
+ #define US_SC_SCSI	0x06		/* Transparent */
+-#define US_SC_ISD200    0x07		/* ISD200 ATA */
+-#define US_SC_MIN	US_SC_RBC
+-#define US_SC_MAX	US_SC_ISD200
++#define US_SC_LOCKABLE	0x07		/* Password-protected */
+ 
++#define US_SC_ISD200    0xf0		/* ISD200 ATA */
+ #define US_SC_DEVICE	0xff		/* Use device's value */
+ 
+ /* Protocols */
+diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
+index 8ca5a7f..17cb108 100644
+--- a/include/linux/usbdevice_fs.h
++++ b/include/linux/usbdevice_fs.h
+@@ -104,7 +104,7 @@ struct usbdevfs_urb {
+ 	int error_count;
+ 	unsigned int signr;	/* signal to be sent on completion,
+ 				  or 0 if none should be sent. */
+-	void *usercontext;
++	void __user *usercontext;
+ 	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+ };
+ 
 diff --git a/include/linux/wait.h b/include/linux/wait.h
 index 0e68628..1f4fb0a 100644
 --- a/include/linux/wait.h
@@ -816784,23 +869261,27 @@
  	__u32		event_capa[6];
  
 diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
-index b58adc5..9b5b00c 100644
+index b58adc5..e31b8c8 100644
 --- a/include/linux/xfrm.h
 +++ b/include/linux/xfrm.h
-@@ -91,9 +91,9 @@ struct xfrm_replay_state
+@@ -91,8 +91,15 @@ struct xfrm_replay_state
  };
  
  struct xfrm_algo {
--	char	alg_name[64];
--	int	alg_key_len;    /* in bits */
--	char	alg_key[0];
 +	char		alg_name[64];
 +	unsigned int	alg_key_len;    /* in bits */
 +	char		alg_key[0];
++};
++
++struct xfrm_algo_aead {
+ 	char	alg_name[64];
+-	int	alg_key_len;    /* in bits */
++	int	alg_key_len;	/* in bits */
++	int	alg_icv_len;	/* in bits */
+ 	char	alg_key[0];
  };
  
- struct xfrm_stats {
-@@ -114,6 +114,7 @@ enum
+@@ -114,6 +121,7 @@ enum
  	XFRM_POLICY_IN	= 0,
  	XFRM_POLICY_OUT	= 1,
  	XFRM_POLICY_FWD	= 2,
@@ -816808,7 +869289,15 @@
  	XFRM_POLICY_MAX	= 3
  };
  
-@@ -328,6 +329,7 @@ struct xfrm_usersa_info {
+@@ -269,6 +277,7 @@ enum xfrm_attr_type_t {
+ 	XFRMA_LASTUSED,
+ 	XFRMA_POLICY_TYPE,	/* struct xfrm_userpolicy_type */
+ 	XFRMA_MIGRATE,
++	XFRMA_ALG_AEAD,		/* struct xfrm_algo_aead */
+ 	__XFRMA_MAX
+ 
+ #define XFRMA_MAX (__XFRMA_MAX - 1)
+@@ -328,6 +337,7 @@ struct xfrm_usersa_info {
  #define XFRM_STATE_DECAP_DSCP	2
  #define XFRM_STATE_NOPMTUDISC	4
  #define XFRM_STATE_WILDRECV	8
@@ -816816,7 +869305,7 @@
  };
  
  struct xfrm_usersa_id {
-@@ -362,6 +364,8 @@ struct xfrm_userpolicy_info {
+@@ -362,6 +372,8 @@ struct xfrm_userpolicy_info {
  #define XFRM_POLICY_BLOCK	1
  	__u8				flags;
  #define XFRM_POLICY_LOCALOK	1	/* Allow user to override global policy */
@@ -817553,10 +870042,10 @@
  #endif
  #endif
 diff --git a/include/net/arp.h b/include/net/arp.h
-index f026645..752eb47 100644
+index f026645..c236270 100644
 --- a/include/net/arp.h
 +++ b/include/net/arp.h
-@@ -5,13 +5,12 @@
+@@ -5,24 +5,25 @@
  #include <linux/if_arp.h>
  #include <net/neighbour.h>
  
@@ -817570,7 +870059,23 @@
 +extern int	arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
  extern void     arp_send(int type, int ptype, __be32 dest_ip,
  			 struct net_device *dev, __be32 src_ip,
- 			 unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
+-			 unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
++			 const unsigned char *dest_hw,
++			 const unsigned char *src_hw, const unsigned char *th);
+ extern int	arp_bind_neighbour(struct dst_entry *dst);
+ extern int	arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
+ extern void	arp_ifdown(struct net_device *dev);
+ 
+ extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ 				  struct net_device *dev, __be32 src_ip,
+-				  unsigned char *dest_hw, unsigned char *src_hw,
+-				  unsigned char *target_hw);
++				  const unsigned char *dest_hw,
++				  const unsigned char *src_hw,
++				  const unsigned char *target_hw);
+ extern void arp_xmit(struct sk_buff *skb);
+ 
+ extern struct neigh_ops arp_broken_ops;
 diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
 index 25aa575..98ec7a3 100644
 --- a/include/net/bluetooth/rfcomm.h
@@ -817921,6 +870426,77 @@
  struct flowi;
  #ifndef CONFIG_XFRM
  static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
+diff --git a/include/net/esp.h b/include/net/esp.h
+index c05f529..d584513 100644
+--- a/include/net/esp.h
++++ b/include/net/esp.h
+@@ -1,58 +1,20 @@
+ #ifndef _NET_ESP_H
+ #define _NET_ESP_H
+ 
+-#include <linux/crypto.h>
+-#include <net/xfrm.h>
+-#include <linux/scatterlist.h>
++#include <linux/skbuff.h>
+ 
+-#define ESP_NUM_FAST_SG		4
++struct crypto_aead;
+ 
+-struct esp_data
+-{
+-	struct scatterlist		sgbuf[ESP_NUM_FAST_SG];
+-
+-	/* Confidentiality */
+-	struct {
+-		int			padlen;		/* 0..255 */
+-		/* ivlen is offset from enc_data, where encrypted data start.
+-		 * It is logically different of crypto_tfm_alg_ivsize(tfm).
+-		 * We assume that it is either zero (no ivec), or
+-		 * >= crypto_tfm_alg_ivsize(tfm). */
+-		int			ivlen;
+-		int			ivinitted;
+-		u8			*ivec;		/* ivec buffer */
+-		struct crypto_blkcipher	*tfm;		/* crypto handle */
+-	} conf;
+-
+-	/* Integrity. It is active when icv_full_len != 0 */
+-	struct {
+-		u8			*work_icv;
+-		int			icv_full_len;
+-		int			icv_trunc_len;
+-		struct crypto_hash	*tfm;
+-	} auth;
++struct esp_data {
++	/* 0..255 */
++	int padlen;
++
++	/* Confidentiality & Integrity */
++	struct crypto_aead *aead;
+ };
+ 
+ extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
+ 
+-static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
+-				 int offset, int len)
+-{
+-	struct hash_desc desc;
+-	int err;
+-
+-	desc.tfm = esp->auth.tfm;
+-	desc.flags = 0;
+-
+-	err = crypto_hash_init(&desc);
+-	if (unlikely(err))
+-		return err;
+-	err = skb_icv_walk(skb, &desc, offset, len, crypto_hash_update);
+-	if (unlikely(err))
+-		return err;
+-	return crypto_hash_final(&desc, esp->auth.work_icv);
+-}
+-
+ struct ip_esp_hdr;
+ 
+ static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
 diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
 index 41a301e..34349f9 100644
 --- a/include/net/fib_rules.h
@@ -818055,6 +870631,55 @@
  	memcpy(buf + 10, addr->s6_addr + 6, 10);
  }
  #endif
+diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
+index 668056b..fdff630 100644
+--- a/include/net/inet6_hashtables.h
++++ b/include/net/inet6_hashtables.h
+@@ -57,34 +57,37 @@ extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
+  *
+  * The sockhash lock must be held as a reader here.
+  */
+-extern struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
++extern struct sock *__inet6_lookup_established(struct net *net,
++					   struct inet_hashinfo *hashinfo,
+ 					   const struct in6_addr *saddr,
+ 					   const __be16 sport,
+ 					   const struct in6_addr *daddr,
+ 					   const u16 hnum,
+ 					   const int dif);
+ 
+-extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
++extern struct sock *inet6_lookup_listener(struct net *net,
++					  struct inet_hashinfo *hashinfo,
+ 					  const struct in6_addr *daddr,
+ 					  const unsigned short hnum,
+ 					  const int dif);
+ 
+-static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo,
++static inline struct sock *__inet6_lookup(struct net *net,
++					  struct inet_hashinfo *hashinfo,
+ 					  const struct in6_addr *saddr,
+ 					  const __be16 sport,
+ 					  const struct in6_addr *daddr,
+ 					  const u16 hnum,
+ 					  const int dif)
+ {
+-	struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport,
+-						     daddr, hnum, dif);
++	struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr,
++						sport, daddr, hnum, dif);
+ 	if (sk)
+ 		return sk;
+ 
+-	return inet6_lookup_listener(hashinfo, daddr, hnum, dif);
++	return inet6_lookup_listener(net, hashinfo, daddr, hnum, dif);
+ }
+ 
+-extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
++extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
+ 				 const struct in6_addr *saddr, const __be16 sport,
+ 				 const struct in6_addr *daddr, const __be16 dport,
+ 				 const int dif);
 diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
 index de8399a..ba33db0 100644
 --- a/include/net/inet_ecn.h
@@ -818153,10 +870778,26 @@
  static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
  {
 diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
-index 37f6cb1..761bdc0 100644
+index 37f6cb1..c23c4ed 100644
 --- a/include/net/inet_hashtables.h
 +++ b/include/net/inet_hashtables.h
-@@ -264,37 +264,14 @@ static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo)
+@@ -74,6 +74,7 @@ struct inet_ehash_bucket {
+  * ports are created in O(1) time?  I thought so. ;-)	-DaveM
+  */
+ struct inet_bind_bucket {
++	struct net		*ib_net;
+ 	unsigned short		port;
+ 	signed short		fastreuse;
+ 	struct hlist_node	node;
+@@ -194,6 +195,7 @@ static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo)
+ 
+ extern struct inet_bind_bucket *
+ 		    inet_bind_bucket_create(struct kmem_cache *cachep,
++					    struct net *net,
+ 					    struct inet_bind_hashbucket *head,
+ 					    const unsigned short snum);
+ extern void inet_bind_bucket_destroy(struct kmem_cache *cachep,
+@@ -264,37 +266,14 @@ static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo)
  		wake_up(&hashinfo->lhash_wait);
  }
  
@@ -818197,7 +870838,7 @@
  		local_bh_enable();
  	}
  }
-@@ -316,7 +293,7 @@ static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
+@@ -316,22 +295,24 @@ static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
  	}
  
  	if (__sk_del_node_init(sk))
@@ -818206,7 +870847,63 @@
  	write_unlock_bh(lock);
  out:
  	if (sk->sk_state == TCP_LISTEN)
-@@ -397,43 +374,9 @@ typedef __u64 __bitwise __addrpair;
+ 		wake_up(&hashinfo->lhash_wait);
+ }
+ 
+-extern struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
++extern struct sock *__inet_lookup_listener(struct net *net,
++					   struct inet_hashinfo *hashinfo,
+ 					   const __be32 daddr,
+ 					   const unsigned short hnum,
+ 					   const int dif);
+ 
+-static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
+-						__be32 daddr, __be16 dport, int dif)
++static inline struct sock *inet_lookup_listener(struct net *net,
++		struct inet_hashinfo *hashinfo,
++		__be32 daddr, __be16 dport, int dif)
+ {
+-	return __inet_lookup_listener(hashinfo, daddr, ntohs(dport), dif);
++	return __inet_lookup_listener(net, hashinfo, daddr, ntohs(dport), dif);
+ }
+ 
+ /* Socket demux engine toys. */
+@@ -365,26 +346,26 @@ typedef __u64 __bitwise __addrpair;
+ 				   (((__force __u64)(__be32)(__daddr)) << 32) | \
+ 				   ((__force __u64)(__be32)(__saddr)));
+ #endif /* __BIG_ENDIAN */
+-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+-	(((__sk)->sk_hash == (__hash))				&&	\
++#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&&	\
+ 	 ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie))	&&	\
+ 	 ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))	&&	\
+ 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+-#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+-	(((__sk)->sk_hash == (__hash))				&&	\
++#define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&&	\
+ 	 ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) &&	\
+ 	 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&	\
+ 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+ #else /* 32-bit arch */
+ #define INET_ADDR_COOKIE(__name, __saddr, __daddr)
+-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)	\
+-	(((__sk)->sk_hash == (__hash))				&&	\
++#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)	\
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&&	\
+ 	 (inet_sk(__sk)->daddr		== (__saddr))		&&	\
+ 	 (inet_sk(__sk)->rcv_saddr	== (__daddr))		&&	\
+ 	 ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))	&&	\
+ 	 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+-#define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif)	\
+-	(((__sk)->sk_hash == (__hash))				&&	\
++#define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif)	\
++	(((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))	&&	\
+ 	 (inet_twsk(__sk)->tw_daddr	== (__saddr))		&&	\
+ 	 (inet_twsk(__sk)->tw_rcv_saddr	== (__daddr))		&&	\
+ 	 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&	\
+@@ -397,66 +378,36 @@ typedef __u64 __bitwise __addrpair;
   *
   * Local BH must be disabled here.
   */
@@ -818247,12 +870944,65 @@
 -	sock_hold(sk);
 -	goto out;
 -}
-+extern struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo,
++extern struct sock * __inet_lookup_established(struct net *net,
++		struct inet_hashinfo *hashinfo,
 +		const __be32 saddr, const __be16 sport,
 +		const __be32 daddr, const u16 hnum, const int dif);
  
  static inline struct sock *
- 	inet_lookup_established(struct inet_hashinfo *hashinfo,
+-	inet_lookup_established(struct inet_hashinfo *hashinfo,
++	inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo,
+ 				const __be32 saddr, const __be16 sport,
+ 				const __be32 daddr, const __be16 dport,
+ 				const int dif)
+ {
+-	return __inet_lookup_established(hashinfo, saddr, sport, daddr,
++	return __inet_lookup_established(net, hashinfo, saddr, sport, daddr,
+ 					 ntohs(dport), dif);
+ }
+ 
+-static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
++static inline struct sock *__inet_lookup(struct net *net,
++					 struct inet_hashinfo *hashinfo,
+ 					 const __be32 saddr, const __be16 sport,
+ 					 const __be32 daddr, const __be16 dport,
+ 					 const int dif)
+ {
+ 	u16 hnum = ntohs(dport);
+-	struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
+-						    hnum, dif);
+-	return sk ? : __inet_lookup_listener(hashinfo, daddr, hnum, dif);
++	struct sock *sk = __inet_lookup_established(net, hashinfo,
++				saddr, sport, daddr, hnum, dif);
++
++	return sk ? : __inet_lookup_listener(net, hashinfo, daddr, hnum, dif);
+ }
+ 
+-static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
++static inline struct sock *inet_lookup(struct net *net,
++				       struct inet_hashinfo *hashinfo,
+ 				       const __be32 saddr, const __be16 sport,
+ 				       const __be32 daddr, const __be16 dport,
+ 				       const int dif)
+@@ -464,12 +415,17 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
+ 	struct sock *sk;
+ 
+ 	local_bh_disable();
+-	sk = __inet_lookup(hashinfo, saddr, sport, daddr, dport, dif);
++	sk = __inet_lookup(net, hashinfo, saddr, sport, daddr, dport, dif);
+ 	local_bh_enable();
+ 
+ 	return sk;
+ }
+ 
++extern int __inet_hash_connect(struct inet_timewait_death_row *death_row,
++		struct sock *sk,
++		int (*check_established)(struct inet_timewait_death_row *,
++			struct sock *, __u16, struct inet_timewait_sock **),
++		void (*hash)(struct inet_hashinfo *, struct sock *));
+ extern int inet_hash_connect(struct inet_timewait_death_row *death_row,
+ 			     struct sock *sk);
+ #endif /* _INET_HASHTABLES_H */
 diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
 index abaff05..67e9250 100644
 --- a/include/net/inet_timewait_sock.h
@@ -818456,10 +871206,18 @@
  
  extern int			ipv6_route_ioctl(unsigned int cmd, void __user *arg);
 diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
-index ed514bf..9daa60b 100644
+index ed514bf..90d1175 100644
 --- a/include/net/ip_fib.h
 +++ b/include/net/ip_fib.h
-@@ -125,11 +125,15 @@ struct fib_result_nl {
+@@ -69,6 +69,7 @@ struct fib_nh {
+ struct fib_info {
+ 	struct hlist_node	fib_hash;
+ 	struct hlist_node	fib_lhash;
++	struct net		*fib_net;
+ 	int			fib_treeref;
+ 	atomic_t		fib_clntref;
+ 	int			fib_dead;
+@@ -125,11 +126,15 @@ struct fib_result_nl {
  #define FIB_RES_NH(res)		((res).fi->fib_nh[(res).nh_sel])
  #define FIB_RES_RESET(res)	((res).nh_sel = 0)
  
@@ -818475,7 +871233,7 @@
  #endif /* CONFIG_IP_ROUTE_MULTIPATH */
  
  #define FIB_RES_PREFSRC(res)		((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res))
-@@ -141,6 +145,7 @@ struct fib_table {
+@@ -141,6 +146,7 @@ struct fib_table {
  	struct hlist_node tb_hlist;
  	u32		tb_id;
  	unsigned	tb_stamp;
@@ -818483,7 +871241,7 @@
  	int		(*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
  	int		(*tb_insert)(struct fib_table *, struct fib_config *);
  	int		(*tb_delete)(struct fib_table *, struct fib_config *);
-@@ -155,50 +160,51 @@ struct fib_table {
+@@ -155,50 +161,51 @@ struct fib_table {
  
  #ifndef CONFIG_IP_MULTIPLE_TABLES
  
@@ -818561,7 +871319,7 @@
  
  #endif /* CONFIG_IP_MULTIPLE_TABLES */
  
-@@ -207,18 +213,19 @@ extern const struct nla_policy rtm_ipv4_policy[];
+@@ -207,18 +214,20 @@ extern const struct nla_policy rtm_ipv4_policy[];
  extern void		ip_fib_init(void);
  extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
  			       struct net_device *dev, __be32 *spec_dst, u32 *itag);
@@ -818573,7 +871331,9 @@
  
  /* Exported by fib_semantics.c */
  extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
- extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
+-extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
++extern int fib_sync_down_dev(struct net_device *dev, int force);
++extern int fib_sync_down_addr(struct net *net, __be32 local);
  extern int fib_sync_up(struct net_device *dev);
  extern __be32  __fib_res_prefsrc(struct fib_result *res);
 +extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
@@ -818586,7 +871346,7 @@
  
  static inline void fib_combine_itag(u32 *itag, struct fib_result *res)
  {
-@@ -255,8 +262,8 @@ static inline void fib_res_put(struct fib_result *res)
+@@ -255,8 +264,8 @@ static inline void fib_res_put(struct fib_result *res)
  }
  
  #ifdef CONFIG_PROC_FS
@@ -819476,10 +872236,10 @@
  static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
  {
 diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
-index 5dd6d90..b8c1d60 100644
+index 5dd6d90..28738b7 100644
 --- a/include/net/net_namespace.h
 +++ b/include/net/net_namespace.h
-@@ -8,8 +8,16 @@
+@@ -8,8 +8,17 @@
  #include <linux/workqueue.h>
  #include <linux/list.h>
  
@@ -819487,6 +872247,7 @@
 +#include <net/netns/packet.h>
 +#include <net/netns/ipv4.h>
 +#include <net/netns/ipv6.h>
++#include <net/netns/x_tables.h>
 +
  struct proc_dir_entry;
  struct net_device;
@@ -819496,7 +872257,7 @@
  struct net {
  	atomic_t		count;		/* To decided when the network
  						 *  namespace should be freed.
-@@ -24,11 +32,30 @@ struct net {
+@@ -24,11 +33,33 @@ struct net {
  	struct proc_dir_entry 	*proc_net_stat;
  	struct proc_dir_entry 	*proc_net_root;
  
@@ -819524,10 +872285,13 @@
 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 +	struct netns_ipv6	ipv6;
 +#endif
++#ifdef CONFIG_NETFILTER
++	struct netns_xt		xt;
++#endif
  };
  
  #ifdef CONFIG_NET
-@@ -137,4 +164,11 @@ extern void unregister_pernet_subsys(struct pernet_operations *);
+@@ -137,4 +168,11 @@ extern void unregister_pernet_subsys(struct pernet_operations *);
  extern int register_pernet_device(struct pernet_operations *);
  extern void unregister_pernet_device(struct pernet_operations *);
  
@@ -819567,10 +872331,55 @@
  
  #endif /* _NF_CONNTRACK_IPV6_H*/
 diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
-index 4ac5ab1..857d899 100644
+index 4ac5ab1..90b3e7f 100644
 --- a/include/net/netfilter/nf_conntrack.h
 +++ b/include/net/netfilter/nf_conntrack.h
-@@ -223,8 +223,6 @@ extern void nf_conntrack_tcp_update(struct sk_buff *skb,
+@@ -129,6 +129,8 @@ struct nf_conn
+ 
+ 	/* Extensions */
+ 	struct nf_ct_ext *ext;
++
++	struct rcu_head rcu;
+ };
+ 
+ static inline struct nf_conn *
+@@ -143,7 +145,7 @@ nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
+ 
+ /* Alter reply tuple (maybe alter helper). */
+ extern void
+-nf_conntrack_alter_reply(struct nf_conn *conntrack,
++nf_conntrack_alter_reply(struct nf_conn *ct,
+ 			 const struct nf_conntrack_tuple *newreply);
+ 
+ /* Is this tuple taken? (ignoring any belonging to the given
+@@ -171,13 +173,12 @@ static inline void nf_ct_put(struct nf_conn *ct)
+ extern int nf_ct_l3proto_try_module_get(unsigned short l3proto);
+ extern void nf_ct_l3proto_module_put(unsigned short l3proto);
+ 
+-extern struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced);
++extern struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced);
+ extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced,
+-				 int size);
++				 unsigned int size);
+ 
+ extern struct nf_conntrack_tuple_hash *
+-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
+-		    const struct nf_conn *ignored_conntrack);
++__nf_conntrack_find(const struct nf_conntrack_tuple *tuple);
+ 
+ extern void nf_conntrack_hash_insert(struct nf_conn *ct);
+ 
+@@ -215,16 +216,14 @@ static inline void nf_ct_refresh(struct nf_conn *ct,
+ 
+ /* These are for NAT.  Icky. */
+ /* Update TCP window tracking data when NAT mangles the packet */
+-extern void nf_conntrack_tcp_update(struct sk_buff *skb,
++extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
+ 				    unsigned int dataoff,
+-				    struct nf_conn *conntrack,
++				    struct nf_conn *ct,
+ 				    int dir);
+ 
  /* Fake conntrack entry for untracked connections */
  extern struct nf_conn nf_conntrack_untracked;
  
@@ -819579,7 +872388,7 @@
  /* Iterate over all conntracks: if iter returns true, it's deleted. */
  extern void
  nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data);
-@@ -264,10 +262,5 @@ do {							\
+@@ -264,10 +263,5 @@ do {							\
  	local_bh_enable();				\
  } while (0)
  
@@ -819591,7 +872400,7 @@
  #endif /* __KERNEL__ */
  #endif /* _NF_CONNTRACK_H */
 diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
-index a532e7b..7ad0828 100644
+index a532e7b..9ee2646 100644
 --- a/include/net/netfilter/nf_conntrack_core.h
 +++ b/include/net/netfilter/nf_conntrack_core.h
 @@ -30,16 +30,6 @@ extern void nf_conntrack_cleanup(void);
@@ -819611,7 +872420,7 @@
  extern int
  nf_ct_get_tuple(const struct sk_buff *skb,
  		unsigned int nhoff,
-@@ -76,8 +66,6 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
+@@ -76,15 +66,13 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
  	return ret;
  }
  
@@ -819619,12 +872428,31 @@
 -
  int
  print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
- 	    struct nf_conntrack_l3proto *l3proto,
+-	    struct nf_conntrack_l3proto *l3proto,
+-	    struct nf_conntrack_l4proto *proto);
++            const struct nf_conntrack_l3proto *l3proto,
++            const struct nf_conntrack_l4proto *proto);
+ 
+ extern struct hlist_head *nf_conntrack_hash;
+-extern rwlock_t nf_conntrack_lock ;
++extern spinlock_t nf_conntrack_lock ;
+ extern struct hlist_head unconfirmed;
+ 
+ #endif /* _NF_CONNTRACK_CORE_H */
 diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
-index b47c04f..6c3fd25 100644
+index b47c04f..cb608a1 100644
 --- a/include/net/netfilter/nf_conntrack_expect.h
 +++ b/include/net/netfilter/nf_conntrack_expect.h
-@@ -73,8 +73,8 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
+@@ -49,6 +49,8 @@ struct nf_conntrack_expect
+ 	/* Direction relative to the master connection. */
+ 	enum ip_conntrack_dir dir;
+ #endif
++
++	struct rcu_head rcu;
+ };
+ 
+ #define NF_CT_EXPECT_PERMANENT 0x1
+@@ -73,8 +75,8 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
     nf_ct_expect_related.  You will have to call put afterwards. */
  struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
  void nf_ct_expect_init(struct nf_conntrack_expect *, int,
@@ -819636,10 +872464,23 @@
  void nf_ct_expect_put(struct nf_conntrack_expect *exp);
  int nf_ct_expect_related(struct nf_conntrack_expect *expect);
 diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
-index d7b2d54..2f3af00 100644
+index d7b2d54..4ca125e 100644
 --- a/include/net/netfilter/nf_conntrack_helper.h
 +++ b/include/net/netfilter/nf_conntrack_helper.h
-@@ -58,4 +58,8 @@ static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
+@@ -43,12 +43,8 @@ extern struct nf_conntrack_helper *
+ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple);
+ 
+ extern struct nf_conntrack_helper *
+-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
+-
+-extern struct nf_conntrack_helper *
+ __nf_conntrack_helper_find_byname(const char *name);
+ 
+-extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
+ extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
+ extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
+ 
+@@ -58,4 +54,8 @@ static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
  {
  	return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
  }
@@ -819649,10 +872490,10 @@
 +
  #endif /*_NF_CONNTRACK_HELPER_H*/
 diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
-index 15888fc..d5526bc 100644
+index 15888fc..b886e3a 100644
 --- a/include/net/netfilter/nf_conntrack_l3proto.h
 +++ b/include/net/netfilter/nf_conntrack_l3proto.h
-@@ -42,9 +42,6 @@ struct nf_conntrack_l3proto
+@@ -42,11 +42,8 @@ struct nf_conntrack_l3proto
  	int (*print_tuple)(struct seq_file *s,
  			   const struct nf_conntrack_tuple *);
  
@@ -819660,8 +872501,20 @@
 -	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
 -
  	/* Returns verdict for packet, or -1 for invalid. */
- 	int (*packet)(struct nf_conn *conntrack,
+-	int (*packet)(struct nf_conn *conntrack,
++	int (*packet)(struct nf_conn *ct,
  		      const struct sk_buff *skb,
+ 		      enum ip_conntrack_info ctinfo);
+ 
+@@ -54,7 +51,7 @@ struct nf_conntrack_l3proto
+ 	 * Called when a new connection for this protocol found;
+ 	 * returns TRUE if it's OK.  If so, packet() called next.
+ 	 */
+-	int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
++	int (*new)(struct nf_conn *ct, const struct sk_buff *skb);
+ 
+ 	/*
+ 	 * Called before tracking. 
 @@ -73,7 +70,7 @@ struct nf_conntrack_l3proto
  
  #ifdef CONFIG_SYSCTL
@@ -819671,8 +872524,74 @@
  	struct ctl_table	*ctl_table;
  #endif /* CONFIG_SYSCTL */
  
+diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
+index fb50c21..efc16ec 100644
+--- a/include/net/netfilter/nf_conntrack_l4proto.h
++++ b/include/net/netfilter/nf_conntrack_l4proto.h
+@@ -23,9 +23,6 @@ struct nf_conntrack_l4proto
+ 	/* L4 Protocol number. */
+ 	u_int8_t l4proto;
+ 
+-	/* Protocol name */
+-	const char *name;
+-
+ 	/* Try to fill in the third arg: dataoff is offset past network protocol
+            hdr.  Return true if possible. */
+ 	int (*pkt_to_tuple)(const struct sk_buff *skb,
+@@ -38,15 +35,8 @@ struct nf_conntrack_l4proto
+ 	int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
+ 			    const struct nf_conntrack_tuple *orig);
+ 
+-	/* Print out the per-protocol part of the tuple. Return like seq_* */
+-	int (*print_tuple)(struct seq_file *s,
+-			   const struct nf_conntrack_tuple *);
+-
+-	/* Print out the private part of the conntrack. */
+-	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
+-
+ 	/* Returns verdict for packet, or -1 for invalid. */
+-	int (*packet)(struct nf_conn *conntrack,
++	int (*packet)(struct nf_conn *ct,
+ 		      const struct sk_buff *skb,
+ 		      unsigned int dataoff,
+ 		      enum ip_conntrack_info ctinfo,
+@@ -55,16 +45,23 @@ struct nf_conntrack_l4proto
+ 
+ 	/* Called when a new connection for this protocol found;
+ 	 * returns TRUE if it's OK.  If so, packet() called next. */
+-	int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb,
++	int (*new)(struct nf_conn *ct, const struct sk_buff *skb,
+ 		   unsigned int dataoff);
+ 
+ 	/* Called when a conntrack entry is destroyed */
+-	void (*destroy)(struct nf_conn *conntrack);
++	void (*destroy)(struct nf_conn *ct);
+ 
+ 	int (*error)(struct sk_buff *skb, unsigned int dataoff,
+ 		     enum ip_conntrack_info *ctinfo,
+ 		     int pf, unsigned int hooknum);
+ 
++	/* Print out the per-protocol part of the tuple. Return like seq_* */
++	int (*print_tuple)(struct seq_file *s,
++			   const struct nf_conntrack_tuple *);
++
++	/* Print out the private part of the conntrack. */
++	int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
++
+ 	/* convert protoinfo to nfnetink attributes */
+ 	int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
+ 			 const struct nf_conn *ct);
+@@ -87,6 +84,8 @@ struct nf_conntrack_l4proto
+ 	struct ctl_table	*ctl_compat_table;
+ #endif
+ #endif
++	/* Protocol name */
++	const char *name;
+ 
+ 	/* Module (if any) which this is connected to. */
+ 	struct module *me;
 diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
-index c48e390..45cb17c 100644
+index c48e390..e69ab2e 100644
 --- a/include/net/netfilter/nf_conntrack_tuple.h
 +++ b/include/net/netfilter/nf_conntrack_tuple.h
 @@ -10,6 +10,7 @@
@@ -819727,9 +872646,60 @@
  		union nf_conntrack_man_proto u;
  	} src;
  };
+@@ -139,34 +132,33 @@ struct nf_conntrack_tuple_hash
+ 
+ #endif /* __KERNEL__ */
+ 
+-static inline int nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
+-				        const struct nf_conntrack_tuple *t2)
++static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
++					  const struct nf_conntrack_tuple *t2)
+ { 
+ 	return (t1->src.u3.all[0] == t2->src.u3.all[0] &&
+ 		t1->src.u3.all[1] == t2->src.u3.all[1] &&
+ 		t1->src.u3.all[2] == t2->src.u3.all[2] &&
+ 		t1->src.u3.all[3] == t2->src.u3.all[3] &&
+ 		t1->src.u.all == t2->src.u.all &&
+-		t1->src.l3num == t2->src.l3num &&
+-		t1->dst.protonum == t2->dst.protonum);
++		t1->src.l3num == t2->src.l3num);
+ }
+ 
+-static inline int nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
+-				        const struct nf_conntrack_tuple *t2)
++static inline int __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
++					  const struct nf_conntrack_tuple *t2)
+ {
+ 	return (t1->dst.u3.all[0] == t2->dst.u3.all[0] &&
+ 		t1->dst.u3.all[1] == t2->dst.u3.all[1] &&
+ 		t1->dst.u3.all[2] == t2->dst.u3.all[2] &&
+ 		t1->dst.u3.all[3] == t2->dst.u3.all[3] &&
+ 		t1->dst.u.all == t2->dst.u.all &&
+-		t1->src.l3num == t2->src.l3num &&
+ 		t1->dst.protonum == t2->dst.protonum);
+ }
+ 
+ static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
+ 				    const struct nf_conntrack_tuple *t2)
+ {
+-	return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2);
++	return __nf_ct_tuple_src_equal(t1, t2) &&
++	       __nf_ct_tuple_dst_equal(t1, t2);
+ }
+ 
+ static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1,
+@@ -206,7 +198,7 @@ static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t,
+ 				       const struct nf_conntrack_tuple_mask *mask)
+ {
+ 	return nf_ct_tuple_src_mask_cmp(t, tuple, mask) &&
+-	       nf_ct_tuple_dst_equal(t, tuple);
++	       __nf_ct_tuple_dst_equal(t, tuple);
+ }
+ 
+ #endif /* _NF_CONNTRACK_TUPLE_H */
 diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h
 new file mode 100644
-index 0000000..037e824
+index 0000000..8c6b5ae
 --- /dev/null
 +++ b/include/net/netfilter/nf_log.h
 @@ -0,0 +1,59 @@
@@ -819789,7 +872759,7 @@
 +		   const struct net_device *in,
 +		   const struct net_device *out,
 +		   const struct nf_loginfo *li,
-+		   const char *fmt, ...);
++		   const char *fmt, ...) __attribute__ ((format(printf,7,8)));
 +
 +#endif /* _NF_LOG_H */
 diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
@@ -820157,10 +873127,10 @@
   */
 diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
 new file mode 100644
-index 0000000..15a0b05
+index 0000000..a9b4f60
 --- /dev/null
 +++ b/include/net/netns/ipv4.h
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,37 @@
 +/*
 + * ipv4 in net namespaces
 + */
@@ -820190,14 +873160,20 @@
 +	struct sock		*fibnl;
 +
 +	struct netns_frags	frags;
++#ifdef CONFIG_NETFILTER
++	struct xt_table		*iptable_filter;
++	struct xt_table		*iptable_mangle;
++	struct xt_table		*iptable_raw;
++	struct xt_table		*arptable_filter;
++#endif
 +};
 +#endif
 diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
 new file mode 100644
-index 0000000..187c424
+index 0000000..1dd7de4
 --- /dev/null
 +++ b/include/net/netns/ipv6.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,40 @@
 +/*
 + * ipv6 in net namespaces
 + */
@@ -820231,6 +873207,11 @@
 +	struct ipv6_devconf	*devconf_all;
 +	struct ipv6_devconf	*devconf_dflt;
 +	struct netns_frags	frags;
++#ifdef CONFIG_NETFILTER
++	struct xt_table		*ip6table_filter;
++	struct xt_table		*ip6table_mangle;
++	struct xt_table		*ip6table_raw;
++#endif
 +};
 +#endif
 diff --git a/include/net/netns/packet.h b/include/net/netns/packet.h
@@ -820273,8 +873254,24 @@
 +};
 +
 +#endif /* __NETNS_UNIX_H__ */
+diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
+new file mode 100644
+index 0000000..0cb63ed
+--- /dev/null
++++ b/include/net/netns/x_tables.h
+@@ -0,0 +1,10 @@
++#ifndef __NETNS_X_TABLES_H
++#define __NETNS_X_TABLES_H
++
++#include <linux/list.h>
++#include <linux/net.h>
++
++struct netns_xt {
++	struct list_head tables[NPROTO];
++};
++#endif
 diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
-index f285de6..8716eb7 100644
+index f285de6..d349c66 100644
 --- a/include/net/pkt_cls.h
 +++ b/include/net/pkt_cls.h
 @@ -2,7 +2,6 @@
@@ -820285,17 +873282,28 @@
  #include <net/sch_generic.h>
  #include <net/act_api.h>
  
-@@ -130,8 +129,8 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
+@@ -130,16 +129,16 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
  	return 0;
  }
  
 -extern int tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
 -	                     struct rtattr *rate_tlv, struct tcf_exts *exts,
+-	                     struct tcf_ext_map *map);
 +extern int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
 +	                     struct nlattr *rate_tlv, struct tcf_exts *exts,
- 	                     struct tcf_ext_map *map);
++	                     const struct tcf_ext_map *map);
  extern void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
  extern void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
+ 	                     struct tcf_exts *src);
+ extern int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
+-	                 struct tcf_ext_map *map);
++	                 const struct tcf_ext_map *map);
+ extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
+-	                       struct tcf_ext_map *map);
++	                       const struct tcf_ext_map *map);
+ 
+ /**
+  * struct tcf_pkt_info - packet information
 @@ -248,7 +247,7 @@ struct tcf_ematch_ops
  
  extern int tcf_em_register(struct tcf_ematch_ops *);
@@ -820347,10 +873355,10 @@
  #endif
  
 diff --git a/include/net/raw.h b/include/net/raw.h
-index e4af597..cca81d8 100644
+index e4af597..1828f81 100644
 --- a/include/net/raw.h
 +++ b/include/net/raw.h
-@@ -22,27 +22,39 @@
+@@ -22,27 +22,38 @@
  
  extern struct proto raw_prot;
  
@@ -820387,7 +873395,6 @@
 +struct raw_iter_state {
 +	struct seq_net_private p;
 +	int bucket;
-+	unsigned short family;
 +	struct raw_hashinfo *h;
 +};
 +
@@ -820395,8 +873402,8 @@
 +void *raw_seq_start(struct seq_file *seq, loff_t *pos);
 +void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 +void raw_seq_stop(struct seq_file *seq, void *v);
-+int raw_seq_open(struct inode *ino, struct file *file, struct raw_hashinfo *h,
-+		unsigned short family);
++int raw_seq_open(struct inode *ino, struct file *file,
++		 struct raw_hashinfo *h, const struct seq_operations *ops);
 +
  #endif
  
@@ -820439,10 +873446,17 @@
  int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
  					   struct sk_buff *skb));
 diff --git a/include/net/route.h b/include/net/route.h
-index 59b0b19..4eabf00 100644
+index 59b0b19..eadad59 100644
 --- a/include/net/route.h
 +++ b/include/net/route.h
-@@ -33,6 +33,7 @@
+@@ -27,12 +27,14 @@
+ #include <net/dst.h>
+ #include <net/inetpeer.h>
+ #include <net/flow.h>
++#include <net/sock.h>
+ #include <linux/in_route.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/route.h>
  #include <linux/ip.h>
  #include <linux/cache.h>
  #include <linux/security.h>
@@ -820450,7 +873464,15 @@
  
  #ifndef __KERNEL__
  #warning This file is not supposed to be used outside of kernel.
-@@ -110,16 +111,17 @@ extern int		ip_rt_init(void);
+@@ -60,6 +62,7 @@ struct rtable
+ 
+ 	struct in_device	*idev;
+ 	
++	int			rt_genid;
+ 	unsigned		rt_flags;
+ 	__u16			rt_type;
+ 
+@@ -110,16 +113,17 @@ extern int		ip_rt_init(void);
  extern void		ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
  				       __be32 src, struct net_device *dev);
  extern void		rt_cache_flush(int how);
@@ -820474,7 +873496,15 @@
  extern void		ip_rt_get_source(u8 *src, struct rtable *rt);
  extern int		ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb);
  
-@@ -156,8 +158,9 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
+@@ -147,6 +151,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
+ 				   int flags)
+ {
+ 	struct flowi fl = { .oif = oif,
++			    .mark = sk->sk_mark,
+ 			    .nl_u = { .ip4_u = { .daddr = dst,
+ 						 .saddr = src,
+ 						 .tos   = tos } },
+@@ -156,8 +161,9 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
  					 .dport = dport } } };
  
  	int err;
@@ -820485,7 +873515,7 @@
  		if (err)
  			return err;
  		fl.fl4_dst = (*rp)->rt_dst;
-@@ -166,7 +169,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
+@@ -166,7 +172,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
  		*rp = NULL;
  	}
  	security_sk_classify_flow(sk, &fl);
@@ -820494,7 +873524,7 @@
  }
  
  static inline int ip_route_newports(struct rtable **rp, u8 protocol,
-@@ -183,7 +186,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
+@@ -183,7 +189,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
  		ip_rt_put(*rp);
  		*rp = NULL;
  		security_sk_classify_flow(sk, &fl);
@@ -820867,7 +873897,7 @@
  
  #endif
 diff --git a/include/net/sock.h b/include/net/sock.h
-index 6e1542d..9023244 100644
+index 6e1542d..e3fb4c0 100644
 --- a/include/net/sock.h
 +++ b/include/net/sock.h
 @@ -47,6 +47,7 @@
@@ -820927,7 +873957,16 @@
  	unsigned short		sk_ack_backlog;
  	unsigned short		sk_max_ack_backlog;
  	__u32			sk_priority;
-@@ -439,7 +445,7 @@ static inline int sk_acceptq_is_full(struct sock *sk)
+@@ -256,6 +262,8 @@ struct sock {
+ 	__u32			sk_sndmsg_off;
+ 	int			sk_write_pending;
+ 	void			*sk_security;
++	__u32			sk_mark;
++	/* XXX 4 bytes hole on 64 bit */
+ 	void			(*sk_state_change)(struct sock *sk);
+ 	void			(*sk_data_ready)(struct sock *sk, int bytes);
+ 	void			(*sk_write_space)(struct sock *sk);
+@@ -439,7 +447,7 @@ static inline int sk_acceptq_is_full(struct sock *sk)
   */
  static inline int sk_stream_min_wspace(struct sock *sk)
  {
@@ -820936,7 +873975,7 @@
  }
  
  static inline int sk_stream_wspace(struct sock *sk)
-@@ -454,25 +460,6 @@ static inline int sk_stream_memory_free(struct sock *sk)
+@@ -454,25 +462,6 @@ static inline int sk_stream_memory_free(struct sock *sk)
  	return sk->sk_wmem_queued < sk->sk_sndbuf;
  }
  
@@ -820962,7 +874001,7 @@
  /* The per-socket spinlock must be held here. */
  static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
  {
-@@ -560,14 +547,11 @@ struct proto {
+@@ -560,14 +549,11 @@ struct proto {
  	void			(*unhash)(struct sock *sk);
  	int			(*get_port)(struct sock *sk, unsigned short snum);
  
@@ -820980,7 +874019,7 @@
  	/* Memory pressure */
  	void			(*enter_memory_pressure)(void);
  	atomic_t		*memory_allocated;	/* Current allocated memory. */
-@@ -575,7 +559,7 @@ struct proto {
+@@ -575,7 +561,7 @@ struct proto {
  	/*
  	 * Pressure flag: try to collapse.
  	 * Technical note: it is used by multiple contexts non atomically.
@@ -820989,7 +874028,7 @@
  	 * is strict, actions are advisory and have some latency.
  	 */
  	int			*memory_pressure;
-@@ -602,36 +586,6 @@ struct proto {
+@@ -602,36 +588,6 @@ struct proto {
  #endif
  };
  
@@ -821026,7 +874065,7 @@
  extern int proto_register(struct proto *prot, int alloc_slab);
  extern void proto_unregister(struct proto *prot);
  
-@@ -660,33 +614,42 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)
+@@ -660,33 +616,42 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)
  #define sk_refcnt_debug_release(sk) do { } while (0)
  #endif /* SOCK_REFCNT_DEBUG */
  
@@ -821088,7 +874127,7 @@
  
  /* With per-bucket locks this operation is not-atomic, so that
   * this version is not worse.
-@@ -750,32 +713,81 @@ static inline struct inode *SOCK_INODE(struct socket *socket)
+@@ -750,32 +715,81 @@ static inline struct inode *SOCK_INODE(struct socket *socket)
  	return &container_of(socket, struct socket_alloc, socket)->vfs_inode;
  }
  
@@ -821183,7 +874222,7 @@
  }
  
  /* Used by processes to "lock" a socket state, so that
-@@ -812,14 +824,14 @@ do {									\
+@@ -812,14 +826,14 @@ do {									\
  	lockdep_init_map(&(sk)->sk_lock.dep_map, (name), (key), 0);	\
  } while (0)
  
@@ -821200,7 +874239,7 @@
  
  /* BH context may only use the following locking interface. */
  #define bh_lock_sock(__sk)	spin_lock(&((__sk)->sk_lock.slock))
-@@ -1113,12 +1125,6 @@ static inline int sk_can_gso(const struct sock *sk)
+@@ -1113,12 +1127,6 @@ static inline int sk_can_gso(const struct sock *sk)
  
  extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
  
@@ -821213,7 +874252,7 @@
  static inline int skb_copy_to_page(struct sock *sk, char __user *from,
  				   struct sk_buff *skb, struct page *page,
  				   int off, int copy)
-@@ -1138,7 +1144,7 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
+@@ -1138,7 +1146,7 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
  	skb->data_len	     += copy;
  	skb->truesize	     += copy;
  	sk->sk_wmem_queued   += copy;
@@ -821222,7 +874261,7 @@
  	return 0;
  }
  
-@@ -1164,6 +1170,7 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
+@@ -1164,6 +1172,7 @@ static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
  	skb->sk = sk;
  	skb->destructor = sock_rfree;
  	atomic_add(skb->truesize, &sk->sk_rmem_alloc);
@@ -821230,7 +874269,7 @@
  }
  
  extern void sk_reset_timer(struct sock *sk, struct timer_list* timer,
-@@ -1225,45 +1232,12 @@ static inline void sk_wake_async(struct sock *sk, int how, int band)
+@@ -1225,45 +1234,12 @@ static inline void sk_wake_async(struct sock *sk, int how, int band)
  static inline void sk_stream_moderate_sndbuf(struct sock *sk)
  {
  	if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) {
@@ -821278,7 +874317,7 @@
  
  static inline struct page *sk_stream_alloc_page(struct sock *sk)
  {
-@@ -1282,7 +1256,7 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk)
+@@ -1282,7 +1258,7 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk)
   */
  static inline int sock_writeable(const struct sock *sk) 
  {
@@ -821287,7 +874326,7 @@
  }
  
  static inline gfp_t gfp_any(void)
-@@ -1391,23 +1365,11 @@ extern int net_msg_warn;
+@@ -1391,23 +1367,11 @@ extern int net_msg_warn;
  				lock_sock(sk); \
  				}
  
@@ -821674,7 +874713,7 @@
   *	Checksum computation is all in software, hence simpler getfrag.
   */
 diff --git a/include/net/xfrm.h b/include/net/xfrm.h
-index 1dd20cf..5ebb9ba 100644
+index 1dd20cf..ac72116 100644
 --- a/include/net/xfrm.h
 +++ b/include/net/xfrm.h
 @@ -19,6 +19,9 @@
@@ -821705,7 +874744,15 @@
  extern struct sock *xfrm_nl;
  extern u32 sysctl_xfrm_aevent_etime;
  extern u32 sysctl_xfrm_aevent_rseqth;
-@@ -183,7 +197,7 @@ struct xfrm_state
+@@ -145,6 +159,7 @@ struct xfrm_state
+ 	struct xfrm_algo	*aalg;
+ 	struct xfrm_algo	*ealg;
+ 	struct xfrm_algo	*calg;
++	struct xfrm_algo_aead	*aead;
+ 
+ 	/* Data for encapsulator */
+ 	struct xfrm_encap_tmpl	*encap;
+@@ -183,11 +198,11 @@ struct xfrm_state
  	struct timer_list	timer;
  
  	/* Last used time */
@@ -821714,7 +874761,12 @@
  
  	/* Reference to data common to all the instances of this
  	 * transformer. */
-@@ -227,22 +241,26 @@ struct km_event
+-	struct xfrm_type	*type;
++	const struct xfrm_type	*type;
+ 	struct xfrm_mode	*inner_mode;
+ 	struct xfrm_mode	*outer_mode;
+ 
+@@ -227,22 +242,26 @@ struct km_event
  	u32	event;
  };
  
@@ -821748,16 +874800,19 @@
  };
  
  extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
-@@ -257,6 +275,8 @@ extern int __xfrm_state_delete(struct xfrm_state *x);
+@@ -257,8 +276,10 @@ extern int __xfrm_state_delete(struct xfrm_state *x);
  
  struct xfrm_state_afinfo {
  	unsigned int		family;
 +	unsigned int		proto;
 +	unsigned int		eth_proto;
  	struct module		*owner;
- 	struct xfrm_type	*type_map[IPPROTO_MAX];
+-	struct xfrm_type	*type_map[IPPROTO_MAX];
++	const struct xfrm_type	*type_map[IPPROTO_MAX];
  	struct xfrm_mode	*mode_map[XFRM_MODE_MAX];
-@@ -267,6 +287,12 @@ struct xfrm_state_afinfo {
+ 	int			(*init_flags)(struct xfrm_state *x);
+ 	void			(*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
+@@ -267,6 +288,12 @@ struct xfrm_state_afinfo {
  	int			(*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);
  	int			(*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n);
  	int			(*output)(struct sk_buff *skb);
@@ -821770,7 +874825,7 @@
  };
  
  extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
-@@ -282,6 +308,8 @@ struct xfrm_type
+@@ -282,6 +309,8 @@ struct xfrm_type
  	__u8			flags;
  #define XFRM_TYPE_NON_FRAGMENT	1
  #define XFRM_TYPE_REPLAY_PROT	2
@@ -821779,7 +874834,7 @@
  
  	int			(*init_state)(struct xfrm_state *x);
  	void			(*destructor)(struct xfrm_state *);
-@@ -289,8 +317,6 @@ struct xfrm_type
+@@ -289,16 +318,35 @@ struct xfrm_type
  	int			(*output)(struct xfrm_state *, struct sk_buff *pskb);
  	int			(*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *);
  	int			(*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
@@ -821788,8 +874843,11 @@
  	/* Estimate maximal size of result of transformation of a dgram */
  	u32			(*get_mtu)(struct xfrm_state *, int size);
  };
-@@ -299,6 +325,27 @@ extern int xfrm_register_type(struct xfrm_type *type, unsigned short family);
- extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family);
+ 
+-extern int xfrm_register_type(struct xfrm_type *type, unsigned short family);
+-extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family);
++extern int xfrm_register_type(const struct xfrm_type *type, unsigned short family);
++extern int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
  
  struct xfrm_mode {
 +	/*
@@ -821816,7 +874874,7 @@
  	int (*input)(struct xfrm_state *x, struct sk_buff *skb);
  
  	/*
-@@ -312,7 +359,18 @@ struct xfrm_mode {
+@@ -312,7 +360,18 @@ struct xfrm_mode {
  	 * header.  The value of the network header will always point
  	 * to the top IP header while skb->data will point to the payload.
  	 */
@@ -821836,7 +874894,7 @@
  
  	struct xfrm_state_afinfo *afinfo;
  	struct module *owner;
-@@ -454,6 +512,51 @@ struct xfrm_skb_cb {
+@@ -454,6 +513,51 @@ struct xfrm_skb_cb {
  
  #define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0]))
  
@@ -821888,7 +874946,7 @@
  /* Audit Information */
  struct xfrm_audit
  {
-@@ -462,41 +565,59 @@ struct xfrm_audit
+@@ -462,41 +566,59 @@ struct xfrm_audit
  };
  
  #ifdef CONFIG_AUDITSYSCALL
@@ -821960,7 +875018,7 @@
  #endif /* CONFIG_AUDITSYSCALL */
  
  static inline void xfrm_pol_hold(struct xfrm_policy *policy)
-@@ -505,12 +626,12 @@ static inline void xfrm_pol_hold(struct xfrm_policy *policy)
+@@ -505,12 +627,12 @@ static inline void xfrm_pol_hold(struct xfrm_policy *policy)
  		atomic_inc(&policy->refcnt);
  }
  
@@ -821975,7 +875033,7 @@
  }
  
  #ifdef CONFIG_XFRM_SUB_POLICY
-@@ -757,17 +878,25 @@ xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short
+@@ -757,17 +879,25 @@ xfrm_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short
  }
  
  #ifdef CONFIG_XFRM
@@ -822005,7 +875063,7 @@
  }
  
  static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
-@@ -780,7 +909,34 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s
+@@ -780,7 +910,34 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s
  	return xfrm_policy_check(sk, dir, skb, AF_INET6);
  }
  
@@ -822041,7 +875099,7 @@
  extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family);
  
  static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
-@@ -841,6 +997,22 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk
+@@ -841,6 +998,22 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk
  {
  	return 1;
  }
@@ -822064,7 +875122,26 @@
  #endif
  
  static __inline__
-@@ -981,12 +1153,27 @@ struct xfrm6_tunnel {
+@@ -936,6 +1109,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
+ /*
+  * xfrm algorithm information
+  */
++struct xfrm_algo_aead_info {
++	u16 icv_truncbits;
++};
++
+ struct xfrm_algo_auth_info {
+ 	u16 icv_truncbits;
+ 	u16 icv_fullbits;
+@@ -955,6 +1132,7 @@ struct xfrm_algo_desc {
+ 	char *compat;
+ 	u8 available:1;
+ 	union {
++		struct xfrm_algo_aead_info aead;
+ 		struct xfrm_algo_auth_info auth;
+ 		struct xfrm_algo_encr_info encr;
+ 		struct xfrm_algo_comp_info comp;
+@@ -981,12 +1159,27 @@ struct xfrm6_tunnel {
  
  extern void xfrm_init(void);
  extern void xfrm4_init(void);
@@ -822095,7 +875172,7 @@
  
  extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *);
  extern struct xfrm_state *xfrm_state_alloc(void);
-@@ -1045,14 +1232,23 @@ extern int xfrm_state_delete(struct xfrm_state *x);
+@@ -1045,14 +1238,23 @@ extern int xfrm_state_delete(struct xfrm_state *x);
  extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
  extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
  extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
@@ -822120,7 +875197,7 @@
  extern int xfrm4_rcv(struct sk_buff *skb);
  
  static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
-@@ -1060,10 +1256,15 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
+@@ -1060,10 +1262,15 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
  	return xfrm4_rcv_encap(skb, nexthdr, spi, 0);
  }
  
@@ -822136,7 +875213,7 @@
  extern int xfrm6_rcv(struct sk_buff *skb);
  extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
  			    xfrm_address_t *saddr, u8 proto);
-@@ -1072,6 +1273,8 @@ extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short
+@@ -1072,6 +1279,8 @@ extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short
  extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
  extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
  extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
@@ -822145,7 +875222,7 @@
  extern int xfrm6_output(struct sk_buff *skb);
  extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
  				 u8 **prevhdr);
-@@ -1079,7 +1282,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
+@@ -1079,7 +1288,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
  #ifdef CONFIG_XFRM
  extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
  extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
@@ -822153,7 +875230,7 @@
  #else
  static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
  {
-@@ -1092,11 +1294,6 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
+@@ -1092,11 +1300,6 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
   	kfree_skb(skb);
  	return 0;
  }
@@ -822165,7 +875242,7 @@
  #endif
  
  struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
-@@ -1113,11 +1310,9 @@ extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
+@@ -1113,11 +1316,9 @@ extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
  struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
  				  xfrm_address_t *daddr, xfrm_address_t *saddr,
  				  int create, unsigned short family);
@@ -822177,7 +875254,16 @@
  
  #ifdef CONFIG_XFRM_MIGRATE
  extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
-@@ -1214,4 +1409,9 @@ static inline void xfrm_states_delete(struct xfrm_state **states, int n)
+@@ -1148,6 +1349,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
+ extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
+ extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
+ extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
++extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
++						   int probe);
+ 
+ struct hash_desc;
+ struct scatterlist;
+@@ -1214,4 +1417,9 @@ static inline void xfrm_states_delete(struct xfrm_state **states, int n)
  }
  #endif
  
@@ -826009,6 +879095,1362 @@
  
  ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
  # According to Alan Modra <alan at linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff --git a/kernel/audit.c b/kernel/audit.c
+index f93c271..c8555b1 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -66,10 +66,11 @@
+  * (Initialization happens after skb_init is called.) */
+ static int	audit_initialized;
+ 
+-/* 0 - no auditing
+- * 1 - auditing enabled
+- * 2 - auditing enabled and configuration is locked/unchangeable. */
++#define AUDIT_OFF	0
++#define AUDIT_ON	1
++#define AUDIT_LOCKED	2
+ int		audit_enabled;
++int		audit_ever_enabled;
+ 
+ /* Default state when kernel boots without any parameters. */
+ static int	audit_default;
+@@ -152,8 +153,10 @@ struct audit_buffer {
+ 
+ static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
+ {
+-	struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+-	nlh->nlmsg_pid = pid;
++	if (ab) {
++		struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
++		nlh->nlmsg_pid = pid;
++	}
+ }
+ 
+ void audit_panic(const char *message)
+@@ -163,7 +166,8 @@ void audit_panic(const char *message)
+ 	case AUDIT_FAIL_SILENT:
+ 		break;
+ 	case AUDIT_FAIL_PRINTK:
+-		printk(KERN_ERR "audit: %s\n", message);
++		if (printk_ratelimit())
++			printk(KERN_ERR "audit: %s\n", message);
+ 		break;
+ 	case AUDIT_FAIL_PANIC:
+ 		panic("audit: %s\n", message);
+@@ -231,161 +235,107 @@ void audit_log_lost(const char *message)
+ 	}
+ 
+ 	if (print) {
+-		printk(KERN_WARNING
+-		       "audit: audit_lost=%d audit_rate_limit=%d audit_backlog_limit=%d\n",
+-		       atomic_read(&audit_lost),
+-		       audit_rate_limit,
+-		       audit_backlog_limit);
++		if (printk_ratelimit())
++			printk(KERN_WARNING
++				"audit: audit_lost=%d audit_rate_limit=%d "
++				"audit_backlog_limit=%d\n",
++				atomic_read(&audit_lost),
++				audit_rate_limit,
++				audit_backlog_limit);
+ 		audit_panic(message);
+ 	}
+ }
+ 
+-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
++static int audit_log_config_change(char *function_name, int new, int old,
++				   uid_t loginuid, u32 sid, int allow_changes)
+ {
+-	int res, rc = 0, old = audit_rate_limit;
+-
+-	/* check if we are locked */
+-	if (audit_enabled == 2)
+-		res = 0;
+-	else
+-		res = 1;
++	struct audit_buffer *ab;
++	int rc = 0;
+ 
++	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
++	audit_log_format(ab, "%s=%d old=%d by auid=%u", function_name, new,
++			 old, loginuid);
+ 	if (sid) {
+ 		char *ctx = NULL;
+ 		u32 len;
+-		if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
+-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-				"audit_rate_limit=%d old=%d by auid=%u"
+-				" subj=%s res=%d",
+-				limit, old, loginuid, ctx, res);
++
++		rc = selinux_sid_to_string(sid, &ctx, &len);
++		if (rc) {
++			audit_log_format(ab, " sid=%u", sid);
++			allow_changes = 0; /* Something weird, deny request */
++		} else {
++			audit_log_format(ab, " subj=%s", ctx);
+ 			kfree(ctx);
+-		} else
+-			res = 0; /* Something weird, deny request */
++		}
+ 	}
+-	audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-		"audit_rate_limit=%d old=%d by auid=%u res=%d",
+-		limit, old, loginuid, res);
+-
+-	/* If we are allowed, make the change */
+-	if (res == 1)
+-		audit_rate_limit = limit;
+-	/* Not allowed, update reason */
+-	else if (rc == 0)
+-		rc = -EPERM;
++	audit_log_format(ab, " res=%d", allow_changes);
++	audit_log_end(ab);
+ 	return rc;
+ }
+ 
+-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
++static int audit_do_config_change(char *function_name, int *to_change,
++				  int new, uid_t loginuid, u32 sid)
+ {
+-	int res, rc = 0, old = audit_backlog_limit;
++	int allow_changes, rc = 0, old = *to_change;
+ 
+ 	/* check if we are locked */
+-	if (audit_enabled == 2)
+-		res = 0;
++	if (audit_enabled == AUDIT_LOCKED)
++		allow_changes = 0;
+ 	else
+-		res = 1;
++		allow_changes = 1;
+ 
+-	if (sid) {
+-		char *ctx = NULL;
+-		u32 len;
+-		if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
+-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-				"audit_backlog_limit=%d old=%d by auid=%u"
+-				" subj=%s res=%d",
+-				limit, old, loginuid, ctx, res);
+-			kfree(ctx);
+-		} else
+-			res = 0; /* Something weird, deny request */
++	if (audit_enabled != AUDIT_OFF) {
++		rc = audit_log_config_change(function_name, new, old,
++					     loginuid, sid, allow_changes);
++		if (rc)
++			allow_changes = 0;
+ 	}
+-	audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-		"audit_backlog_limit=%d old=%d by auid=%u res=%d",
+-		limit, old, loginuid, res);
+ 
+ 	/* If we are allowed, make the change */
+-	if (res == 1)
+-		audit_backlog_limit = limit;
++	if (allow_changes == 1)
++		*to_change = new;
+ 	/* Not allowed, update reason */
+ 	else if (rc == 0)
+ 		rc = -EPERM;
+ 	return rc;
+ }
+ 
+-static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
++static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
+ {
+-	int res, rc = 0, old = audit_enabled;
++	return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
++				      limit, loginuid, sid);
++}
++
++static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
++{
++	return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
++				      limit, loginuid, sid);
++}
+ 
+-	if (state < 0 || state > 2)
++static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
++{
++	int rc;
++	if (state < AUDIT_OFF || state > AUDIT_LOCKED)
+ 		return -EINVAL;
+ 
+-	/* check if we are locked */
+-	if (audit_enabled == 2)
+-		res = 0;
+-	else
+-		res = 1;
++	rc =  audit_do_config_change("audit_enabled", &audit_enabled, state,
++				     loginuid, sid);
+ 
+-	if (sid) {
+-		char *ctx = NULL;
+-		u32 len;
+-		if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
+-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-				"audit_enabled=%d old=%d by auid=%u"
+-				" subj=%s res=%d",
+-				state, old, loginuid, ctx, res);
+-			kfree(ctx);
+-		} else
+-			res = 0; /* Something weird, deny request */
+-	}
+-	audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-		"audit_enabled=%d old=%d by auid=%u res=%d",
+-		state, old, loginuid, res);
++	if (!rc)
++		audit_ever_enabled |= !!state;
+ 
+-	/* If we are allowed, make the change */
+-	if (res == 1)
+-		audit_enabled = state;
+-	/* Not allowed, update reason */
+-	else if (rc == 0)
+-		rc = -EPERM;
+ 	return rc;
+ }
+ 
+ static int audit_set_failure(int state, uid_t loginuid, u32 sid)
+ {
+-	int res, rc = 0, old = audit_failure;
+-
+ 	if (state != AUDIT_FAIL_SILENT
+ 	    && state != AUDIT_FAIL_PRINTK
+ 	    && state != AUDIT_FAIL_PANIC)
+ 		return -EINVAL;
+ 
+-	/* check if we are locked */
+-	if (audit_enabled == 2)
+-		res = 0;
+-	else
+-		res = 1;
+-
+-	if (sid) {
+-		char *ctx = NULL;
+-		u32 len;
+-		if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
+-			audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-				"audit_failure=%d old=%d by auid=%u"
+-				" subj=%s res=%d",
+-				state, old, loginuid, ctx, res);
+-			kfree(ctx);
+-		} else
+-			res = 0; /* Something weird, deny request */
+-	}
+-	audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-		"audit_failure=%d old=%d by auid=%u res=%d",
+-		state, old, loginuid, res);
+-
+-	/* If we are allowed, make the change */
+-	if (res == 1)
+-		audit_failure = state;
+-	/* Not allowed, update reason */
+-	else if (rc == 0)
+-		rc = -EPERM;
+-	return rc;
++	return audit_do_config_change("audit_failure", &audit_failure, state,
++				      loginuid, sid);
+ }
+ 
+ static int kauditd_thread(void *dummy)
+@@ -405,7 +355,11 @@ static int kauditd_thread(void *dummy)
+ 					audit_pid = 0;
+ 				}
+ 			} else {
+-				printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
++				if (printk_ratelimit())
++					printk(KERN_NOTICE "%s\n", skb->data +
++						NLMSG_SPACE(0));
++				else
++					audit_log_lost("printk limit exceeded\n");
+ 				kfree_skb(skb);
+ 			}
+ 		} else {
+@@ -573,6 +527,33 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
+ 	return err;
+ }
+ 
++static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
++				     u32 pid, u32 uid, uid_t auid, u32 sid)
++{
++	int rc = 0;
++	char *ctx = NULL;
++	u32 len;
++
++	if (!audit_enabled) {
++		*ab = NULL;
++		return rc;
++	}
++
++	*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
++	audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
++			 pid, uid, auid);
++	if (sid) {
++		rc = selinux_sid_to_string(sid, &ctx, &len);
++		if (rc)
++			audit_log_format(*ab, " ssid=%u", sid);
++		else
++			audit_log_format(*ab, " subj=%s", ctx);
++		kfree(ctx);
++	}
++
++	return rc;
++}
++
+ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ {
+ 	u32			uid, pid, seq, sid;
+@@ -583,7 +564,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 	u16			msg_type = nlh->nlmsg_type;
+ 	uid_t			loginuid; /* loginuid of sender */
+ 	struct audit_sig_info   *sig_data;
+-	char			*ctx;
++	char			*ctx = NULL;
+ 	u32			len;
+ 
+ 	err = audit_netlink_ok(skb, msg_type);
+@@ -634,23 +615,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 			if (err < 0) return err;
+ 		}
+ 		if (status_get->mask & AUDIT_STATUS_PID) {
+-			int old   = audit_pid;
+-			if (sid) {
+-				if ((err = selinux_sid_to_string(
+-						sid, &ctx, &len)))
+-					return err;
+-				else
+-					audit_log(NULL, GFP_KERNEL,
+-						AUDIT_CONFIG_CHANGE,
+-						"audit_pid=%d old=%d by auid=%u subj=%s",
+-						status_get->pid, old,
+-						loginuid, ctx);
+-				kfree(ctx);
+-			} else
+-				audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+-					"audit_pid=%d old=%d by auid=%u",
+-					  status_get->pid, old, loginuid);
+-			audit_pid = status_get->pid;
++			int new_pid = status_get->pid;
++
++			if (audit_enabled != AUDIT_OFF)
++				audit_log_config_change("audit_pid", new_pid,
++							audit_pid, loginuid,
++							sid, 1);
++
++			audit_pid = new_pid;
+ 		}
+ 		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
+ 			err = audit_set_rate_limit(status_get->rate_limit,
+@@ -673,64 +645,35 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 				if (err)
+ 					break;
+ 			}
+-			ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
+-			if (ab) {
+-				audit_log_format(ab,
+-						 "user pid=%d uid=%u auid=%u",
+-						 pid, uid, loginuid);
+-				if (sid) {
+-					if (selinux_sid_to_string(
+-							sid, &ctx, &len)) {
+-						audit_log_format(ab,
+-							" ssid=%u", sid);
+-						/* Maybe call audit_panic? */
+-					} else
+-						audit_log_format(ab,
+-							" subj=%s", ctx);
+-					kfree(ctx);
+-				}
+-				if (msg_type != AUDIT_USER_TTY)
+-					audit_log_format(ab, " msg='%.1024s'",
+-							 (char *)data);
+-				else {
+-					int size;
+-
+-					audit_log_format(ab, " msg=");
+-					size = nlmsg_len(nlh);
+-					audit_log_n_untrustedstring(ab, size,
+-								    data);
+-				}
+-				audit_set_pid(ab, pid);
+-				audit_log_end(ab);
++			audit_log_common_recv_msg(&ab, msg_type, pid, uid,
++						  loginuid, sid);
++
++			if (msg_type != AUDIT_USER_TTY)
++				audit_log_format(ab, " msg='%.1024s'",
++						 (char *)data);
++			else {
++				int size;
++
++				audit_log_format(ab, " msg=");
++				size = nlmsg_len(nlh);
++				audit_log_n_untrustedstring(ab, size,
++							    data);
+ 			}
++			audit_set_pid(ab, pid);
++			audit_log_end(ab);
+ 		}
+ 		break;
+ 	case AUDIT_ADD:
+ 	case AUDIT_DEL:
+ 		if (nlmsg_len(nlh) < sizeof(struct audit_rule))
+ 			return -EINVAL;
+-		if (audit_enabled == 2) {
+-			ab = audit_log_start(NULL, GFP_KERNEL,
+-					AUDIT_CONFIG_CHANGE);
+-			if (ab) {
+-				audit_log_format(ab,
+-						 "pid=%d uid=%u auid=%u",
+-						 pid, uid, loginuid);
+-				if (sid) {
+-					if (selinux_sid_to_string(
+-							sid, &ctx, &len)) {
+-						audit_log_format(ab,
+-							" ssid=%u", sid);
+-						/* Maybe call audit_panic? */
+-					} else
+-						audit_log_format(ab,
+-							" subj=%s", ctx);
+-					kfree(ctx);
+-				}
+-				audit_log_format(ab, " audit_enabled=%d res=0",
+-					audit_enabled);
+-				audit_log_end(ab);
+-			}
++		if (audit_enabled == AUDIT_LOCKED) {
++			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
++						  uid, loginuid, sid);
++
++			audit_log_format(ab, " audit_enabled=%d res=0",
++					 audit_enabled);
++			audit_log_end(ab);
+ 			return -EPERM;
+ 		}
+ 		/* fallthrough */
+@@ -743,28 +686,13 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 	case AUDIT_DEL_RULE:
+ 		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
+ 			return -EINVAL;
+-		if (audit_enabled == 2) {
+-			ab = audit_log_start(NULL, GFP_KERNEL,
+-					AUDIT_CONFIG_CHANGE);
+-			if (ab) {
+-				audit_log_format(ab,
+-						 "pid=%d uid=%u auid=%u",
+-						 pid, uid, loginuid);
+-				if (sid) {
+-					if (selinux_sid_to_string(
+-							sid, &ctx, &len)) {
+-						audit_log_format(ab,
+-							" ssid=%u", sid);
+-						/* Maybe call audit_panic? */
+-					} else
+-						audit_log_format(ab,
+-							" subj=%s", ctx);
+-					kfree(ctx);
+-				}
+-				audit_log_format(ab, " audit_enabled=%d res=0",
+-					audit_enabled);
+-				audit_log_end(ab);
+-			}
++		if (audit_enabled == AUDIT_LOCKED) {
++			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
++						  uid, loginuid, sid);
++
++			audit_log_format(ab, " audit_enabled=%d res=0",
++					 audit_enabled);
++			audit_log_end(ab);
+ 			return -EPERM;
+ 		}
+ 		/* fallthrough */
+@@ -775,19 +703,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 		break;
+ 	case AUDIT_TRIM:
+ 		audit_trim_trees();
+-		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+-		if (!ab)
+-			break;
+-		audit_log_format(ab, "auid=%u", loginuid);
+-		if (sid) {
+-			u32 len;
+-			ctx = NULL;
+-			if (selinux_sid_to_string(sid, &ctx, &len))
+-				audit_log_format(ab, " ssid=%u", sid);
+-			else
+-				audit_log_format(ab, " subj=%s", ctx);
+-			kfree(ctx);
+-		}
++
++		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
++					  uid, loginuid, sid);
++
+ 		audit_log_format(ab, " op=trim res=1");
+ 		audit_log_end(ab);
+ 		break;
+@@ -817,22 +736,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ 		/* OK, here comes... */
+ 		err = audit_tag_tree(old, new);
+ 
+-		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+-		if (!ab) {
+-			kfree(old);
+-			kfree(new);
+-			break;
+-		}
+-		audit_log_format(ab, "auid=%u", loginuid);
+-		if (sid) {
+-			u32 len;
+-			ctx = NULL;
+-			if (selinux_sid_to_string(sid, &ctx, &len))
+-				audit_log_format(ab, " ssid=%u", sid);
+-			else
+-				audit_log_format(ab, " subj=%s", ctx);
+-			kfree(ctx);
+-		}
++		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
++					  uid, loginuid, sid);
++
+ 		audit_log_format(ab, " op=make_equiv old=");
+ 		audit_log_untrustedstring(ab, old);
+ 		audit_log_format(ab, " new=");
+@@ -965,6 +871,7 @@ static int __init audit_init(void)
+ 	skb_queue_head_init(&audit_skb_queue);
+ 	audit_initialized = 1;
+ 	audit_enabled = audit_default;
++	audit_ever_enabled |= !!audit_default;
+ 
+ 	/* Register the callback with selinux.  This callback will be invoked
+ 	 * when a new policy is loaded. */
+@@ -992,8 +899,10 @@ static int __init audit_enable(char *str)
+ 	printk(KERN_INFO "audit: %s%s\n",
+ 	       audit_default ? "enabled" : "disabled",
+ 	       audit_initialized ? "" : " (after initialization)");
+-	if (audit_initialized)
++	if (audit_initialized) {
+ 		audit_enabled = audit_default;
++		audit_ever_enabled |= !!audit_default;
++	}
+ 	return 1;
+ }
+ 
+@@ -1130,7 +1039,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
+ {
+ 	struct audit_buffer	*ab	= NULL;
+ 	struct timespec		t;
+-	unsigned int		serial;
++	unsigned int		uninitialized_var(serial);
+ 	int reserve;
+ 	unsigned long timeout_start = jiffies;
+ 
+@@ -1164,7 +1073,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
+ 			remove_wait_queue(&audit_backlog_wait, &wait);
+ 			continue;
+ 		}
+-		if (audit_rate_check())
++		if (audit_rate_check() && printk_ratelimit())
+ 			printk(KERN_WARNING
+ 			       "audit: audit_backlog=%d > "
+ 			       "audit_backlog_limit=%d\n",
+@@ -1200,13 +1109,17 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
+ static inline int audit_expand(struct audit_buffer *ab, int extra)
+ {
+ 	struct sk_buff *skb = ab->skb;
+-	int ret = pskb_expand_head(skb, skb_headroom(skb), extra,
+-				   ab->gfp_mask);
++	int oldtail = skb_tailroom(skb);
++	int ret = pskb_expand_head(skb, 0, extra, ab->gfp_mask);
++	int newtail = skb_tailroom(skb);
++
+ 	if (ret < 0) {
+ 		audit_log_lost("out of memory in audit_expand");
+ 		return 0;
+ 	}
+-	return skb_tailroom(skb);
++
++	skb->truesize += newtail - oldtail;
++	return newtail;
+ }
+ 
+ /*
+@@ -1245,6 +1158,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
+ 			goto out;
+ 		len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
+ 	}
++	va_end(args2);
+ 	if (len > 0)
+ 		skb_put(skb, len);
+ out:
+@@ -1346,6 +1260,21 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
+ }
+ 
+ /**
++ * audit_string_contains_control - does a string need to be logged in hex
++ * @string - string to be checked
++ * @len - max length of the string to check
++ */
++int audit_string_contains_control(const char *string, size_t len)
++{
++	const unsigned char *p;
++	for (p = string; p < (const unsigned char *)string + len && *p; p++) {
++		if (*p == '"' || *p < 0x21 || *p > 0x7f)
++			return 1;
++	}
++	return 0;
++}
++
++/**
+  * audit_log_n_untrustedstring - log a string that may contain random characters
+  * @ab: audit_buffer
+  * @len: lenth of string (not including trailing null)
+@@ -1359,19 +1288,13 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
+  * The caller specifies the number of characters in the string to log, which may
+  * or may not be the entire string.
+  */
+-const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
+-					const char *string)
++void audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
++				 const char *string)
+ {
+-	const unsigned char *p;
+-
+-	for (p = string; p < (const unsigned char *)string + len && *p; p++) {
+-		if (*p == '"' || *p < 0x21 || *p > 0x7f) {
+-			audit_log_hex(ab, string, len);
+-			return string + len + 1;
+-		}
+-	}
+-	audit_log_n_string(ab, len, string);
+-	return p + 1;
++	if (audit_string_contains_control(string, len))
++		audit_log_hex(ab, string, len);
++	else
++		audit_log_n_string(ab, len, string);
+ }
+ 
+ /**
+@@ -1382,9 +1305,9 @@ const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
+  * Same as audit_log_n_untrustedstring(), except that strlen is used to
+  * determine string length.
+  */
+-const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
++void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+ {
+-	return audit_log_n_untrustedstring(ab, strlen(string), string);
++	audit_log_n_untrustedstring(ab, strlen(string), string);
+ }
+ 
+ /* This is a helper-function to print the escaped d_path */
+@@ -1433,8 +1356,11 @@ void audit_log_end(struct audit_buffer *ab)
+ 			skb_queue_tail(&audit_skb_queue, ab->skb);
+ 			ab->skb = NULL;
+ 			wake_up_interruptible(&kauditd_wait);
++		} else if (printk_ratelimit()) {
++			struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
++			printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, ab->skb->data + NLMSG_SPACE(0));
+ 		} else {
+-			printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));
++			audit_log_lost("printk limit exceeded\n");
+ 		}
+ 	}
+ 	audit_buffer_free(ab);
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index 5d96f2c..6f19fd4 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -95,6 +95,8 @@ extern struct inotify_handle *audit_ih;
+ /* Inotify events we care about. */
+ #define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+ 
++extern int audit_enabled;
++
+ void audit_free_parent(struct inotify_watch *i_watch)
+ {
+ 	struct audit_parent *parent;
+@@ -974,7 +976,6 @@ static void audit_update_watch(struct audit_parent *parent,
+ 	struct audit_watch *owatch, *nwatch, *nextw;
+ 	struct audit_krule *r, *nextr;
+ 	struct audit_entry *oentry, *nentry;
+-	struct audit_buffer *ab;
+ 
+ 	mutex_lock(&audit_filter_mutex);
+ 	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+@@ -1014,13 +1015,18 @@ static void audit_update_watch(struct audit_parent *parent,
+ 			call_rcu(&oentry->rcu, audit_free_rule_rcu);
+ 		}
+ 
+-		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+-		audit_log_format(ab, "op=updated rules specifying path=");
+-		audit_log_untrustedstring(ab, owatch->path);
+-		audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino);
+-		audit_log_format(ab, " list=%d res=1", r->listnr);
+-		audit_log_end(ab);
+-
++		if (audit_enabled) {
++			struct audit_buffer *ab;
++			ab = audit_log_start(NULL, GFP_KERNEL,
++				AUDIT_CONFIG_CHANGE);
++			audit_log_format(ab,
++				"op=updated rules specifying path=");
++			audit_log_untrustedstring(ab, owatch->path);
++			audit_log_format(ab, " with dev=%u ino=%lu\n",
++				 dev, ino);
++			audit_log_format(ab, " list=%d res=1", r->listnr);
++			audit_log_end(ab);
++		}
+ 		audit_remove_watch(owatch);
+ 		goto add_watch_to_parent; /* event applies to a single watch */
+ 	}
+@@ -1039,25 +1045,28 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
+ 	struct audit_watch *w, *nextw;
+ 	struct audit_krule *r, *nextr;
+ 	struct audit_entry *e;
+-	struct audit_buffer *ab;
+ 
+ 	mutex_lock(&audit_filter_mutex);
+ 	parent->flags |= AUDIT_PARENT_INVALID;
+ 	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
+ 		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+ 			e = container_of(r, struct audit_entry, rule);
+-
+-			ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+-			audit_log_format(ab, "op=remove rule path=");
+-			audit_log_untrustedstring(ab, w->path);
+-			if (r->filterkey) {
+-				audit_log_format(ab, " key=");
+-				audit_log_untrustedstring(ab, r->filterkey);
+-			} else
+-				audit_log_format(ab, " key=(null)");
+-			audit_log_format(ab, " list=%d res=1", r->listnr);
+-			audit_log_end(ab);
+-
++			if (audit_enabled) {
++				struct audit_buffer *ab;
++				ab = audit_log_start(NULL, GFP_KERNEL,
++					AUDIT_CONFIG_CHANGE);
++				audit_log_format(ab, "op=remove rule path=");
++				audit_log_untrustedstring(ab, w->path);
++				if (r->filterkey) {
++					audit_log_format(ab, " key=");
++					audit_log_untrustedstring(ab,
++							r->filterkey);
++				} else
++					audit_log_format(ab, " key=(null)");
++				audit_log_format(ab, " list=%d res=1",
++					r->listnr);
++				audit_log_end(ab);
++			}
+ 			list_del(&r->rlist);
+ 			list_del_rcu(&e->list);
+ 			call_rcu(&e->rcu, audit_free_rule_rcu);
+@@ -1495,6 +1504,9 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
+ {
+ 	struct audit_buffer *ab;
+ 
++	if (!audit_enabled)
++		return;
++
+ 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+ 	if (!ab)
+ 		return;
+diff --git a/kernel/auditsc.c b/kernel/auditsc.c
+index bce9ecd..1c06ecf 100644
+--- a/kernel/auditsc.c
++++ b/kernel/auditsc.c
+@@ -70,6 +70,7 @@
+ #include "audit.h"
+ 
+ extern struct list_head audit_filter_list[];
++extern int audit_ever_enabled;
+ 
+ /* AUDIT_NAMES is the number of slots we reserve in the audit_context
+  * for saving names from getname(). */
+@@ -78,6 +79,9 @@ extern struct list_head audit_filter_list[];
+ /* Indicates that audit should log the full pathname. */
+ #define AUDIT_NAME_FULL -1
+ 
++/* no execve audit message should be longer than this (userspace limits) */
++#define MAX_EXECVE_AUDIT_LEN 7500
++
+ /* number of audit rules */
+ int audit_n_rules;
+ 
+@@ -176,7 +180,11 @@ struct audit_aux_data_fd_pair {
+ struct audit_aux_data_pids {
+ 	struct audit_aux_data	d;
+ 	pid_t			target_pid[AUDIT_AUX_PIDS];
++	uid_t			target_auid[AUDIT_AUX_PIDS];
++	uid_t			target_uid[AUDIT_AUX_PIDS];
++	unsigned int		target_sessionid[AUDIT_AUX_PIDS];
+ 	u32			target_sid[AUDIT_AUX_PIDS];
++	char 			target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
+ 	int			pid_count;
+ };
+ 
+@@ -192,7 +200,6 @@ struct audit_context {
+ 	enum audit_state    state;
+ 	unsigned int	    serial;     /* serial number for record */
+ 	struct timespec	    ctime;      /* time of syscall entry */
+-	uid_t		    loginuid;   /* login uid (identity) */
+ 	int		    major;      /* syscall number */
+ 	unsigned long	    argv[4];    /* syscall arguments */
+ 	int		    return_valid; /* return code is valid */
+@@ -215,7 +222,11 @@ struct audit_context {
+ 	int		    arch;
+ 
+ 	pid_t		    target_pid;
++	uid_t		    target_auid;
++	uid_t		    target_uid;
++	unsigned int	    target_sessionid;
+ 	u32		    target_sid;
++	char		    target_comm[TASK_COMM_LEN];
+ 
+ 	struct audit_tree_refs *trees, *first_trees;
+ 	int tree_count;
+@@ -506,7 +517,7 @@ static int audit_filter_rules(struct task_struct *tsk,
+ 		case AUDIT_LOGINUID:
+ 			result = 0;
+ 			if (ctx)
+-				result = audit_comparator(ctx->loginuid, f->op, f->val);
++				result = audit_comparator(tsk->loginuid, f->op, f->val);
+ 			break;
+ 		case AUDIT_SUBJ_USER:
+ 		case AUDIT_SUBJ_ROLE:
+@@ -702,7 +713,24 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
+ 	if (likely(!context))
+ 		return NULL;
+ 	context->return_valid = return_valid;
+-	context->return_code  = return_code;
++
++	/*
++	 * we need to fix up the return code in the audit logs if the actual
++	 * return codes are later going to be fixed up by the arch specific
++	 * signal handlers
++	 *
++	 * This is actually a test for:
++	 * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
++	 * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
++	 *
++	 * but is faster than a bunch of ||
++	 */
++	if (unlikely(return_code <= -ERESTARTSYS) &&
++	    (return_code >= -ERESTART_RESTARTBLOCK) &&
++	    (return_code != -ENOIOCTLCMD))
++		context->return_code = -EINTR;
++	else
++		context->return_code  = return_code;
+ 
+ 	if (context->in_syscall && !context->dummy && !context->auditable) {
+ 		enum audit_state state;
+@@ -783,11 +811,8 @@ static inline void audit_free_aux(struct audit_context *context)
+ static inline void audit_zero_context(struct audit_context *context,
+ 				      enum audit_state state)
+ {
+-	uid_t loginuid = context->loginuid;
+-
+ 	memset(context, 0, sizeof(*context));
+ 	context->state      = state;
+-	context->loginuid   = loginuid;
+ }
+ 
+ static inline struct audit_context *audit_alloc_context(enum audit_state state)
+@@ -814,7 +839,7 @@ int audit_alloc(struct task_struct *tsk)
+ 	struct audit_context *context;
+ 	enum audit_state     state;
+ 
+-	if (likely(!audit_enabled))
++	if (likely(!audit_ever_enabled))
+ 		return 0; /* Return if not auditing. */
+ 
+ 	state = audit_filter_task(tsk);
+@@ -826,11 +851,6 @@ int audit_alloc(struct task_struct *tsk)
+ 		return -ENOMEM;
+ 	}
+ 
+-				/* Preserve login uid */
+-	context->loginuid = -1;
+-	if (current->audit_context)
+-		context->loginuid = current->audit_context->loginuid;
+-
+ 	tsk->audit_context  = context;
+ 	set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+ 	return 0;
+@@ -922,7 +942,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
+ }
+ 
+ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
+-				 u32 sid)
++				 uid_t auid, uid_t uid, unsigned int sessionid,
++				 u32 sid, char *comm)
+ {
+ 	struct audit_buffer *ab;
+ 	char *s = NULL;
+@@ -931,68 +952,204 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
+ 
+ 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
+ 	if (!ab)
+-		return 1;
++		return rc;
+ 
++	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
++			 uid, sessionid);
+ 	if (selinux_sid_to_string(sid, &s, &len)) {
+-		audit_log_format(ab, "opid=%d obj=(none)", pid);
++		audit_log_format(ab, " obj=(none)");
+ 		rc = 1;
+ 	} else
+-		audit_log_format(ab, "opid=%d  obj=%s", pid, s);
++		audit_log_format(ab, " obj=%s", s);
++	audit_log_format(ab, " ocomm=");
++	audit_log_untrustedstring(ab, comm);
+ 	audit_log_end(ab);
+ 	kfree(s);
+ 
+ 	return rc;
+ }
+ 
+-static void audit_log_execve_info(struct audit_buffer *ab,
+-		struct audit_aux_data_execve *axi)
++/*
++ * to_send and len_sent accounting are very loose estimates.  We aren't
++ * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
++ * within about 500 bytes (next page boundry)
++ *
++ * why snprintf?  an int is up to 12 digits long.  if we just assumed when
++ * logging that a[%d]= was going to be 16 characters long we would be wasting
++ * space in every audit message.  In one 7500 byte message we can log up to
++ * about 1000 min size arguments.  That comes down to about 50% waste of space
++ * if we didn't do the snprintf to find out how long arg_num_len was.
++ */
++static int audit_log_single_execve_arg(struct audit_context *context,
++					struct audit_buffer **ab,
++					int arg_num,
++					size_t *len_sent,
++					const char __user *p,
++					char *buf)
+ {
+-	int i;
+-	long len, ret;
+-	const char __user *p;
+-	char *buf;
++	char arg_num_len_buf[12];
++	const char __user *tmp_p = p;
++	/* how many digits are in arg_num? 3 is the length of a=\n */
++	size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3;
++	size_t len, len_left, to_send;
++	size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
++	unsigned int i, has_cntl = 0, too_long = 0;
++	int ret;
++
++	/* strnlen_user includes the null we don't want to send */
++	len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+ 
+-	if (axi->mm != current->mm)
+-		return; /* execve failed, no additional info */
+-
+-	p = (const char __user *)axi->mm->arg_start;
++	/*
++	 * We just created this mm, if we can't find the strings
++	 * we just copied into it something is _very_ wrong. Similar
++	 * for strings that are too long, we should not have created
++	 * any.
++	 */
++	if (unlikely((len  = -1) || len > MAX_ARG_STRLEN - 1)) {
++		WARN_ON(1);
++		send_sig(SIGKILL, current, 0);
++	}
+ 
+-	for (i = 0; i < axi->argc; i++, p += len) {
+-		len = strnlen_user(p, MAX_ARG_STRLEN);
++	/* walk the whole argument looking for non-ascii chars */
++	do {
++		if (len_left > MAX_EXECVE_AUDIT_LEN)
++			to_send = MAX_EXECVE_AUDIT_LEN;
++		else
++			to_send = len_left;
++		ret = copy_from_user(buf, tmp_p, to_send);
+ 		/*
+-		 * We just created this mm, if we can't find the strings
+-		 * we just copied into it something is _very_ wrong. Similar
+-		 * for strings that are too long, we should not have created
+-		 * any.
++		 * There is no reason for this copy to be short. We just
++		 * copied them here, and the mm hasn't been exposed to user-
++		 * space yet.
+ 		 */
+-		if (!len || len > MAX_ARG_STRLEN) {
++		if (ret) {
+ 			WARN_ON(1);
+ 			send_sig(SIGKILL, current, 0);
+ 		}
+-
+-		buf = kmalloc(len, GFP_KERNEL);
+-		if (!buf) {
+-			audit_panic("out of memory for argv string\n");
++		buf[to_send] = '\0';
++		has_cntl = audit_string_contains_control(buf, to_send);
++		if (has_cntl) {
++			/*
++			 * hex messages get logged as 2 bytes, so we can only
++			 * send half as much in each message
++			 */
++			max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
+ 			break;
+ 		}
++		len_left -= to_send;
++		tmp_p += to_send;
++	} while (len_left > 0);
++
++	len_left = len;
++
++	if (len > max_execve_audit_len)
++		too_long = 1;
++
++	/* rewalk the argument actually logging the message */
++	for (i = 0; len_left > 0; i++) {
++		int room_left;
++
++		if (len_left > max_execve_audit_len)
++			to_send = max_execve_audit_len;
++		else
++			to_send = len_left;
++
++		/* do we have space left to send this argument in this ab? */
++		room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
++		if (has_cntl)
++			room_left -= (to_send * 2);
++		else
++			room_left -= to_send;
++		if (room_left < 0) {
++			*len_sent = 0;
++			audit_log_end(*ab);
++			*ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
++			if (!*ab)
++				return 0;
++		}
+ 
+-		ret = copy_from_user(buf, p, len);
+ 		/*
+-		 * There is no reason for this copy to be short. We just
+-		 * copied them here, and the mm hasn't been exposed to user-
+-		 * space yet.
++		 * first record needs to say how long the original string was
++		 * so we can be sure nothing was lost.
++		 */
++		if ((i == 0) && (too_long))
++			audit_log_format(*ab, "a%d_len=%ld ", arg_num,
++					 has_cntl ? 2*len : len);
++
++		/*
++		 * normally arguments are small enough to fit and we already
++		 * filled buf above when we checked for control characters
++		 * so don't bother with another copy_from_user
+ 		 */
++		if (len >= max_execve_audit_len)
++			ret = copy_from_user(buf, p, to_send);
++		else
++			ret = 0;
+ 		if (ret) {
+ 			WARN_ON(1);
+ 			send_sig(SIGKILL, current, 0);
+ 		}
++		buf[to_send] = '\0';
++
++		/* actually log it */
++		audit_log_format(*ab, "a%d", arg_num);
++		if (too_long)
++			audit_log_format(*ab, "[%d]", i);
++		audit_log_format(*ab, "=");
++		if (has_cntl)
++			audit_log_hex(*ab, buf, to_send);
++		else
++			audit_log_format(*ab, "\"%s\"", buf);
++		audit_log_format(*ab, "\n");
++
++		p += to_send;
++		len_left -= to_send;
++		*len_sent += arg_num_len;
++		if (has_cntl)
++			*len_sent += to_send * 2;
++		else
++			*len_sent += to_send;
++	}
++	/* include the null we didn't log */
++	return len + 1;
++}
+ 
+-		audit_log_format(ab, "a%d=", i);
+-		audit_log_untrustedstring(ab, buf);
+-		audit_log_format(ab, "\n");
++static void audit_log_execve_info(struct audit_context *context,
++				  struct audit_buffer **ab,
++				  struct audit_aux_data_execve *axi)
++{
++	int i;
++	size_t len, len_sent = 0;
++	const char __user *p;
++	char *buf;
++
++	if (axi->mm != current->mm)
++		return; /* execve failed, no additional info */
++
++	p = (const char __user *)axi->mm->arg_start;
++
++	audit_log_format(*ab, "argc=%d ", axi->argc);
++
++	/*
++	 * we need some kernel buffer to hold the userspace args.  Just
++	 * allocate one big one rather than allocating one of the right size
++	 * for every single argument inside audit_log_single_execve_arg()
++	 * should be <8k allocation so should be pretty safe.
++	 */
++	buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
++	if (!buf) {
++		audit_panic("out of memory for argv string\n");
++		return;
++	}
+ 
+-		kfree(buf);
++	for (i = 0; i < axi->argc; i++) {
++		len = audit_log_single_execve_arg(context, ab, i,
++						  &len_sent, p, buf);
++		if (len <= 0)
++			break;
++		p += len;
+ 	}
++	kfree(buf);
+ }
+ 
+ static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
+@@ -1039,7 +1196,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
+ 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
+ 		  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
+ 		  " euid=%u suid=%u fsuid=%u"
+-		  " egid=%u sgid=%u fsgid=%u tty=%s",
++		  " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
+ 		  context->argv[0],
+ 		  context->argv[1],
+ 		  context->argv[2],
+@@ -1047,11 +1204,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
+ 		  context->name_count,
+ 		  context->ppid,
+ 		  context->pid,
+-		  context->loginuid,
++		  tsk->loginuid,
+ 		  context->uid,
+ 		  context->gid,
+ 		  context->euid, context->suid, context->fsuid,
+-		  context->egid, context->sgid, context->fsgid, tty);
++		  context->egid, context->sgid, context->fsgid, tty,
++		  tsk->sessionid);
+ 
+ 	mutex_unlock(&tty_mutex);
+ 
+@@ -1135,7 +1293,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
+ 
+ 		case AUDIT_EXECVE: {
+ 			struct audit_aux_data_execve *axi = (void *)aux;
+-			audit_log_execve_info(ab, axi);
++			audit_log_execve_info(context, &ab, axi);
+ 			break; }
+ 
+ 		case AUDIT_SOCKETCALL: {
+@@ -1168,13 +1326,19 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
+ 
+ 		for (i = 0; i < axs->pid_count; i++)
+ 			if (audit_log_pid_context(context, axs->target_pid[i],
+-						  axs->target_sid[i]))
++						  axs->target_auid[i],
++						  axs->target_uid[i],
++						  axs->target_sessionid[i],
++						  axs->target_sid[i],
++						  axs->target_comm[i]))
+ 				call_panic = 1;
+ 	}
+ 
+ 	if (context->target_pid &&
+ 	    audit_log_pid_context(context, context->target_pid,
+-				  context->target_sid))
++				  context->target_auid, context->target_uid,
++				  context->target_sessionid,
++				  context->target_sid, context->target_comm))
+ 			call_panic = 1;
+ 
+ 	if (context->pwd && context->pwdmnt) {
+@@ -1242,6 +1406,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
+ 
+ 		audit_log_end(ab);
+ 	}
++
++	/* Send end of event record to help user space know we are finished */
++	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
++	if (ab)
++		audit_log_end(ab);
+ 	if (call_panic)
+ 		audit_panic("error converting sid to string");
+ }
+@@ -1766,6 +1935,9 @@ void auditsc_get_stamp(struct audit_context *ctx,
+ 	ctx->auditable = 1;
+ }
+ 
++/* global counter which is incremented every time something logs in */
++static atomic_t session_id = ATOMIC_INIT(0);
++
+ /**
+  * audit_set_loginuid - set a task's audit_context loginuid
+  * @task: task whose audit context is being modified
+@@ -1777,41 +1949,29 @@ void auditsc_get_stamp(struct audit_context *ctx,
+  */
+ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
+ {
++	unsigned int sessionid = atomic_inc_return(&session_id);
+ 	struct audit_context *context = task->audit_context;
+ 
+-	if (context) {
+-		/* Only log if audit is enabled */
+-		if (context->in_syscall) {
+-			struct audit_buffer *ab;
+-
+-			ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+-			if (ab) {
+-				audit_log_format(ab, "login pid=%d uid=%u "
+-					"old auid=%u new auid=%u",
+-					task->pid, task->uid,
+-					context->loginuid, loginuid);
+-				audit_log_end(ab);
+-			}
++	if (context && context->in_syscall) {
++		struct audit_buffer *ab;
++
++		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
++		if (ab) {
++			audit_log_format(ab, "login pid=%d uid=%u "
++				"old auid=%u new auid=%u"
++				" old ses=%u new ses=%u",
++				task->pid, task->uid,
++				task->loginuid, loginuid,
++				task->sessionid, sessionid);
++			audit_log_end(ab);
+ 		}
+-		context->loginuid = loginuid;
+ 	}
++	task->sessionid = sessionid;
++	task->loginuid = loginuid;
+ 	return 0;
+ }
+ 
+ /**
+- * audit_get_loginuid - get the loginuid for an audit_context
+- * @ctx: the audit_context
+- *
+- * Returns the context's loginuid or -1 if @ctx is NULL.
+- */
+-uid_t audit_get_loginuid(struct audit_context *ctx)
+-{
+-	return ctx ? ctx->loginuid : -1;
+-}
+-
+-EXPORT_SYMBOL(audit_get_loginuid);
+-
+-/**
+  * __audit_mq_open - record audit data for a POSIX MQ open
+  * @oflag: open flag
+  * @mode: mode bits
+@@ -2070,8 +2230,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
+ 	return 0;
+ }
+ 
+-int audit_argv_kb = 32;
+-
+ int audit_bprm(struct linux_binprm *bprm)
+ {
+ 	struct audit_aux_data_execve *ax;
+@@ -2080,14 +2238,6 @@ int audit_bprm(struct linux_binprm *bprm)
+ 	if (likely(!audit_enabled || !context || context->dummy))
+ 		return 0;
+ 
+-	/*
+-	 * Even though the stack code doesn't limit the arg+env size any more,
+-	 * the audit code requires that _all_ arguments be logged in a single
+-	 * netlink skb. Hence cap it :-(
+-	 */
+-	if (bprm->argv_len > (audit_argv_kb << 10))
+-		return -E2BIG;
+-
+ 	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ 	if (!ax)
+ 		return -ENOMEM;
+@@ -2193,7 +2343,11 @@ void __audit_ptrace(struct task_struct *t)
+ 	struct audit_context *context = current->audit_context;
+ 
+ 	context->target_pid = t->pid;
++	context->target_auid = audit_get_loginuid(t);
++	context->target_uid = t->uid;
++	context->target_sessionid = audit_get_sessionid(t);
+ 	selinux_get_task_sid(t, &context->target_sid);
++	memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
+ }
+ 
+ /**
+@@ -2216,8 +2370,8 @@ int __audit_signal_info(int sig, struct task_struct *t)
+ 	if (audit_pid && t->tgid == audit_pid) {
+ 		if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
+ 			audit_sig_pid = tsk->pid;
+-			if (ctx)
+-				audit_sig_uid = ctx->loginuid;
++			if (tsk->loginuid != -1)
++				audit_sig_uid = tsk->loginuid;
+ 			else
+ 				audit_sig_uid = tsk->uid;
+ 			selinux_get_task_sid(tsk, &audit_sig_sid);
+@@ -2230,7 +2384,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
+ 	 * in audit_context */
+ 	if (!ctx->target_pid) {
+ 		ctx->target_pid = t->tgid;
++		ctx->target_auid = audit_get_loginuid(t);
++		ctx->target_uid = t->uid;
++		ctx->target_sessionid = audit_get_sessionid(t);
+ 		selinux_get_task_sid(t, &ctx->target_sid);
++		memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
+ 		return 0;
+ 	}
+ 
+@@ -2247,7 +2405,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
+ 	BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS);
+ 
+ 	axp->target_pid[axp->pid_count] = t->tgid;
++	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
++	axp->target_uid[axp->pid_count] = t->uid;
++	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
+ 	selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
++	memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
+ 	axp->pid_count++;
+ 
+ 	return 0;
+@@ -2264,6 +2426,8 @@ void audit_core_dumps(long signr)
+ {
+ 	struct audit_buffer *ab;
+ 	u32 sid;
++	uid_t auid = audit_get_loginuid(current);
++	unsigned int sessionid = audit_get_sessionid(current);
+ 
+ 	if (!audit_enabled)
+ 		return;
+@@ -2272,9 +2436,8 @@ void audit_core_dumps(long signr)
+ 		return;
+ 
+ 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+-	audit_log_format(ab, "auid=%u uid=%u gid=%u",
+-			audit_get_loginuid(current->audit_context),
+-			current->uid, current->gid);
++	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
++			auid, current->uid, current->gid, sessionid);
+ 	selinux_get_task_sid(current, &sid);
+ 	if (sid) {
+ 		char *ctx = NULL;
 diff --git a/kernel/backtracetest.c b/kernel/backtracetest.c
 new file mode 100644
 index 0000000..d1a7605
@@ -826686,8 +881128,162 @@
  bad_fork_cleanup_namespaces:
  	exit_task_namespaces(p);
  bad_fork_cleanup_keys:
+diff --git a/kernel/futex.c b/kernel/futex.c
+index db9824d..a6baaec 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -109,6 +109,9 @@ struct futex_q {
+ 	/* Optional priority inheritance state: */
+ 	struct futex_pi_state *pi_state;
+ 	struct task_struct *task;
++
++	/* Bitset for the optional bitmasked wakeup */
++	u32 bitset;
+ };
+ 
+ /*
+@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
+  * to this virtual address:
+  */
+ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+-		      int nr_wake)
++		      int nr_wake, u32 bitset)
+ {
+ 	struct futex_hash_bucket *hb;
+ 	struct futex_q *this, *next;
+@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 	union futex_key key;
+ 	int ret;
+ 
++	if (!bitset)
++		return -EINVAL;
++
+ 	futex_lock_mm(fshared);
+ 
+ 	ret = get_futex_key(uaddr, fshared, &key);
+@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 				ret = -EINVAL;
+ 				break;
+ 			}
++
++			/* Check if one of the bits is set in both bitsets */
++			if (!(this->bitset & bitset))
++				continue;
++
+ 			wake_futex(this);
+ 			if (++ret >= nr_wake)
+ 				break;
+@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
+ static long futex_wait_restart(struct restart_block *restart);
+ 
+ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+-		      u32 val, ktime_t *abs_time)
++		      u32 val, ktime_t *abs_time, u32 bitset)
+ {
+ 	struct task_struct *curr = current;
+ 	DECLARE_WAITQUEUE(wait, curr);
+@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 	struct hrtimer_sleeper t;
+ 	int rem = 0;
+ 
++	if (!bitset)
++		return -EINVAL;
++
+ 	q.pi_state = NULL;
++	q.bitset = bitset;
+  retry:
+ 	futex_lock_mm(fshared);
+ 
+@@ -1252,6 +1267,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 			t.timer.expires = *abs_time;
+ 
+ 			hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
++			if (!hrtimer_active(&t.timer))
++				t.task = NULL;
+ 
+ 			/*
+ 			 * the timer could have already expired, in which
+@@ -1293,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 		restart->futex.uaddr = (u32 *)uaddr;
+ 		restart->futex.val = val;
+ 		restart->futex.time = abs_time->tv64;
++		restart->futex.bitset = bitset;
+ 		restart->futex.flags = 0;
+ 
+ 		if (fshared)
+@@ -1319,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
+ 	restart->fn = do_no_restart_syscall;
+ 	if (restart->futex.flags & FLAGS_SHARED)
+ 		fshared = &current->mm->mmap_sem;
+-	return (long)futex_wait(uaddr, fshared, restart->futex.val, &t);
++	return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
++				restart->futex.bitset);
+ }
+ 
+ 
+@@ -1535,9 +1554,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
+ 				owner = rt_mutex_owner(&q.pi_state->pi_mutex);
+ 				res = fixup_pi_state_owner(uaddr, &q, owner);
+ 
+-				WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
+-					owner);
+-
+ 				/* propagate -EFAULT, if the fixup failed */
+ 				if (res)
+ 					ret = res;
+@@ -1943,7 +1959,8 @@ retry:
+ 		 * PI futexes happens in exit_pi_state():
+ 		 */
+ 		if (!pi && (uval & FUTEX_WAITERS))
+-				futex_wake(uaddr, &curr->mm->mmap_sem, 1);
++			futex_wake(uaddr, &curr->mm->mmap_sem, 1,
++				   FUTEX_BITSET_MATCH_ANY);
+ 	}
+ 	return 0;
+ }
+@@ -2043,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
+ 
+ 	switch (cmd) {
+ 	case FUTEX_WAIT:
+-		ret = futex_wait(uaddr, fshared, val, timeout);
++		val3 = FUTEX_BITSET_MATCH_ANY;
++	case FUTEX_WAIT_BITSET:
++		ret = futex_wait(uaddr, fshared, val, timeout, val3);
+ 		break;
+ 	case FUTEX_WAKE:
+-		ret = futex_wake(uaddr, fshared, val);
++		val3 = FUTEX_BITSET_MATCH_ANY;
++	case FUTEX_WAKE_BITSET:
++		ret = futex_wake(uaddr, fshared, val, val3);
+ 		break;
+ 	case FUTEX_FD:
+ 		/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
+@@ -2086,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
+ 	u32 val2 = 0;
+ 	int cmd = op & FUTEX_CMD_MASK;
+ 
+-	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
++	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
++		      cmd == FUTEX_WAIT_BITSET)) {
+ 		if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
+ 			return -EFAULT;
+ 		if (!timespec_valid(&ts))
+diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
+index 0a43def..133d558 100644
+--- a/kernel/futex_compat.c
++++ b/kernel/futex_compat.c
+@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
+ 	int val2 = 0;
+ 	int cmd = op & FUTEX_CMD_MASK;
+ 
+-	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
++	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
++		      cmd == FUTEX_WAIT_BITSET)) {
+ 		if (get_compat_timespec(&ts, utime))
+ 			return -EFAULT;
+ 		if (!timespec_valid(&ts))
 diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
-index f994bb8..bd5d6b5 100644
+index f994bb8..1069998 100644
 --- a/kernel/hrtimer.c
 +++ b/kernel/hrtimer.c
 @@ -325,6 +325,22 @@ unsigned long ktime_divns(const ktime_t kt, s64 div)
@@ -827057,7 +881653,16 @@
  
  		if (likely(t->task))
  			schedule();
-@@ -1389,6 +1416,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
+@@ -1288,6 +1315,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
+ 
+ 	} while (t->task && !signal_pending(current));
+ 
++	__set_current_state(TASK_RUNNING);
++
+ 	return t->task == NULL;
+ }
+ 
+@@ -1389,6 +1418,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
  	for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
  		cpu_base->clock_base[i].cpu_base = cpu_base;
  
@@ -828479,83 +883084,838 @@
 +			}
 +			__group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
 +		}
-+	}
- }
++	}
+ }
+ 
+ /*
+diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
+index 8e186c6..ef9b802 100644
+--- a/kernel/power/Kconfig
++++ b/kernel/power/Kconfig
+@@ -44,9 +44,30 @@ config PM_VERBOSE
+ 	---help---
+ 	This option enables verbose messages from the Power Management code.
+ 
++config CAN_PM_TRACE
++	def_bool y
++	depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL
++
+ config PM_TRACE
++	bool
++	help
++	  This enables code to save the last PM event point across
++	  reboot. The architecture needs to support this, x86 for
++	  example does by saving things in the RTC, see below.
++
++	  The architecture specific code must provide the extern
++	  functions from <linux/resume-trace.h> as well as the
++	  <asm/resume-trace.h> header with a TRACE_RESUME() macro.
++
++	  The way the information is presented is architecture-
++	  dependent, x86 will print the information during a
++	  late_initcall.
++
++config PM_TRACE_RTC
+ 	bool "Suspend/resume event tracing"
+-	depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL
++	depends on CAN_PM_TRACE
++	depends on X86
++	select PM_TRACE
+ 	default n
+ 	---help---
+ 	This enables some cheesy code to save the last PM event point in the
+@@ -63,7 +84,8 @@ config PM_TRACE
+ 
+ config PM_SLEEP_SMP
+ 	bool
+-	depends on SUSPEND_SMP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
++	depends on SMP
++	depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
+ 	depends on PM_SLEEP
+ 	select HOTPLUG_CPU
+ 	default y
+@@ -73,46 +95,29 @@ config PM_SLEEP
+ 	depends on SUSPEND || HIBERNATION
+ 	default y
+ 
+-config SUSPEND_UP_POSSIBLE
+-	bool
+-	depends on (X86 && !X86_VOYAGER) || PPC || ARM || BLACKFIN || MIPS \
+-		   || SUPERH || FRV
+-	depends on !SMP
+-	default y
+-
+-config SUSPEND_SMP_POSSIBLE
+-	bool
+-	depends on (X86 && !X86_VOYAGER) \
+-		   || (PPC && (PPC_PSERIES || PPC_PMAC)) || ARM
+-	depends on SMP
+-	default y
+-
+ config SUSPEND
+ 	bool "Suspend to RAM and standby"
+-	depends on PM
+-	depends on SUSPEND_UP_POSSIBLE || SUSPEND_SMP_POSSIBLE
++	depends on PM && ARCH_SUSPEND_POSSIBLE
+ 	default y
+ 	---help---
+ 	  Allow the system to enter sleep states in which main memory is
+ 	  powered and thus its contents are preserved, such as the
+-	  suspend-to-RAM state (i.e. the ACPI S3 state).
++	  suspend-to-RAM state (e.g. the ACPI S3 state).
+ 
+-config HIBERNATION_UP_POSSIBLE
+-	bool
+-	depends on X86 || PPC64_SWSUSP || PPC32
+-	depends on !SMP
++config SUSPEND_FREEZER
++	bool "Enable freezer for suspend to RAM/standby" \
++		if ARCH_WANTS_FREEZER_CONTROL || BROKEN
++	depends on SUSPEND
+ 	default y
++	help
++	  This allows you to turn off the freezer for suspend. If this is
++	  done, no tasks are frozen for suspend to RAM/standby.
+ 
+-config HIBERNATION_SMP_POSSIBLE
+-	bool
+-	depends on (X86 && !X86_VOYAGER) || PPC64_SWSUSP
+-	depends on SMP
+-	default y
++	  Turning OFF this setting is NOT recommended! If in doubt, say Y.
+ 
+ config HIBERNATION
+ 	bool "Hibernation (aka 'suspend to disk')"
+-	depends on PM && SWAP
+-	depends on HIBERNATION_UP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
++	depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
+ 	---help---
+ 	  Enable the suspend to disk (STD) functionality, which is usually
+ 	  called "hibernation" in user interfaces.  STD checkpoints the
+diff --git a/kernel/power/disk.c b/kernel/power/disk.c
+index 05b6479..d09da08 100644
+--- a/kernel/power/disk.c
++++ b/kernel/power/disk.c
+@@ -54,8 +54,8 @@ static struct platform_hibernation_ops *hibernation_ops;
+ 
+ void hibernation_set_ops(struct platform_hibernation_ops *ops)
+ {
+-	if (ops && !(ops->start && ops->pre_snapshot && ops->finish
+-	    && ops->prepare && ops->enter && ops->pre_restore
++	if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
++	    && ops->prepare && ops->finish && ops->enter && ops->pre_restore
+ 	    && ops->restore_cleanup)) {
+ 		WARN_ON(1);
+ 		return;
+@@ -70,15 +70,55 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
+ 	mutex_unlock(&pm_mutex);
+ }
+ 
++#ifdef CONFIG_PM_DEBUG
++static void hibernation_debug_sleep(void)
++{
++	printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
++	mdelay(5000);
++}
++
++static int hibernation_testmode(int mode)
++{
++	if (hibernation_mode == mode) {
++		hibernation_debug_sleep();
++		return 1;
++	}
++	return 0;
++}
++
++static int hibernation_test(int level)
++{
++	if (pm_test_level == level) {
++		hibernation_debug_sleep();
++		return 1;
++	}
++	return 0;
++}
++#else /* !CONFIG_PM_DEBUG */
++static int hibernation_testmode(int mode) { return 0; }
++static int hibernation_test(int level) { return 0; }
++#endif /* !CONFIG_PM_DEBUG */
++
+ /**
+- *	platform_start - tell the platform driver that we're starting
++ *	platform_begin - tell the platform driver that we're starting
+  *	hibernation
+  */
+ 
+-static int platform_start(int platform_mode)
++static int platform_begin(int platform_mode)
+ {
+ 	return (platform_mode && hibernation_ops) ?
+-		hibernation_ops->start() : 0;
++		hibernation_ops->begin() : 0;
++}
++
++/**
++ *	platform_end - tell the platform driver that we've entered the
++ *	working state
++ */
++
++static void platform_end(int platform_mode)
++{
++	if (platform_mode && hibernation_ops)
++		hibernation_ops->end();
+ }
+ 
+ /**
+@@ -162,19 +202,25 @@ int create_image(int platform_mode)
+ 	 */
+ 	error = device_power_down(PMSG_FREEZE);
+ 	if (error) {
+-		printk(KERN_ERR "Some devices failed to power down, "
+-			KERN_ERR "aborting suspend\n");
++		printk(KERN_ERR "PM: Some devices failed to power down, "
++			"aborting hibernation\n");
+ 		goto Enable_irqs;
+ 	}
+ 
++	if (hibernation_test(TEST_CORE))
++		goto Power_up;
++
++	in_suspend = 1;
+ 	save_processor_state();
+ 	error = swsusp_arch_suspend();
+ 	if (error)
+-		printk(KERN_ERR "Error %d while creating the image\n", error);
++		printk(KERN_ERR "PM: Error %d creating hibernation image\n",
++			error);
+ 	/* Restore control flow magically appears here */
+ 	restore_processor_state();
+ 	if (!in_suspend)
+ 		platform_leave(platform_mode);
++ Power_up:
+ 	/* NOTE:  device_power_up() is just a resume() for devices
+ 	 * that suspended with irqs off ... no overall powerup.
+ 	 */
+@@ -202,36 +248,90 @@ int hibernation_snapshot(int platform_mode)
+ 	if (error)
+ 		return error;
+ 
+-	error = platform_start(platform_mode);
++	error = platform_begin(platform_mode);
+ 	if (error)
+-		return error;
++		goto Close;
+ 
+ 	suspend_console();
+ 	error = device_suspend(PMSG_FREEZE);
+ 	if (error)
+ 		goto Resume_console;
+ 
+-	error = platform_pre_snapshot(platform_mode);
+-	if (error)
++	if (hibernation_test(TEST_DEVICES))
+ 		goto Resume_devices;
+ 
++	error = platform_pre_snapshot(platform_mode);
++	if (error || hibernation_test(TEST_PLATFORM))
++		goto Finish;
++
+ 	error = disable_nonboot_cpus();
+ 	if (!error) {
+-		if (hibernation_mode != HIBERNATION_TEST) {
+-			in_suspend = 1;
+-			error = create_image(platform_mode);
+-			/* Control returns here after successful restore */
+-		} else {
+-			printk("swsusp debug: Waiting for 5 seconds.\n");
+-			mdelay(5000);
+-		}
++		if (hibernation_test(TEST_CPUS))
++			goto Enable_cpus;
++
++		if (hibernation_testmode(HIBERNATION_TEST))
++			goto Enable_cpus;
++
++		error = create_image(platform_mode);
++		/* Control returns here after successful restore */
+ 	}
++ Enable_cpus:
+ 	enable_nonboot_cpus();
+- Resume_devices:
++ Finish:
+ 	platform_finish(platform_mode);
++ Resume_devices:
+ 	device_resume();
+  Resume_console:
+ 	resume_console();
++ Close:
++	platform_end(platform_mode);
++	return error;
++}
++
++/**
++ *	resume_target_kernel - prepare devices that need to be suspended with
++ *	interrupts off, restore the contents of highmem that have not been
++ *	restored yet from the image and run the low level code that will restore
++ *	the remaining contents of memory and switch to the just restored target
++ *	kernel.
++ */
++
++static int resume_target_kernel(void)
++{
++	int error;
++
++	local_irq_disable();
++	error = device_power_down(PMSG_PRETHAW);
++	if (error) {
++		printk(KERN_ERR "PM: Some devices failed to power down, "
++			"aborting resume\n");
++		goto Enable_irqs;
++	}
++	/* We'll ignore saved state, but this gets preempt count (etc) right */
++	save_processor_state();
++	error = restore_highmem();
++	if (!error) {
++		error = swsusp_arch_resume();
++		/*
++		 * The code below is only ever reached in case of a failure.
++		 * Otherwise execution continues at place where
++		 * swsusp_arch_suspend() was called
++		 */
++		BUG_ON(!error);
++		/* This call to restore_highmem() undos the previous one */
++		restore_highmem();
++	}
++	/*
++	 * The only reason why swsusp_arch_resume() can fail is memory being
++	 * very tight, so we have to free it as soon as we can to avoid
++	 * subsequent failures
++	 */
++	swsusp_free();
++	restore_processor_state();
++	touch_softlockup_watchdog();
++	device_power_up();
++ Enable_irqs:
++	local_irq_enable();
+ 	return error;
+ }
+ 
+@@ -258,7 +358,7 @@ int hibernation_restore(int platform_mode)
+ 	if (!error) {
+ 		error = disable_nonboot_cpus();
+ 		if (!error)
+-			error = swsusp_resume();
++			error = resume_target_kernel();
+ 		enable_nonboot_cpus();
+ 	}
+ 	platform_restore_cleanup(platform_mode);
+@@ -286,9 +386,9 @@ int hibernation_platform_enter(void)
+ 	 * hibernation_ops->finish() before saving the image, so we should let
+ 	 * the firmware know that we're going to enter the sleep state after all
+ 	 */
+-	error = hibernation_ops->start();
++	error = hibernation_ops->begin();
+ 	if (error)
+-		return error;
++		goto Close;
+ 
+ 	suspend_console();
+ 	error = device_suspend(PMSG_SUSPEND);
+@@ -322,6 +422,8 @@ int hibernation_platform_enter(void)
+ 	device_resume();
+  Resume_console:
+ 	resume_console();
++ Close:
++	hibernation_ops->end();
+ 	return error;
+ }
+ 
+@@ -352,24 +454,17 @@ static void power_down(void)
+ 	 * Valid image is on the disk, if we continue we risk serious data
+ 	 * corruption after resume.
+ 	 */
+-	printk(KERN_CRIT "Please power me down manually\n");
++	printk(KERN_CRIT "PM: Please power down manually\n");
+ 	while(1);
+ }
+ 
+-static void unprepare_processes(void)
+-{
+-	thaw_processes();
+-	pm_restore_console();
+-}
+-
+ static int prepare_processes(void)
+ {
+ 	int error = 0;
+ 
+-	pm_prepare_console();
+ 	if (freeze_processes()) {
+ 		error = -EBUSY;
+-		unprepare_processes();
++		thaw_processes();
+ 	}
+ 	return error;
+ }
+@@ -389,6 +484,7 @@ int hibernate(void)
+ 		goto Unlock;
+ 	}
+ 
++	pm_prepare_console();
+ 	error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+ 	if (error)
+ 		goto Exit;
+@@ -398,7 +494,7 @@ int hibernate(void)
+ 	if (error)
+ 		goto Exit;
+ 
+-	printk("Syncing filesystems ... ");
++	printk(KERN_INFO "PM: Syncing filesystems ... ");
+ 	sys_sync();
+ 	printk("done.\n");
+ 
+@@ -406,11 +502,12 @@ int hibernate(void)
+ 	if (error)
+ 		goto Finish;
+ 
+-	if (hibernation_mode == HIBERNATION_TESTPROC) {
+-		printk("swsusp debug: Waiting for 5 seconds.\n");
+-		mdelay(5000);
++	if (hibernation_test(TEST_FREEZER))
+ 		goto Thaw;
+-	}
++
++	if (hibernation_testmode(HIBERNATION_TESTPROC))
++		goto Thaw;
++
+ 	error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+ 	if (in_suspend && !error) {
+ 		unsigned int flags = 0;
+@@ -427,11 +524,12 @@ int hibernate(void)
+ 		swsusp_free();
+ 	}
+  Thaw:
+-	unprepare_processes();
++	thaw_processes();
+  Finish:
+ 	free_basic_memory_bitmaps();
+  Exit:
+ 	pm_notifier_call_chain(PM_POST_HIBERNATION);
++	pm_restore_console();
+ 	atomic_inc(&snapshot_device_available);
+  Unlock:
+ 	mutex_unlock(&pm_mutex);
+@@ -473,22 +571,23 @@ static int software_resume(void)
+ 			return -ENOENT;
+ 		}
+ 		swsusp_resume_device = name_to_dev_t(resume_file);
+-		pr_debug("swsusp: Resume From Partition %s\n", resume_file);
++		pr_debug("PM: Resume from partition %s\n", resume_file);
+ 	} else {
+-		pr_debug("swsusp: Resume From Partition %d:%d\n",
+-			 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
++		pr_debug("PM: Resume from partition %d:%d\n",
++				MAJOR(swsusp_resume_device),
++				MINOR(swsusp_resume_device));
+ 	}
+ 
+ 	if (noresume) {
+ 		/**
+-		 * FIXME: If noresume is specified, we need to find the partition
+-		 * and reset it back to normal swap space.
++		 * FIXME: If noresume is specified, we need to find the
++		 * partition and reset it back to normal swap space.
+ 		 */
+ 		mutex_unlock(&pm_mutex);
+ 		return 0;
+ 	}
+ 
+-	pr_debug("PM: Checking swsusp image.\n");
++	pr_debug("PM: Checking hibernation image.\n");
+ 	error = swsusp_check();
+ 	if (error)
+ 		goto Unlock;
+@@ -499,6 +598,11 @@ static int software_resume(void)
+ 		goto Unlock;
+ 	}
+ 
++	pm_prepare_console();
++	error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
++	if (error)
++		goto Finish;
++
+ 	error = create_basic_memory_bitmaps();
+ 	if (error)
+ 		goto Finish;
+@@ -510,7 +614,7 @@ static int software_resume(void)
+ 		goto Done;
+ 	}
+ 
+-	pr_debug("PM: Reading swsusp image.\n");
++	pr_debug("PM: Reading hibernation image.\n");
+ 
+ 	error = swsusp_read(&flags);
+ 	if (!error)
+@@ -518,10 +622,12 @@ static int software_resume(void)
+ 
+ 	printk(KERN_ERR "PM: Restore failed, recovering.\n");
+ 	swsusp_free();
+-	unprepare_processes();
++	thaw_processes();
+  Done:
+ 	free_basic_memory_bitmaps();
+  Finish:
++	pm_notifier_call_chain(PM_POST_RESTORE);
++	pm_restore_console();
+ 	atomic_inc(&snapshot_device_available);
+ 	/* For success case, the suspend path will release the lock */
+  Unlock:
+@@ -567,7 +673,8 @@ static const char * const hibernation_modes[] = {
+  *	supports it (as determined by having hibernation_ops).
+  */
+ 
+-static ssize_t disk_show(struct kset *kset, char *buf)
++static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
++			 char *buf)
+ {
+ 	int i;
+ 	char *start = buf;
+@@ -597,7 +704,8 @@ static ssize_t disk_show(struct kset *kset, char *buf)
+ }
+ 
+ 
+-static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
++static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
++			  const char *buf, size_t n)
+ {
+ 	int error = 0;
+ 	int i;
+@@ -634,7 +742,7 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
+ 		error = -EINVAL;
+ 
+ 	if (!error)
+-		pr_debug("PM: suspend-to-disk mode set to '%s'\n",
++		pr_debug("PM: Hibernation mode set to '%s'\n",
+ 			 hibernation_modes[mode]);
+ 	mutex_unlock(&pm_mutex);
+ 	return error ? error : n;
+@@ -642,13 +750,15 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
+ 
+ power_attr(disk);
+ 
+-static ssize_t resume_show(struct kset *kset, char *buf)
++static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
++			   char *buf)
+ {
+ 	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
+ 		       MINOR(swsusp_resume_device));
+ }
+ 
+-static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
++static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
++			    const char *buf, size_t n)
+ {
+ 	unsigned int maj, min;
+ 	dev_t res;
+@@ -664,7 +774,7 @@ static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
+ 	mutex_lock(&pm_mutex);
+ 	swsusp_resume_device = res;
+ 	mutex_unlock(&pm_mutex);
+-	printk("Attempting manual resume\n");
++	printk(KERN_INFO "PM: Starting manual resume from disk\n");
+ 	noresume = 0;
+ 	software_resume();
+ 	ret = n;
+@@ -674,12 +784,14 @@ static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
+ 
+ power_attr(resume);
+ 
+-static ssize_t image_size_show(struct kset *kset, char *buf)
++static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
++			       char *buf)
+ {
+ 	return sprintf(buf, "%lu\n", image_size);
+ }
+ 
+-static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
++static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
++				const char *buf, size_t n)
+ {
+ 	unsigned long size;
+ 
+@@ -708,7 +820,7 @@ static struct attribute_group attr_group = {
+ 
+ static int __init pm_disk_init(void)
+ {
+-	return sysfs_create_group(&power_subsys.kobj, &attr_group);
++	return sysfs_create_group(power_kobj, &attr_group);
+ }
+ 
+ core_initcall(pm_disk_init);
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index f71c950..6a6d5eb 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -24,13 +24,112 @@
+ 
+ #include "power.h"
+ 
+-BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+-
+ DEFINE_MUTEX(pm_mutex);
+ 
+ unsigned int pm_flags;
+ EXPORT_SYMBOL(pm_flags);
+ 
++#ifdef CONFIG_PM_SLEEP
++
++/* Routines for PM-transition notifications */
++
++static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
++
++int register_pm_notifier(struct notifier_block *nb)
++{
++	return blocking_notifier_chain_register(&pm_chain_head, nb);
++}
++EXPORT_SYMBOL_GPL(register_pm_notifier);
++
++int unregister_pm_notifier(struct notifier_block *nb)
++{
++	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
++}
++EXPORT_SYMBOL_GPL(unregister_pm_notifier);
++
++int pm_notifier_call_chain(unsigned long val)
++{
++	return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
++			== NOTIFY_BAD) ? -EINVAL : 0;
++}
++
++#ifdef CONFIG_PM_DEBUG
++int pm_test_level = TEST_NONE;
++
++static int suspend_test(int level)
++{
++	if (pm_test_level == level) {
++		printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
++		mdelay(5000);
++		return 1;
++	}
++	return 0;
++}
++
++static const char * const pm_tests[__TEST_AFTER_LAST] = {
++	[TEST_NONE] = "none",
++	[TEST_CORE] = "core",
++	[TEST_CPUS] = "processors",
++	[TEST_PLATFORM] = "platform",
++	[TEST_DEVICES] = "devices",
++	[TEST_FREEZER] = "freezer",
++};
++
++static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
++				char *buf)
++{
++	char *s = buf;
++	int level;
++
++	for (level = TEST_FIRST; level <= TEST_MAX; level++)
++		if (pm_tests[level]) {
++			if (level == pm_test_level)
++				s += sprintf(s, "[%s] ", pm_tests[level]);
++			else
++				s += sprintf(s, "%s ", pm_tests[level]);
++		}
++
++	if (s != buf)
++		/* convert the last space to a newline */
++		*(s-1) = '\n';
++
++	return (s - buf);
++}
++
++static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
++				const char *buf, size_t n)
++{
++	const char * const *s;
++	int level;
++	char *p;
++	int len;
++	int error = -EINVAL;
++
++	p = memchr(buf, '\n', n);
++	len = p ? p - buf : n;
++
++	mutex_lock(&pm_mutex);
++
++	level = TEST_FIRST;
++	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
++		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
++			pm_test_level = level;
++			error = 0;
++			break;
++		}
++
++	mutex_unlock(&pm_mutex);
++
++	return error ? error : n;
++}
++
++power_attr(pm_test);
++#else /* !CONFIG_PM_DEBUG */
++static inline int suspend_test(int level) { return 0; }
++#endif /* !CONFIG_PM_DEBUG */
++
++#endif /* CONFIG_PM_SLEEP */
++
+ #ifdef CONFIG_SUSPEND
  
- /*
-diff --git a/kernel/power/disk.c b/kernel/power/disk.c
-index 05b6479..b138b43 100644
---- a/kernel/power/disk.c
-+++ b/kernel/power/disk.c
-@@ -567,7 +567,8 @@ static const char * const hibernation_modes[] = {
-  *	supports it (as determined by having hibernation_ops).
-  */
+ /* This is just an arbitrary number */
+@@ -76,13 +175,13 @@ static int suspend_prepare(void)
+ 	if (!suspend_ops || !suspend_ops->enter)
+ 		return -EPERM;
  
--static ssize_t disk_show(struct kset *kset, char *buf)
-+static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			 char *buf)
- {
- 	int i;
- 	char *start = buf;
-@@ -597,7 +598,8 @@ static ssize_t disk_show(struct kset *kset, char *buf)
- }
++	pm_prepare_console();
++
+ 	error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
+ 	if (error)
+ 		goto Finish;
  
+-	pm_prepare_console();
+-
+-	if (freeze_processes()) {
++	if (suspend_freeze_processes()) {
+ 		error = -EAGAIN;
+ 		goto Thaw;
+ 	}
+@@ -100,10 +199,10 @@ static int suspend_prepare(void)
+ 		return 0;
  
--static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
-+static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
-+			  const char *buf, size_t n)
- {
- 	int error = 0;
- 	int i;
-@@ -642,13 +644,15 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
+  Thaw:
+-	thaw_processes();
+-	pm_restore_console();
++	suspend_thaw_processes();
+  Finish:
+ 	pm_notifier_call_chain(PM_POST_SUSPEND);
++	pm_restore_console();
+ 	return error;
+ }
  
- power_attr(disk);
+@@ -133,10 +232,13 @@ static int suspend_enter(suspend_state_t state)
+ 	BUG_ON(!irqs_disabled());
  
--static ssize_t resume_show(struct kset *kset, char *buf)
-+static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			   char *buf)
- {
- 	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
- 		       MINOR(swsusp_resume_device));
+ 	if ((error = device_power_down(PMSG_SUSPEND))) {
+-		printk(KERN_ERR "Some devices failed to power down\n");
++		printk(KERN_ERR "PM: Some devices failed to power down\n");
+ 		goto Done;
+ 	}
+-	error = suspend_ops->enter(state);
++
++	if (!suspend_test(TEST_CORE))
++		error = suspend_ops->enter(state);
++
+ 	device_power_up();
+  Done:
+ 	arch_suspend_enable_irqs();
+@@ -145,8 +247,8 @@ static int suspend_enter(suspend_state_t state)
  }
  
--static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
-+static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
-+			    const char *buf, size_t n)
- {
- 	unsigned int maj, min;
- 	dev_t res;
-@@ -674,12 +678,14 @@ static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
+ /**
+- *	suspend_devices_and_enter - suspend devices and enter the desired system sleep
+- *			  state.
++ *	suspend_devices_and_enter - suspend devices and enter the desired system
++ *				    sleep state.
+  *	@state:		  state to enter
+  */
+ int suspend_devices_and_enter(suspend_state_t state)
+@@ -156,33 +258,45 @@ int suspend_devices_and_enter(suspend_state_t state)
+ 	if (!suspend_ops)
+ 		return -ENOSYS;
  
- power_attr(resume);
+-	if (suspend_ops->set_target) {
+-		error = suspend_ops->set_target(state);
++	if (suspend_ops->begin) {
++		error = suspend_ops->begin(state);
+ 		if (error)
+-			return error;
++			goto Close;
+ 	}
+ 	suspend_console();
+ 	error = device_suspend(PMSG_SUSPEND);
+ 	if (error) {
+-		printk(KERN_ERR "Some devices failed to suspend\n");
++		printk(KERN_ERR "PM: Some devices failed to suspend\n");
+ 		goto Resume_console;
+ 	}
++
++	if (suspend_test(TEST_DEVICES))
++		goto Resume_devices;
++
+ 	if (suspend_ops->prepare) {
+ 		error = suspend_ops->prepare();
+ 		if (error)
+ 			goto Resume_devices;
+ 	}
++
++	if (suspend_test(TEST_PLATFORM))
++		goto Finish;
++
+ 	error = disable_nonboot_cpus();
+-	if (!error)
++	if (!error && !suspend_test(TEST_CPUS))
+ 		suspend_enter(state);
  
--static ssize_t image_size_show(struct kset *kset, char *buf)
-+static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
-+			       char *buf)
- {
- 	return sprintf(buf, "%lu\n", image_size);
+ 	enable_nonboot_cpus();
++ Finish:
+ 	if (suspend_ops->finish)
+ 		suspend_ops->finish();
+  Resume_devices:
+ 	device_resume();
+  Resume_console:
+ 	resume_console();
++ Close:
++	if (suspend_ops->end)
++		suspend_ops->end();
+ 	return error;
  }
  
--static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
-+static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
-+				const char *buf, size_t n)
+@@ -194,9 +308,9 @@ int suspend_devices_and_enter(suspend_state_t state)
+  */
+ static void suspend_finish(void)
  {
- 	unsigned long size;
+-	thaw_processes();
+-	pm_restore_console();
++	suspend_thaw_processes();
+ 	pm_notifier_call_chain(PM_POST_SUSPEND);
++	pm_restore_console();
+ }
  
-@@ -708,7 +714,7 @@ static struct attribute_group attr_group = {
  
- static int __init pm_disk_init(void)
- {
--	return sysfs_create_group(&power_subsys.kobj, &attr_group);
-+	return sysfs_create_group(power_kobj, &attr_group);
- }
+@@ -238,17 +352,22 @@ static int enter_state(suspend_state_t state)
+ 	if (!mutex_trylock(&pm_mutex))
+ 		return -EBUSY;
  
- core_initcall(pm_disk_init);
-diff --git a/kernel/power/main.c b/kernel/power/main.c
-index f71c950..efc0836 100644
---- a/kernel/power/main.c
-+++ b/kernel/power/main.c
-@@ -276,8 +276,7 @@ EXPORT_SYMBOL(pm_suspend);
+-	printk("Syncing filesystems ... ");
++	printk(KERN_INFO "PM: Syncing filesystems ... ");
+ 	sys_sync();
+ 	printk("done.\n");
+ 
+ 	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
+-	if ((error = suspend_prepare()))
++	error = suspend_prepare();
++	if (error)
+ 		goto Unlock;
+ 
++	if (suspend_test(TEST_FREEZER))
++		goto Finish;
++
+ 	pr_debug("PM: Entering %s sleep\n", pm_states[state]);
+ 	error = suspend_devices_and_enter(state);
+ 
++ Finish:
+ 	pr_debug("PM: Finishing wakeup.\n");
+ 	suspend_finish();
+  Unlock:
+@@ -276,8 +395,7 @@ EXPORT_SYMBOL(pm_suspend);
  
  #endif /* CONFIG_SUSPEND */
  
@@ -828565,7 +883925,7 @@
  
  /**
   *	state - control system power state.
-@@ -290,7 +289,8 @@ decl_subsys(power,NULL,NULL);
+@@ -290,7 +408,8 @@ decl_subsys(power,NULL,NULL);
   *	proper enumerated value, and initiates a suspend transition.
   */
  
@@ -828575,7 +883935,7 @@
  {
  	char *s = buf;
  #ifdef CONFIG_SUSPEND
-@@ -311,7 +311,8 @@ static ssize_t state_show(struct kset *kset, char *buf)
+@@ -311,7 +430,8 @@ static ssize_t state_show(struct kset *kset, char *buf)
  	return (s - buf);
  }
  
@@ -828585,7 +883945,7 @@
  {
  #ifdef CONFIG_SUSPEND
  	suspend_state_t state = PM_SUSPEND_STANDBY;
-@@ -348,13 +349,15 @@ power_attr(state);
+@@ -348,13 +468,15 @@ power_attr(state);
  #ifdef CONFIG_PM_TRACE
  int pm_trace_enabled;
  
@@ -828603,7 +883963,32 @@
  {
  	int val;
  
-@@ -386,10 +389,10 @@ static struct attribute_group attr_group = {
+@@ -366,18 +488,18 @@ pm_trace_store(struct kset *kset, const char *buf, size_t n)
+ }
+ 
+ power_attr(pm_trace);
++#endif /* CONFIG_PM_TRACE */
+ 
+ static struct attribute * g[] = {
+ 	&state_attr.attr,
++#ifdef CONFIG_PM_TRACE
+ 	&pm_trace_attr.attr,
++#endif
++#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
++	&pm_test_attr.attr,
++#endif
+ 	NULL,
+ };
+-#else
+-static struct attribute * g[] = {
+-	&state_attr.attr,
+-	NULL,
+-};
+-#endif /* CONFIG_PM_TRACE */
+ 
+ static struct attribute_group attr_group = {
+ 	.attrs = g,
+@@ -386,10 +508,10 @@ static struct attribute_group attr_group = {
  
  static int __init pm_init(void)
  {
@@ -828619,10 +884004,18 @@
  
  core_initcall(pm_init);
 diff --git a/kernel/power/power.h b/kernel/power/power.h
-index 195dc46..2093c3a 100644
+index 195dc46..700f44e 100644
 --- a/kernel/power/power.h
 +++ b/kernel/power/power.h
-@@ -54,7 +54,7 @@ extern int pfn_is_nosave(unsigned long);
+@@ -1,5 +1,7 @@
+ #include <linux/suspend.h>
++#include <linux/suspend_ioctls.h>
+ #include <linux/utsname.h>
++#include <linux/freezer.h>
+ 
+ struct swsusp_info {
+ 	struct new_utsname	uts;
+@@ -54,7 +56,7 @@ extern int pfn_is_nosave(unsigned long);
  extern struct mutex pm_mutex;
  
  #define power_attr(_name) \
@@ -828631,7 +884024,7 @@
  	.attr	= {				\
  		.name = __stringify(_name),	\
  		.mode = 0644,			\
-@@ -63,8 +63,6 @@ static struct subsys_attribute _name##_attr = {	\
+@@ -63,8 +65,6 @@ static struct subsys_attribute _name##_attr = {	\
  	.store	= _name##_store,		\
  }
  
@@ -828640,6 +884033,120 @@
  /* Preferred image size in bytes (default 500 MB) */
  extern unsigned long image_size;
  extern int in_suspend;
+@@ -130,42 +130,12 @@ struct snapshot_handle {
+ #define data_of(handle)	((handle).buffer + (handle).buf_offset)
+ 
+ extern unsigned int snapshot_additional_pages(struct zone *zone);
++extern unsigned long snapshot_get_image_size(void);
+ extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
+ extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
+ extern void snapshot_write_finalize(struct snapshot_handle *handle);
+ extern int snapshot_image_loaded(struct snapshot_handle *handle);
+ 
+-/*
+- * This structure is used to pass the values needed for the identification
+- * of the resume swap area from a user space to the kernel via the
+- * SNAPSHOT_SET_SWAP_AREA ioctl
+- */
+-struct resume_swap_area {
+-	loff_t offset;
+-	u_int32_t dev;
+-} __attribute__((packed));
+-
+-#define SNAPSHOT_IOC_MAGIC	'3'
+-#define SNAPSHOT_FREEZE			_IO(SNAPSHOT_IOC_MAGIC, 1)
+-#define SNAPSHOT_UNFREEZE		_IO(SNAPSHOT_IOC_MAGIC, 2)
+-#define SNAPSHOT_ATOMIC_SNAPSHOT	_IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
+-#define SNAPSHOT_ATOMIC_RESTORE		_IO(SNAPSHOT_IOC_MAGIC, 4)
+-#define SNAPSHOT_FREE			_IO(SNAPSHOT_IOC_MAGIC, 5)
+-#define SNAPSHOT_SET_IMAGE_SIZE		_IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
+-#define SNAPSHOT_AVAIL_SWAP		_IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
+-#define SNAPSHOT_GET_SWAP_PAGE		_IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
+-#define SNAPSHOT_FREE_SWAP_PAGES	_IO(SNAPSHOT_IOC_MAGIC, 9)
+-#define SNAPSHOT_SET_SWAP_FILE		_IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
+-#define SNAPSHOT_S2RAM			_IO(SNAPSHOT_IOC_MAGIC, 11)
+-#define SNAPSHOT_PMOPS			_IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
+-#define SNAPSHOT_SET_SWAP_AREA		_IOW(SNAPSHOT_IOC_MAGIC, 13, \
+-							struct resume_swap_area)
+-#define SNAPSHOT_IOC_MAXNR	13
+-
+-#define PMOPS_PREPARE	1
+-#define PMOPS_ENTER	2
+-#define PMOPS_FINISH	3
+-
+ /* If unset, the snapshot device cannot be open. */
+ extern atomic_t snapshot_device_available;
+ 
+@@ -183,7 +153,6 @@ extern int swsusp_swap_in_use(void);
+ extern int swsusp_check(void);
+ extern int swsusp_shrink_memory(void);
+ extern void swsusp_free(void);
+-extern int swsusp_resume(void);
+ extern int swsusp_read(unsigned int *flags_p);
+ extern int swsusp_write(unsigned int flags);
+ extern void swsusp_close(void);
+@@ -203,11 +172,56 @@ static inline int suspend_devices_and_enter(suspend_state_t state)
+ }
+ #endif /* !CONFIG_SUSPEND */
+ 
+-/* kernel/power/common.c */
+-extern struct blocking_notifier_head pm_chain_head;
++#ifdef CONFIG_PM_SLEEP
++/* kernel/power/main.c */
++extern int pm_notifier_call_chain(unsigned long val);
++#endif
++
++#ifdef CONFIG_HIGHMEM
++unsigned int count_highmem_pages(void);
++int restore_highmem(void);
++#else
++static inline unsigned int count_highmem_pages(void) { return 0; }
++static inline int restore_highmem(void) { return 0; }
++#endif
++
++/*
++ * Suspend test levels
++ */
++enum {
++	/* keep first */
++	TEST_NONE,
++	TEST_CORE,
++	TEST_CPUS,
++	TEST_PLATFORM,
++	TEST_DEVICES,
++	TEST_FREEZER,
++	/* keep last */
++	__TEST_AFTER_LAST
++};
+ 
+-static inline int pm_notifier_call_chain(unsigned long val)
++#define TEST_FIRST	TEST_NONE
++#define TEST_MAX	(__TEST_AFTER_LAST - 1)
++
++extern int pm_test_level;
++
++#ifdef CONFIG_SUSPEND_FREEZER
++static inline int suspend_freeze_processes(void)
++{
++	return freeze_processes();
++}
++
++static inline void suspend_thaw_processes(void)
+ {
+-	return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+-			== NOTIFY_BAD) ? -EINVAL : 0;
++	thaw_processes();
+ }
++#else
++static inline int suspend_freeze_processes(void)
++{
++	return 0;
++}
++
++static inline void suspend_thaw_processes(void)
++{
++}
++#endif
 diff --git a/kernel/power/process.c b/kernel/power/process.c
 index 6533923..7c2118f 100644
 --- a/kernel/power/process.c
@@ -828665,6 +884172,579 @@
  				cancel_freezing(p);
  				continue;
  			}
+diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
+index 78039b4..f6a5df9 100644
+--- a/kernel/power/snapshot.c
++++ b/kernel/power/snapshot.c
+@@ -635,7 +635,7 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+ 	region->end_pfn = end_pfn;
+ 	list_add_tail(&region->list, &nosave_regions);
+  Report:
+-	printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
++	printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
+ 		start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+ }
+ 
+@@ -704,7 +704,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
+ 	list_for_each_entry(region, &nosave_regions, list) {
+ 		unsigned long pfn;
+ 
+-		printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
++		pr_debug("PM: Marking nosave pages: %016lx - %016lx\n",
+ 				region->start_pfn << PAGE_SHIFT,
+ 				region->end_pfn << PAGE_SHIFT);
+ 
+@@ -749,7 +749,7 @@ int create_basic_memory_bitmaps(void)
+ 	free_pages_map = bm2;
+ 	mark_nosave_pages(forbidden_pages_map);
+ 
+-	printk("swsusp: Basic memory bitmaps created\n");
++	pr_debug("PM: Basic memory bitmaps created\n");
+ 
+ 	return 0;
+ 
+@@ -784,7 +784,7 @@ void free_basic_memory_bitmaps(void)
+ 	memory_bm_free(bm2, PG_UNSAFE_CLEAR);
+ 	kfree(bm2);
+ 
+-	printk("swsusp: Basic memory bitmaps freed\n");
++	pr_debug("PM: Basic memory bitmaps freed\n");
+ }
+ 
+ /**
+@@ -872,7 +872,6 @@ unsigned int count_highmem_pages(void)
+ }
+ #else
+ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
+-static inline unsigned int count_highmem_pages(void) { return 0; }
+ #endif /* CONFIG_HIGHMEM */
+ 
+ /**
+@@ -1089,7 +1088,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
+ 	}
+ 
+ 	nr_pages += count_pages_for_highmem(nr_highmem);
+-	pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n",
++	pr_debug("PM: Normal pages needed: %u + %u + %u, available pages: %u\n",
+ 		nr_pages, PAGES_FOR_IO, meta, free);
+ 
+ 	return free > nr_pages + PAGES_FOR_IO + meta;
+@@ -1202,20 +1201,20 @@ asmlinkage int swsusp_save(void)
+ {
+ 	unsigned int nr_pages, nr_highmem;
+ 
+-	printk("swsusp: critical section: \n");
++	printk(KERN_INFO "PM: Creating hibernation image: \n");
+ 
+ 	drain_local_pages();
+ 	nr_pages = count_data_pages();
+ 	nr_highmem = count_highmem_pages();
+-	printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem);
++	printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem);
+ 
+ 	if (!enough_free_mem(nr_pages, nr_highmem)) {
+-		printk(KERN_ERR "swsusp: Not enough free memory\n");
++		printk(KERN_ERR "PM: Not enough free memory\n");
+ 		return -ENOMEM;
+ 	}
+ 
+ 	if (swsusp_alloc(&orig_bm, &copy_bm, nr_pages, nr_highmem)) {
+-		printk(KERN_ERR "swsusp: Memory allocation failed\n");
++		printk(KERN_ERR "PM: Memory allocation failed\n");
+ 		return -ENOMEM;
+ 	}
+ 
+@@ -1235,7 +1234,8 @@ asmlinkage int swsusp_save(void)
+ 	nr_copy_pages = nr_pages;
+ 	nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
+ 
+-	printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
++	printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
++		nr_pages);
+ 
+ 	return 0;
+ }
+@@ -1264,12 +1264,17 @@ static char *check_image_kernel(struct swsusp_info *info)
+ }
+ #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
+ 
++unsigned long snapshot_get_image_size(void)
++{
++	return nr_copy_pages + nr_meta_pages + 1;
++}
++
+ static int init_header(struct swsusp_info *info)
+ {
+ 	memset(info, 0, sizeof(struct swsusp_info));
+ 	info->num_physpages = num_physpages;
+ 	info->image_pages = nr_copy_pages;
+-	info->pages = nr_copy_pages + nr_meta_pages + 1;
++	info->pages = snapshot_get_image_size();
+ 	info->size = info->pages;
+ 	info->size <<= PAGE_SHIFT;
+ 	return init_header_complete(info);
+@@ -1429,7 +1434,7 @@ static int check_header(struct swsusp_info *info)
+ 	if (!reason && info->num_physpages != num_physpages)
+ 		reason = "memory size";
+ 	if (reason) {
+-		printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
++		printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
+ 		return -EPERM;
+ 	}
+ 	return 0;
+diff --git a/kernel/power/swap.c b/kernel/power/swap.c
+index 917aba1..a0abf9a 100644
+--- a/kernel/power/swap.c
++++ b/kernel/power/swap.c
+@@ -28,8 +28,6 @@
+ 
+ #include "power.h"
+ 
+-extern char resume_file[];
+-
+ #define SWSUSP_SIG	"S1SUSPEND"
+ 
+ struct swsusp_header {
+@@ -73,7 +71,8 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
+ 	bio->bi_end_io = end_swap_bio_read;
+ 
+ 	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
+-		printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
++		printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
++			page_off);
+ 		bio_put(bio);
+ 		return -EFAULT;
+ 	}
+@@ -153,7 +152,7 @@ static int mark_swapfiles(sector_t start, unsigned int flags)
+ 		error = bio_write_page(swsusp_resume_block,
+ 					swsusp_header, NULL);
+ 	} else {
+-		printk(KERN_ERR "swsusp: Swap header not found!\n");
++		printk(KERN_ERR "PM: Swap header not found!\n");
+ 		error = -ENODEV;
+ 	}
+ 	return error;
+@@ -325,7 +324,8 @@ static int save_image(struct swap_map_handle *handle,
+ 	struct timeval start;
+ 	struct timeval stop;
+ 
+-	printk("Saving image data pages (%u pages) ...     ", nr_to_write);
++	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
++		nr_to_write);
+ 	m = nr_to_write / 100;
+ 	if (!m)
+ 		m = 1;
+@@ -365,7 +365,7 @@ static int enough_swap(unsigned int nr_pages)
+ {
+ 	unsigned int free_swap = count_swap_pages(root_swap, 1);
+ 
+-	pr_debug("swsusp: free swap pages: %u\n", free_swap);
++	pr_debug("PM: Free swap pages: %u\n", free_swap);
+ 	return free_swap > nr_pages + PAGES_FOR_IO;
+ }
+ 
+@@ -388,7 +388,7 @@ int swsusp_write(unsigned int flags)
+ 
+ 	error = swsusp_swap_check();
+ 	if (error) {
+-		printk(KERN_ERR "swsusp: Cannot find swap device, try "
++		printk(KERN_ERR "PM: Cannot find swap device, try "
+ 				"swapon -a.\n");
+ 		return error;
+ 	}
+@@ -402,7 +402,7 @@ int swsusp_write(unsigned int flags)
+ 	}
+ 	header = (struct swsusp_info *)data_of(snapshot);
+ 	if (!enough_swap(header->pages)) {
+-		printk(KERN_ERR "swsusp: Not enough free swap\n");
++		printk(KERN_ERR "PM: Not enough free swap\n");
+ 		error = -ENOSPC;
+ 		goto out;
+ 	}
+@@ -417,7 +417,7 @@ int swsusp_write(unsigned int flags)
+ 
+ 		if (!error) {
+ 			flush_swap_writer(&handle);
+-			printk("S");
++			printk(KERN_INFO "PM: S");
+ 			error = mark_swapfiles(start, flags);
+ 			printk("|\n");
+ 		}
+@@ -507,7 +507,8 @@ static int load_image(struct swap_map_handle *handle,
+ 	int err2;
+ 	unsigned nr_pages;
+ 
+-	printk("Loading image data pages (%u pages) ...     ", nr_to_read);
++	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
++		nr_to_read);
+ 	m = nr_to_read / 100;
+ 	if (!m)
+ 		m = 1;
+@@ -558,7 +559,7 @@ int swsusp_read(unsigned int *flags_p)
+ 
+ 	*flags_p = swsusp_header->flags;
+ 	if (IS_ERR(resume_bdev)) {
+-		pr_debug("swsusp: block device not initialised\n");
++		pr_debug("PM: Image device not initialised\n");
+ 		return PTR_ERR(resume_bdev);
+ 	}
+ 
+@@ -577,9 +578,9 @@ int swsusp_read(unsigned int *flags_p)
+ 	blkdev_put(resume_bdev);
+ 
+ 	if (!error)
+-		pr_debug("swsusp: Reading resume file was successful\n");
++		pr_debug("PM: Image successfully loaded\n");
+ 	else
+-		pr_debug("swsusp: Error %d resuming\n", error);
++		pr_debug("PM: Error %d resuming\n", error);
+ 	return error;
+ }
+ 
+@@ -611,13 +612,13 @@ int swsusp_check(void)
+ 		if (error)
+ 			blkdev_put(resume_bdev);
+ 		else
+-			pr_debug("swsusp: Signature found, resuming\n");
++			pr_debug("PM: Signature found, resuming\n");
+ 	} else {
+ 		error = PTR_ERR(resume_bdev);
+ 	}
+ 
+ 	if (error)
+-		pr_debug("swsusp: Error %d check for resume file\n", error);
++		pr_debug("PM: Error %d checking image file\n", error);
+ 
+ 	return error;
+ }
+@@ -629,7 +630,7 @@ int swsusp_check(void)
+ void swsusp_close(void)
+ {
+ 	if (IS_ERR(resume_bdev)) {
+-		pr_debug("swsusp: block device not initialised\n");
++		pr_debug("PM: Image device not initialised\n");
+ 		return;
+ 	}
+ 
+diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
+index e1722d3..023ff2a 100644
+--- a/kernel/power/swsusp.c
++++ b/kernel/power/swsusp.c
+@@ -64,14 +64,6 @@ unsigned long image_size = 500 * 1024 * 1024;
+ 
+ int in_suspend __nosavedata = 0;
+ 
+-#ifdef CONFIG_HIGHMEM
+-unsigned int count_highmem_pages(void);
+-int restore_highmem(void);
+-#else
+-static inline int restore_highmem(void) { return 0; }
+-static inline unsigned int count_highmem_pages(void) { return 0; }
+-#endif
+-
+ /**
+  *	The following functions are used for tracing the allocated
+  *	swap pages, so that they can be freed in case of an error.
+@@ -196,7 +188,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+ 		centisecs = 1;	/* avoid div-by-zero */
+ 	k = nr_pages * (PAGE_SIZE / 1024);
+ 	kps = (k * 100) / centisecs;
+-	printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k,
++	printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
++			msg, k,
+ 			centisecs / 100, centisecs % 100,
+ 			kps / 1000, (kps % 1000) / 10);
+ }
+@@ -227,7 +220,7 @@ int swsusp_shrink_memory(void)
+ 	char *p = "-\\|/";
+ 	struct timeval start, stop;
+ 
+-	printk("Shrinking memory...  ");
++	printk(KERN_INFO "PM: Shrinking memory...  ");
+ 	do_gettimeofday(&start);
+ 	do {
+ 		long size, highmem_size;
+@@ -269,38 +262,3 @@ int swsusp_shrink_memory(void)
+ 
+ 	return 0;
+ }
+-
+-int swsusp_resume(void)
+-{
+-	int error;
+-
+-	local_irq_disable();
+-	/* NOTE:  device_power_down() is just a suspend() with irqs off;
+-	 * it has no special "power things down" semantics
+-	 */
+-	if (device_power_down(PMSG_PRETHAW))
+-		printk(KERN_ERR "Some devices failed to power down, very bad\n");
+-	/* We'll ignore saved state, but this gets preempt count (etc) right */
+-	save_processor_state();
+-	error = restore_highmem();
+-	if (!error) {
+-		error = swsusp_arch_resume();
+-		/* The code below is only ever reached in case of a failure.
+-		 * Otherwise execution continues at place where
+-		 * swsusp_arch_suspend() was called
+-        	 */
+-		BUG_ON(!error);
+-		/* This call to restore_highmem() undos the previous one */
+-		restore_highmem();
+-	}
+-	/* The only reason why swsusp_arch_resume() can fail is memory being
+-	 * very tight, so we have to free it as soon as we can to avoid
+-	 * subsequent failures
+-	 */
+-	swsusp_free();
+-	restore_processor_state();
+-	touch_softlockup_watchdog();
+-	device_power_up();
+-	local_irq_enable();
+-	return error;
+-}
+diff --git a/kernel/power/user.c b/kernel/power/user.c
+index 5bd321b..f5512cb 100644
+--- a/kernel/power/user.c
++++ b/kernel/power/user.c
+@@ -28,6 +28,29 @@
+ 
+ #include "power.h"
+ 
++/*
++ * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
++ * will be removed in the future.  They are only preserved here for
++ * compatibility with existing userland utilities.
++ */
++#define SNAPSHOT_SET_SWAP_FILE	_IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
++#define SNAPSHOT_PMOPS		_IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
++
++#define PMOPS_PREPARE	1
++#define PMOPS_ENTER	2
++#define PMOPS_FINISH	3
++
++/*
++ * NOTE: The following ioctl definitions are wrong and have been replaced with
++ * correct ones.  They are only preserved here for compatibility with existing
++ * userland utilities and will be removed in the future.
++ */
++#define SNAPSHOT_ATOMIC_SNAPSHOT	_IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
++#define SNAPSHOT_SET_IMAGE_SIZE		_IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
++#define SNAPSHOT_AVAIL_SWAP		_IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
++#define SNAPSHOT_GET_SWAP_PAGE		_IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
++
++
+ #define SNAPSHOT_MINOR	231
+ 
+ static struct snapshot_data {
+@@ -36,7 +59,7 @@ static struct snapshot_data {
+ 	int mode;
+ 	char frozen;
+ 	char ready;
+-	char platform_suspend;
++	char platform_support;
+ } snapshot_state;
+ 
+ atomic_t snapshot_device_available = ATOMIC_INIT(1);
+@@ -44,6 +67,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1);
+ static int snapshot_open(struct inode *inode, struct file *filp)
+ {
+ 	struct snapshot_data *data;
++	int error;
+ 
+ 	if (!atomic_add_unless(&snapshot_device_available, -1, 0))
+ 		return -EBUSY;
+@@ -64,13 +88,23 @@ static int snapshot_open(struct inode *inode, struct file *filp)
+ 		data->swap = swsusp_resume_device ?
+ 			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
+ 		data->mode = O_RDONLY;
++		error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
++		if (error)
++			pm_notifier_call_chain(PM_POST_RESTORE);
+ 	} else {
+ 		data->swap = -1;
+ 		data->mode = O_WRONLY;
++		error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
++		if (error)
++			pm_notifier_call_chain(PM_POST_HIBERNATION);
++	}
++	if (error) {
++		atomic_inc(&snapshot_device_available);
++		return error;
+ 	}
+ 	data->frozen = 0;
+ 	data->ready = 0;
+-	data->platform_suspend = 0;
++	data->platform_support = 0;
+ 
+ 	return 0;
+ }
+@@ -88,6 +122,8 @@ static int snapshot_release(struct inode *inode, struct file *filp)
+ 		thaw_processes();
+ 		mutex_unlock(&pm_mutex);
+ 	}
++	pm_notifier_call_chain(data->mode == O_WRONLY ?
++			PM_POST_HIBERNATION : PM_POST_RESTORE);
+ 	atomic_inc(&snapshot_device_available);
+ 	return 0;
+ }
+@@ -133,7 +169,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ {
+ 	int error = 0;
+ 	struct snapshot_data *data;
+-	loff_t avail;
++	loff_t size;
+ 	sector_t offset;
+ 
+ 	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
+@@ -151,18 +187,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 		if (data->frozen)
+ 			break;
+ 		mutex_lock(&pm_mutex);
+-		error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+-		if (!error) {
+-			printk("Syncing filesystems ... ");
+-			sys_sync();
+-			printk("done.\n");
+-
+-			error = freeze_processes();
+-			if (error)
+-				thaw_processes();
+-		}
++		printk("Syncing filesystems ... ");
++		sys_sync();
++		printk("done.\n");
++
++		error = freeze_processes();
+ 		if (error)
+-			pm_notifier_call_chain(PM_POST_HIBERNATION);
++			thaw_processes();
+ 		mutex_unlock(&pm_mutex);
+ 		if (!error)
+ 			data->frozen = 1;
+@@ -173,19 +204,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 			break;
+ 		mutex_lock(&pm_mutex);
+ 		thaw_processes();
+-		pm_notifier_call_chain(PM_POST_HIBERNATION);
+ 		mutex_unlock(&pm_mutex);
+ 		data->frozen = 0;
+ 		break;
+ 
++	case SNAPSHOT_CREATE_IMAGE:
+ 	case SNAPSHOT_ATOMIC_SNAPSHOT:
+ 		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
+ 			error = -EPERM;
+ 			break;
+ 		}
+-		error = hibernation_snapshot(data->platform_suspend);
++		error = hibernation_snapshot(data->platform_support);
+ 		if (!error)
+-			error = put_user(in_suspend, (unsigned int __user *)arg);
++			error = put_user(in_suspend, (int __user *)arg);
+ 		if (!error)
+ 			data->ready = 1;
+ 		break;
+@@ -197,7 +228,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 			error = -EPERM;
+ 			break;
+ 		}
+-		error = hibernation_restore(data->platform_suspend);
++		error = hibernation_restore(data->platform_support);
+ 		break;
+ 
+ 	case SNAPSHOT_FREE:
+@@ -206,16 +237,29 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 		data->ready = 0;
+ 		break;
+ 
++	case SNAPSHOT_PREF_IMAGE_SIZE:
+ 	case SNAPSHOT_SET_IMAGE_SIZE:
+ 		image_size = arg;
+ 		break;
+ 
++	case SNAPSHOT_GET_IMAGE_SIZE:
++		if (!data->ready) {
++			error = -ENODATA;
++			break;
++		}
++		size = snapshot_get_image_size();
++		size <<= PAGE_SHIFT;
++		error = put_user(size, (loff_t __user *)arg);
++		break;
++
++	case SNAPSHOT_AVAIL_SWAP_SIZE:
+ 	case SNAPSHOT_AVAIL_SWAP:
+-		avail = count_swap_pages(data->swap, 1);
+-		avail <<= PAGE_SHIFT;
+-		error = put_user(avail, (loff_t __user *)arg);
++		size = count_swap_pages(data->swap, 1);
++		size <<= PAGE_SHIFT;
++		error = put_user(size, (loff_t __user *)arg);
+ 		break;
+ 
++	case SNAPSHOT_ALLOC_SWAP_PAGE:
+ 	case SNAPSHOT_GET_SWAP_PAGE:
+ 		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
+ 			error = -ENODEV;
+@@ -224,7 +268,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 		offset = alloc_swapdev_block(data->swap);
+ 		if (offset) {
+ 			offset <<= PAGE_SHIFT;
+-			error = put_user(offset, (sector_t __user *)arg);
++			error = put_user(offset, (loff_t __user *)arg);
+ 		} else {
+ 			error = -ENOSPC;
+ 		}
+@@ -238,7 +282,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 		free_all_swap_pages(data->swap);
+ 		break;
+ 
+-	case SNAPSHOT_SET_SWAP_FILE:
++	case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
+ 		if (!swsusp_swap_in_use()) {
+ 			/*
+ 			 * User space encodes device types as two-byte values,
+@@ -275,26 +319,33 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
+ 		mutex_unlock(&pm_mutex);
+ 		break;
+ 
+-	case SNAPSHOT_PMOPS:
++	case SNAPSHOT_PLATFORM_SUPPORT:
++		data->platform_support = !!arg;
++		break;
++
++	case SNAPSHOT_POWER_OFF:
++		if (data->platform_support)
++			error = hibernation_platform_enter();
++		break;
++
++	case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
+ 		error = -EINVAL;
+ 
+ 		switch (arg) {
+ 
+ 		case PMOPS_PREPARE:
+-			data->platform_suspend = 1;
++			data->platform_support = 1;
+ 			error = 0;
+ 			break;
+ 
+ 		case PMOPS_ENTER:
+-			if (data->platform_suspend)
++			if (data->platform_support)
+ 				error = hibernation_platform_enter();
+-
+ 			break;
+ 
+ 		case PMOPS_FINISH:
+-			if (data->platform_suspend)
++			if (data->platform_support)
+ 				error = 0;
+-
+ 			break;
+ 
+ 		default:
 diff --git a/kernel/printk.c b/kernel/printk.c
 index 89011bf..29ae1e9 100644
 --- a/kernel/printk.c
@@ -836261,7 +892341,7 @@
  #endif
  }
 diff --git a/kernel/softlockup.c b/kernel/softlockup.c
-index 11df812..c1d7655 100644
+index 11df812..7c2da88 100644
 --- a/kernel/softlockup.c
 +++ b/kernel/softlockup.c
 @@ -8,6 +8,7 @@
@@ -836292,20 +892372,16 @@
  }
  
  void touch_softlockup_watchdog(void)
-@@ -100,11 +101,7 @@ void softlockup_tick(void)
+@@ -104,7 +105,7 @@ void softlockup_tick(void)
+ 	if (now > (touch_timestamp + 1))
+ 		wake_up_process(per_cpu(watchdog_task, this_cpu));
  
- 	now = get_timestamp(this_cpu);
- 
--	/* Wake up the high-prio watchdog task every second: */
--	if (now > (touch_timestamp + 1))
--		wake_up_process(per_cpu(watchdog_task, this_cpu));
--
 -	/* Warn about unreasonable 10+ seconds delays: */
 +	/* Warn about unreasonable delays: */
  	if (now <= (touch_timestamp + softlockup_thresh))
  		return;
  
-@@ -122,11 +119,93 @@ void softlockup_tick(void)
+@@ -122,11 +123,93 @@ void softlockup_tick(void)
  }
  
  /*
@@ -836381,11 +892457,11 @@
 +	read_lock(&tasklist_lock);
 +	do_each_thread(g, t) {
 +		if (!--max_count)
-+			break;
++			goto unlock;
 +		if (t->state & TASK_UNINTERRUPTIBLE)
 +			check_hung_task(t, now);
 +	} while_each_thread(g, t);
-+
++ unlock:
 +	read_unlock(&tasklist_lock);
 +}
 +
@@ -836399,7 +892475,7 @@
  
  	sched_setscheduler(current, SCHED_FIFO, &param);
  
-@@ -135,13 +214,18 @@ static int watchdog(void *__bind_cpu)
+@@ -135,13 +218,23 @@ static int watchdog(void *__bind_cpu)
  
  	/*
  	 * Run briefly once per second to reset the softlockup timestamp.
@@ -836408,20 +892484,23 @@
  	 * debug-printout triggers in softlockup_tick().
  	 */
  	while (!kthread_should_stop()) {
--		set_current_state(TASK_INTERRUPTIBLE);
+ 		set_current_state(TASK_INTERRUPTIBLE);
  		touch_softlockup_watchdog();
--		schedule();
-+		msleep_interruptible(10000);
+ 		schedule();
++
++		if (kthread_should_stop())
++			break;
 +
 +		if (this_cpu != check_cpu)
 +			continue;
 +
 +		if (sysctl_hung_task_timeout_secs)
 +			check_hung_uninterruptible_tasks(this_cpu);
++
  	}
  
  	return 0;
-@@ -171,6 +255,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+@@ -171,9 +264,20 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
  		break;
  	case CPU_ONLINE:
  	case CPU_ONLINE_FROZEN:
@@ -836429,10 +892508,6 @@
  		wake_up_process(per_cpu(watchdog_task, hotcpu));
  		break;
  #ifdef CONFIG_HOTPLUG_CPU
-@@ -181,6 +266,15 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
- 		/* Unbind so it can run.  Fall thru. */
- 		kthread_bind(per_cpu(watchdog_task, hotcpu),
- 			     any_online_cpu(cpu_online_map));
 +	case CPU_DOWN_PREPARE:
 +	case CPU_DOWN_PREPARE_FROZEN:
 +		if (hotcpu == check_cpu) {
@@ -836442,9 +892517,10 @@
 +			check_cpu = any_online_cpu(temp_cpu_online_map);
 +		}
 +		break;
- 	case CPU_DEAD:
- 	case CPU_DEAD_FROZEN:
- 		p = per_cpu(watchdog_task, hotcpu);
++
+ 	case CPU_UP_CANCELED:
+ 	case CPU_UP_CANCELED_FROZEN:
+ 		if (!per_cpu(watchdog_task, hotcpu))
 diff --git a/kernel/spinlock.c b/kernel/spinlock.c
 index cd72424..ae28c82 100644
 --- a/kernel/spinlock.c
@@ -836492,7 +892568,7 @@
  /* mmu depending weak syscall entries */
  cond_syscall(sys_mprotect);
 diff --git a/kernel/sysctl.c b/kernel/sysctl.c
-index c68f68d..357b68b 100644
+index c68f68d..7cb1ac3 100644
 --- a/kernel/sysctl.c
 +++ b/kernel/sysctl.c
 @@ -53,6 +53,7 @@
@@ -836503,15 +892579,16 @@
  #endif
  
  static int deprecated_sysctl_warning(struct __sysctl_args *args);
-@@ -81,6 +82,7 @@ extern int compat_log;
+@@ -80,7 +81,7 @@ extern int percpu_pagelist_fraction;
+ extern int compat_log;
  extern int maps_protect;
  extern int sysctl_stat_interval;
- extern int audit_argv_kb;
+-extern int audit_argv_kb;
 +extern int latencytop_enabled;
  
  /* Constants used for minimum and  maximum */
  #ifdef CONFIG_DETECT_SOFTLOCKUP
-@@ -156,8 +158,16 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
+@@ -156,8 +157,16 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
  #endif
  
  static struct ctl_table root_table[];
@@ -836530,7 +892607,7 @@
  
  static struct ctl_table kern_table[];
  static struct ctl_table vm_table[];
-@@ -191,14 +201,6 @@ static struct ctl_table root_table[] = {
+@@ -191,14 +200,6 @@ static struct ctl_table root_table[] = {
  		.mode		= 0555,
  		.child		= vm_table,
  	},
@@ -836545,7 +892622,7 @@
  	{
  		.ctl_name	= CTL_FS,
  		.procname	= "fs",
-@@ -306,9 +308,43 @@ static struct ctl_table kern_table[] = {
+@@ -306,9 +307,43 @@ static struct ctl_table kern_table[] = {
  		.procname	= "sched_nr_migrate",
  		.data		= &sysctl_sched_nr_migrate,
  		.maxlen		= sizeof(unsigned int),
@@ -836590,7 +892667,24 @@
  #endif
  	{
  		.ctl_name	= CTL_UNNUMBERED,
-@@ -382,6 +418,15 @@ static struct ctl_table kern_table[] = {
+@@ -354,16 +389,6 @@ static struct ctl_table kern_table[] = {
+ 		.mode		= 0644,
+ 		.proc_handler	= &proc_dointvec,
+ 	},
+-#ifdef CONFIG_AUDITSYSCALL
+-	{
+-		.ctl_name	= CTL_UNNUMBERED,
+-		.procname	= "audit_argv_kb",
+-		.data		= &audit_argv_kb,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec,
+-	},
+-#endif
+ 	{
+ 		.ctl_name	= KERN_CORE_PATTERN,
+ 		.procname	= "core_pattern",
+@@ -382,6 +407,15 @@ static struct ctl_table kern_table[] = {
  		.proc_handler	= &proc_dointvec_taint,
  	},
  #endif
@@ -836606,7 +892700,7 @@
  #ifdef CONFIG_SECURITY_CAPABILITIES
  	{
  		.procname	= "cap-bound",
-@@ -683,6 +728,14 @@ static struct ctl_table kern_table[] = {
+@@ -683,6 +717,14 @@ static struct ctl_table kern_table[] = {
  		.mode		= 0644,
  		.proc_handler	= &proc_dointvec,
  	},
@@ -836621,7 +892715,7 @@
  #endif
  #if defined(CONFIG_MMU)
  	{
-@@ -728,13 +781,40 @@ static struct ctl_table kern_table[] = {
+@@ -728,13 +770,40 @@ static struct ctl_table kern_table[] = {
  		.ctl_name	= CTL_UNNUMBERED,
  		.procname	= "softlockup_thresh",
  		.data		= &softlockup_thresh,
@@ -836664,7 +892758,7 @@
  #endif
  #ifdef CONFIG_COMPAT
  	{
-@@ -1300,12 +1380,27 @@ void sysctl_head_finish(struct ctl_table_header *head)
+@@ -1300,12 +1369,27 @@ void sysctl_head_finish(struct ctl_table_header *head)
  	spin_unlock(&sysctl_lock);
  }
  
@@ -836693,7 +892787,7 @@
  		tmp = &prev->ctl_entry;
  		unuse_table(prev);
  		goto next;
-@@ -1319,14 +1414,38 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
+@@ -1319,14 +1403,38 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
  		spin_unlock(&sysctl_lock);
  		return head;
  	next:
@@ -836734,7 +892828,7 @@
  #ifdef CONFIG_SYSCTL_SYSCALL
  int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
  	       void __user *newval, size_t newlen)
-@@ -1483,18 +1602,21 @@ static __init int sysctl_init(void)
+@@ -1483,18 +1591,21 @@ static __init int sysctl_init(void)
  {
  	int err;
  	sysctl_set_parent(NULL, root_table);
@@ -836759,7 +892853,7 @@
   *
   * The members of the &struct ctl_table structure are used as follows:
   *
-@@ -1557,25 +1679,99 @@ core_initcall(sysctl_init);
+@@ -1557,25 +1668,99 @@ core_initcall(sysctl_init);
   * This routine returns %NULL on a failure to register, and a pointer
   * to the table header on success.
   */
@@ -836872,7 +892966,7 @@
  }
  
  /**
-@@ -1604,6 +1800,12 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+@@ -1604,6 +1789,12 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
  	return NULL;
  }
  
@@ -836885,7 +892979,7 @@
  void unregister_sysctl_table(struct ctl_table_header * table)
  {
  }
-@@ -2662,6 +2864,7 @@ EXPORT_SYMBOL(proc_dostring);
+@@ -2662,6 +2853,7 @@ EXPORT_SYMBOL(proc_dostring);
  EXPORT_SYMBOL(proc_doulongvec_minmax);
  EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
  EXPORT_SYMBOL(register_sysctl_table);
@@ -837215,6 +893309,18 @@
 +
 +	return 0;
 +}
+diff --git a/kernel/time.c b/kernel/time.c
+index 09d3c45..4064c05 100644
+--- a/kernel/time.c
++++ b/kernel/time.c
+@@ -129,6 +129,7 @@ static inline void warp_clock(void)
+ 	write_seqlock_irq(&xtime_lock);
+ 	wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
+ 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
++	update_xtime_cache(0);
+ 	write_sequnlock_irq(&xtime_lock);
+ 	clock_was_set();
+ }
 diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
 index 5fb139f..3e59fce 100644
 --- a/kernel/time/clockevents.c
@@ -837373,7 +893479,7 @@
  extern int tick_check_broadcast_device(struct clock_event_device *dev);
  extern int tick_is_broadcast_device(struct clock_event_device *dev);
 diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
-index cb89fa8..63f24b5 100644
+index cb89fa8..88267f0 100644
 --- a/kernel/time/tick-sched.c
 +++ b/kernel/time/tick-sched.c
 @@ -9,7 +9,7 @@
@@ -837385,7 +893491,14 @@
   */
  #include <linux/cpu.h>
  #include <linux/err.h>
-@@ -143,6 +143,44 @@ void tick_nohz_update_jiffies(void)
+@@ -137,12 +137,51 @@ void tick_nohz_update_jiffies(void)
+ 
+ 	cpu_clear(cpu, nohz_cpu_mask);
+ 	now = ktime_get();
++	ts->idle_waketime = now;
+ 
+ 	local_irq_save(flags);
+ 	tick_do_update_jiffies64(now);
  	local_irq_restore(flags);
  }
  
@@ -837430,7 +893543,7 @@
  /**
   * tick_nohz_stop_sched_tick - stop the idle tick from the idle task
   *
-@@ -153,14 +191,16 @@ void tick_nohz_update_jiffies(void)
+@@ -153,14 +192,16 @@ void tick_nohz_update_jiffies(void)
  void tick_nohz_stop_sched_tick(void)
  {
  	unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
@@ -837448,7 +893561,7 @@
  	ts = &per_cpu(tick_cpu_sched, cpu);
  
  	/*
-@@ -192,19 +232,7 @@ void tick_nohz_stop_sched_tick(void)
+@@ -192,19 +233,7 @@ void tick_nohz_stop_sched_tick(void)
  		}
  	}
  
@@ -837468,7 +893581,7 @@
  	/* Read jiffies and the time when jiffies were updated last */
  	do {
  		seq = read_seqbegin(&xtime_lock);
-@@ -216,6 +244,10 @@ void tick_nohz_stop_sched_tick(void)
+@@ -216,6 +245,10 @@ void tick_nohz_stop_sched_tick(void)
  	next_jiffies = get_next_timer_interrupt(last_jiffies);
  	delta_jiffies = next_jiffies - last_jiffies;
  
@@ -837479,7 +893592,7 @@
  	if (rcu_needs_cpu(cpu))
  		delta_jiffies = 1;
  	/*
-@@ -291,7 +323,7 @@ void tick_nohz_stop_sched_tick(void)
+@@ -291,7 +324,7 @@ void tick_nohz_stop_sched_tick(void)
  			/* Check, if the timer was already in the past */
  			if (hrtimer_active(&ts->sched_timer))
  				goto out;
@@ -837488,7 +893601,7 @@
  				goto out;
  		/*
  		 * We are past the event already. So we crossed a
-@@ -332,23 +364,22 @@ void tick_nohz_restart_sched_tick(void)
+@@ -332,23 +365,22 @@ void tick_nohz_restart_sched_tick(void)
  	int cpu = smp_processor_id();
  	struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
  	unsigned long ticks;
@@ -837520,7 +893633,15 @@
  	/*
  	 * We stopped the tick in idle. Update process times would miss the
  	 * time we slept as update_process_times does only a 1 tick
-@@ -502,14 +533,13 @@ static inline void tick_nohz_switch_to_nohz(void) { }
+@@ -369,6 +401,7 @@ void tick_nohz_restart_sched_tick(void)
+ 	 * Cancel the scheduled timer and restore the tick
+ 	 */
+ 	ts->tick_stopped  = 0;
++	ts->idle_exittime = now;
+ 	hrtimer_cancel(&ts->sched_timer);
+ 	ts->sched_timer.expires = ts->idle_tick;
+ 
+@@ -502,14 +535,13 @@ static inline void tick_nohz_switch_to_nohz(void) { }
   */
  #ifdef CONFIG_HIGH_RES_TIMERS
  /*
@@ -837536,7 +893657,7 @@
  	struct pt_regs *regs = get_irq_regs();
  	ktime_t now = ktime_get();
  	int cpu = smp_processor_id();
-@@ -547,15 +577,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
+@@ -547,15 +579,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
  			touch_softlockup_watchdog();
  			ts->idle_jiffies++;
  		}
@@ -837553,9 +893674,18 @@
  
  	/* Do not restart, when we are in the idle loop */
 diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
-index e5e466b..092a236 100644
+index e5e466b..cd5dbc4 100644
 --- a/kernel/time/timekeeping.c
 +++ b/kernel/time/timekeeping.c
+@@ -47,7 +47,7 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+ static unsigned long total_sleep_time;		/* seconds */
+ 
+ static struct timespec xtime_cache __attribute__ ((aligned (16)));
+-static inline void update_xtime_cache(u64 nsec)
++void update_xtime_cache(u64 nsec)
+ {
+ 	xtime_cache = xtime;
+ 	timespec_add_ns(&xtime_cache, nsec);
 @@ -82,13 +82,12 @@ static inline s64 __get_nsec_offset(void)
  }
  
@@ -837606,7 +893736,15 @@
  	tv->tv_sec = now.tv_sec;
  	tv->tv_usec = now.tv_nsec/1000;
  }
-@@ -198,7 +186,8 @@ static void change_clocksource(void)
+@@ -157,6 +145,7 @@ int do_settimeofday(struct timespec *tv)
+ 
+ 	set_normalized_timespec(&xtime, sec, nsec);
+ 	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
++	update_xtime_cache(0);
+ 
+ 	clock->error = 0;
+ 	ntp_clear();
+@@ -198,7 +187,8 @@ static void change_clocksource(void)
  
  	clock->error = 0;
  	clock->xtime_nsec = 0;
@@ -837616,7 +893754,7 @@
  
  	tick_clock_notify();
  
-@@ -255,7 +244,8 @@ void __init timekeeping_init(void)
+@@ -255,15 +245,16 @@ void __init timekeeping_init(void)
  	ntp_clear();
  
  	clock = clocksource_get_next();
@@ -837626,7 +893764,24 @@
  	clock->cycle_last = clocksource_read(clock);
  
  	xtime.tv_sec = sec;
-@@ -335,9 +325,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
+ 	xtime.tv_nsec = 0;
+ 	set_normalized_timespec(&wall_to_monotonic,
+ 		-xtime.tv_sec, -xtime.tv_nsec);
++	update_xtime_cache(0);
+ 	total_sleep_time = 0;
+-
+ 	write_sequnlock_irqrestore(&xtime_lock, flags);
+ }
+ 
+@@ -300,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
+ 	}
+ 	/* Make sure that we have the correct xtime reference */
+ 	timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
++	update_xtime_cache(0);
+ 	/* re-base the last cycle value */
+ 	clock->cycle_last = clocksource_read(clock);
+ 	clock->error = 0;
+@@ -335,9 +327,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
  
  /* sysfs resume/suspend bits for timekeeping */
  static struct sysdev_class timekeeping_sysclass = {
@@ -837637,6 +893792,19 @@
  };
  
  static struct sys_device device_timer = {
+diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
+index 12c5f4c..d3d94c1 100644
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -166,6 +166,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
+ 		P(idle_calls);
+ 		P(idle_sleeps);
+ 		P_ns(idle_entrytime);
++		P_ns(idle_waketime);
++		P_ns(idle_exittime);
+ 		P_ns(idle_sleeptime);
+ 		P(last_jiffies);
+ 		P(next_jiffies);
 diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c
 index c36bb7e..417da8c 100644
 --- a/kernel/time/timer_stats.c
@@ -838311,7 +894479,7 @@
  
  		case CPU_ONLINE:
 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
-index a601093..89f4035 100644
+index a601093..0d8a5a4 100644
 --- a/lib/Kconfig.debug
 +++ b/lib/Kconfig.debug
 @@ -79,6 +79,38 @@ config HEADERS_CHECK
@@ -838396,7 +894564,7 @@
 +	select STACKTRACE
 +	select SCHEDSTATS
 +	select SCHED_DEBUG
-+	depends on X86 || X86_64
++	depends on HAVE_LATENCYTOP_SUPPORT
 +	help
 +	  Enable this option if you want to use the LatencyTOP tool
 +	  to find out which userspace is blocking on what kernel operations.
@@ -840700,7 +896868,7 @@
 -	{ 0 },
 -};
 diff --git a/net/802/tr.c b/net/802/tr.c
-index 1e115e5..3f16b17 100644
+index 1e115e5..18c6647 100644
 --- a/net/802/tr.c
 +++ b/net/802/tr.c
 @@ -35,6 +35,7 @@
@@ -840711,6 +896879,15 @@
  #include <net/arp.h>
  #include <net/net_namespace.h>
  
+@@ -75,7 +76,7 @@ static DEFINE_SPINLOCK(rif_lock);
+ 
+ static struct timer_list rif_timer;
+ 
+-int sysctl_tr_rif_timeout = 60*10*HZ;
++static int sysctl_tr_rif_timeout = 60*10*HZ;
+ 
+ static inline unsigned long rif_hash(const unsigned char *addr)
+ {
 @@ -634,6 +635,26 @@ struct net_device *alloc_trdev(int sizeof_priv)
  	return alloc_netdev(sizeof_priv, "tr%d", tr_setup);
  }
@@ -841478,7 +897655,7 @@
  int vlan_netlink_init(void);
  void vlan_netlink_fini(void);
 diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
-index 4f99bb8..8059fa4 100644
+index 4f99bb8..77f04e4 100644
 --- a/net/8021q/vlan_dev.c
 +++ b/net/8021q/vlan_dev.c
 @@ -3,7 +3,7 @@
@@ -842139,7 +898316,7 @@
  	struct net_device *real_dev = vlan->real_dev;
  	int err;
  
-@@ -650,9 +558,9 @@ int vlan_dev_open(struct net_device *dev)
+@@ -650,11 +558,12 @@ int vlan_dev_open(struct net_device *dev)
  	return 0;
  }
  
@@ -842150,8 +898327,11 @@
 +	struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
  
  	dev_mc_unsync(real_dev, dev);
++	dev_unicast_unsync(real_dev, dev);
  	if (dev->flags & IFF_ALLMULTI)
-@@ -666,9 +574,9 @@ int vlan_dev_stop(struct net_device *dev)
+ 		dev_set_allmulti(real_dev, -1);
+ 	if (dev->flags & IFF_PROMISC)
+@@ -666,9 +575,9 @@ int vlan_dev_stop(struct net_device *dev)
  	return 0;
  }
  
@@ -842163,7 +898343,7 @@
  	struct sockaddr *addr = p;
  	int err;
  
-@@ -692,16 +600,16 @@ out:
+@@ -692,16 +601,16 @@ out:
  	return 0;
  }
  
@@ -842183,7 +898363,7 @@
  	case SIOCGMIIPHY:
  	case SIOCGMIIREG:
  	case SIOCSMIIREG:
-@@ -716,9 +624,9 @@ int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -716,9 +625,9 @@ int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  	return err;
  }
  
@@ -842195,15 +898375,16 @@
  
  	if (change & IFF_ALLMULTI)
  		dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
-@@ -726,8 +634,78 @@ void vlan_change_rx_flags(struct net_device *dev, int change)
+@@ -726,8 +635,80 @@ void vlan_change_rx_flags(struct net_device *dev, int change)
  		dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
  }
  
 -/** Taken from Gleb + Lennert's VLAN code, and modified... */
 -void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
-+static void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
++static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
 +{
 +	dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
++	dev_unicast_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
 +}
 +
 +/*
@@ -842270,7 +898451,8 @@
 +	dev->open		= vlan_dev_open;
 +	dev->stop		= vlan_dev_stop;
 +	dev->set_mac_address	= vlan_dev_set_mac_address;
-+	dev->set_multicast_list	= vlan_dev_set_multicast_list;
++	dev->set_rx_mode	= vlan_dev_set_rx_mode;
++	dev->set_multicast_list	= vlan_dev_set_rx_mode;
 +	dev->change_rx_flags	= vlan_dev_change_rx_flags;
 +	dev->do_ioctl		= vlan_dev_ioctl;
 +	dev->destructor		= free_netdev;
@@ -842566,6 +898748,22 @@
  #endif
  
  #endif /* !(__BEN_VLAN_PROC_INC__) */
+diff --git a/net/9p/conv.c b/net/9p/conv.c
+index aa2aa98..3fe35d5 100644
+--- a/net/9p/conv.c
++++ b/net/9p/conv.c
+@@ -128,11 +128,6 @@ static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+ 	return ret;
+ }
+ 
+-static inline void buf_put_string(struct cbuf *buf, const char *s)
+-{
+-	buf_put_stringn(buf, s, strlen(s));
+-}
+-
+ static u8 buf_get_int8(struct cbuf *buf)
+ {
+ 	u8 ret = 0;
 diff --git a/net/Kconfig b/net/Kconfig
 index ab4e6da..b6a5d45 100644
 --- a/net/Kconfig
@@ -843710,7 +899908,7 @@
  		goto err_out;
  	for (e = atm_proc_ents; e->name; e++) {
 diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
-index b4725ff..1bc0e85 100644
+index b4725ff..8fc64e3 100644
 --- a/net/ax25/af_ax25.c
 +++ b/net/ax25/af_ax25.c
 @@ -330,10 +330,9 @@ void ax25_destroy_socket(ax25_cb *ax25)
@@ -843735,7 +899933,29 @@
  		ax25->t1  = opt * HZ;
  		break;
  
-@@ -1864,6 +1863,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+@@ -1038,16 +1037,13 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+ 	int err = 0;
+ 
+ 	if (addr_len != sizeof(struct sockaddr_ax25) &&
+-	    addr_len != sizeof(struct full_sockaddr_ax25)) {
+-		/* support for old structure may go away some time */
++	    addr_len != sizeof(struct full_sockaddr_ax25))
++		/* support for old structure may go away some time
++		 * ax25_bind(): uses old (6 digipeater) socket structure.
++		 */
+ 		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
+-		    (addr_len > sizeof(struct full_sockaddr_ax25))) {
++		    (addr_len > sizeof(struct full_sockaddr_ax25)))
+ 			return -EINVAL;
+-	}
+-
+-		printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
+-			current->comm);
+-	}
+ 
+ 	if (addr->fsa_ax25.sax25_family != AF_AX25)
+ 		return -EINVAL;
+@@ -1864,6 +1860,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  #ifdef CONFIG_PROC_FS
  
  static void *ax25_info_start(struct seq_file *seq, loff_t *pos)
@@ -843743,7 +899963,7 @@
  {
  	struct ax25_cb *ax25;
  	struct hlist_node *node;
-@@ -1887,6 +1887,7 @@ static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1887,6 +1884,7 @@ static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void ax25_info_stop(struct seq_file *seq, void *v)
@@ -843956,6 +900176,110 @@
  
  	atomic_set(&conn->refcnt, 0);
  
+diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
+index 17f7fb7..e13cf5e 100644
+--- a/net/bluetooth/hci_sysfs.c
++++ b/net/bluetooth/hci_sysfs.c
+@@ -12,6 +12,8 @@
+ #undef  BT_DBG
+ #define BT_DBG(D...)
+ #endif
++static struct workqueue_struct *btaddconn;
++static struct workqueue_struct *btdelconn;
+ 
+ static inline char *typetostr(int type)
+ {
+@@ -279,6 +281,8 @@ static void add_conn(struct work_struct *work)
+ 	struct hci_conn *conn = container_of(work, struct hci_conn, work);
+ 	int i;
+ 
++	flush_workqueue(btdelconn);
++
+ 	if (device_add(&conn->dev) < 0) {
+ 		BT_ERR("Failed to register connection device");
+ 		return;
+@@ -313,7 +317,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
+ 
+ 	INIT_WORK(&conn->work, add_conn);
+ 
+-	schedule_work(&conn->work);
++	queue_work(btaddconn, &conn->work);
+ }
+ 
+ static int __match_tty(struct device *dev, void *data)
+@@ -349,7 +353,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
+ 
+ 	INIT_WORK(&conn->work, del_conn);
+ 
+-	schedule_work(&conn->work);
++	queue_work(btdelconn, &conn->work);
+ }
+ 
+ int hci_register_sysfs(struct hci_dev *hdev)
+@@ -398,28 +402,54 @@ int __init bt_sysfs_init(void)
+ {
+ 	int err;
+ 
++	btaddconn = create_singlethread_workqueue("btaddconn");
++	if (!btaddconn) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	btdelconn = create_singlethread_workqueue("btdelconn");
++	if (!btdelconn) {
++		err = -ENOMEM;
++		goto out_del;
++	}
++
+ 	bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
+-	if (IS_ERR(bt_platform))
+-		return PTR_ERR(bt_platform);
++	if (IS_ERR(bt_platform)) {
++		err = PTR_ERR(bt_platform);
++		goto out_platform;
++	}
+ 
+ 	err = bus_register(&bt_bus);
+-	if (err < 0) {
+-		platform_device_unregister(bt_platform);
+-		return err;
+-	}
++	if (err < 0)
++		goto out_bus;
+ 
+ 	bt_class = class_create(THIS_MODULE, "bluetooth");
+ 	if (IS_ERR(bt_class)) {
+-		bus_unregister(&bt_bus);
+-		platform_device_unregister(bt_platform);
+-		return PTR_ERR(bt_class);
++		err = PTR_ERR(bt_class);
++		goto out_class;
+ 	}
+ 
+ 	return 0;
++
++out_class:
++	bus_unregister(&bt_bus);
++out_bus:
++	platform_device_unregister(bt_platform);
++out_platform:
++	destroy_workqueue(btdelconn);
++out_del:
++	destroy_workqueue(btaddconn);
++out:
++	return err;
+ }
+ 
+ void bt_sysfs_cleanup(void)
+ {
++	destroy_workqueue(btaddconn);
++
++	destroy_workqueue(btdelconn);
++
+ 	class_destroy(bt_class);
+ 
+ 	bus_unregister(&bt_bus);
 diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
 index 4bbacdd..782a226 100644
 --- a/net/bluetooth/hidp/core.c
@@ -844142,7 +900466,7 @@
  	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
  }
 diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
-index 9f78a69..80014ba 100644
+index 9f78a69..1c0efd8 100644
 --- a/net/bridge/br_netfilter.c
 +++ b/net/bridge/br_netfilter.c
 @@ -353,7 +353,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
@@ -844181,16 +900505,20 @@
  		br_nf_forward_finish);
  
  	return NF_STOLEN;
-@@ -832,7 +832,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
- 	if (nf_bridge->netoutdev)
- 		realoutdev = nf_bridge->netoutdev;
- #endif
+@@ -828,11 +828,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
+ 	nf_bridge_pull_encap_header(skb);
+ 	nf_bridge_save_header(skb);
+ 
+-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+-	if (nf_bridge->netoutdev)
+-		realoutdev = nf_bridge->netoutdev;
+-#endif
 -	NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev,
 +	NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev,
  		br_nf_dev_queue_xmit);
  
  	return NF_STOLEN;
-@@ -871,7 +871,7 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
+@@ -871,7 +867,7 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
   * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
   * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
   * ip_refrag() can return NF_STOLEN. */
@@ -844199,7 +900527,7 @@
  	{ .hook = br_nf_pre_routing,
  	  .owner = THIS_MODULE,
  	  .pf = PF_BRIDGE,
-@@ -905,12 +905,12 @@ static struct nf_hook_ops br_nf_ops[] = {
+@@ -905,12 +901,12 @@ static struct nf_hook_ops br_nf_ops[] = {
  	{ .hook = ip_sabotage_in,
  	  .owner = THIS_MODULE,
  	  .pf = PF_INET,
@@ -844214,7 +900542,7 @@
  	  .priority = NF_IP6_PRI_FIRST, },
  };
  
-@@ -967,24 +967,10 @@ static ctl_table brnf_table[] = {
+@@ -967,24 +963,10 @@ static ctl_table brnf_table[] = {
  	{ .ctl_name = 0 }
  };
  
@@ -844243,7 +900571,7 @@
  };
  #endif
  
-@@ -996,7 +982,7 @@ int __init br_netfilter_init(void)
+@@ -996,7 +978,7 @@ int __init br_netfilter_init(void)
  	if (ret < 0)
  		return ret;
  #ifdef CONFIG_SYSCTL
@@ -844380,11 +900708,360 @@
  
  config BRIDGE_NF_EBTABLES
  	tristate "Ethernet Bridge tables (ebtables) support"
+diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
+index 41a7807..9853402 100644
+--- a/net/bridge/netfilter/ebt_802_3.c
++++ b/net/bridge/netfilter/ebt_802_3.c
+@@ -15,8 +15,8 @@
+ static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
+    const struct net_device *out, const void *data, unsigned int datalen)
+ {
+-	struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
+-	struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
++	const struct ebt_802_3_info *info = data;
++	const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
+ 	__be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
+ 
+ 	if (info->bitmask & EBT_802_3_SAP) {
+@@ -40,7 +40,7 @@ static struct ebt_match filter_802_3;
+ static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
++	const struct ebt_802_3_info *info = data;
+ 
+ 	if (datalen < sizeof(struct ebt_802_3_info))
+ 		return -EINVAL;
+@@ -50,8 +50,7 @@ static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_802_3 =
+-{
++static struct ebt_match filter_802_3 __read_mostly = {
+ 	.name		= EBT_802_3_MATCH,
+ 	.match		= ebt_filter_802_3,
+ 	.check		= ebt_802_3_check,
+@@ -70,4 +69,5 @@ static void __exit ebt_802_3_fini(void)
+ 
+ module_init(ebt_802_3_init);
+ module_exit(ebt_802_3_fini);
++MODULE_DESCRIPTION("Ebtables: DSAP/SSAP field and SNAP type matching");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
+index 6436d30..70b6dca 100644
+--- a/net/bridge/netfilter/ebt_among.c
++++ b/net/bridge/netfilter/ebt_among.c
+@@ -25,7 +25,7 @@ static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
+ 	const struct ebt_mac_wormhash_tuple *p;
+ 	int start, limit, i;
+ 	uint32_t cmp[2] = { 0, 0 };
+-	int key = (const unsigned char) mac[5];
++	int key = ((const unsigned char *)mac)[5];
+ 
+ 	memcpy(((char *) cmp) + 2, mac, 6);
+ 	start = wh->table[key];
+@@ -73,15 +73,18 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
+ static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
+ {
+ 	if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+-		struct iphdr _iph, *ih;
++		const struct iphdr *ih;
++		struct iphdr _iph;
+ 
+ 		ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ 		if (ih == NULL)
+ 			return -1;
+ 		*addr = ih->daddr;
+ 	} else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+-		struct arphdr _arph, *ah;
+-		__be32 buf, *bp;
++		const struct arphdr *ah;
++		struct arphdr _arph;
++		const __be32 *bp;
++		__be32 buf;
+ 
+ 		ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ 		if (ah == NULL ||
+@@ -101,15 +104,18 @@ static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
+ static int get_ip_src(const struct sk_buff *skb, __be32 *addr)
+ {
+ 	if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+-		struct iphdr _iph, *ih;
++		const struct iphdr *ih;
++		struct iphdr _iph;
+ 
+ 		ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ 		if (ih == NULL)
+ 			return -1;
+ 		*addr = ih->saddr;
+ 	} else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+-		struct arphdr _arph, *ah;
+-		__be32 buf, *bp;
++		const struct arphdr *ah;
++		struct arphdr _arph;
++		const __be32 *bp;
++		__be32 buf;
+ 
+ 		ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ 		if (ah == NULL ||
+@@ -130,7 +136,7 @@ static int ebt_filter_among(const struct sk_buff *skb,
+ 			    const struct net_device *out, const void *data,
+ 			    unsigned int datalen)
+ {
+-	struct ebt_among_info *info = (struct ebt_among_info *) data;
++	const struct ebt_among_info *info = data;
+ 	const char *dmac, *smac;
+ 	const struct ebt_mac_wormhash *wh_dst, *wh_src;
+ 	__be32 dip = 0, sip = 0;
+@@ -175,7 +181,7 @@ static int ebt_among_check(const char *tablename, unsigned int hookmask,
+ 			   const struct ebt_entry *e, void *data,
+ 			   unsigned int datalen)
+ {
+-	struct ebt_among_info *info = (struct ebt_among_info *) data;
++	const struct ebt_among_info *info = data;
+ 	int expected_length = sizeof(struct ebt_among_info);
+ 	const struct ebt_mac_wormhash *wh_dst, *wh_src;
+ 	int err;
+@@ -206,7 +212,7 @@ static int ebt_among_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_among = {
++static struct ebt_match filter_among __read_mostly = {
+ 	.name		= EBT_AMONG_MATCH,
+ 	.match		= ebt_filter_among,
+ 	.check		= ebt_among_check,
+@@ -225,4 +231,5 @@ static void __exit ebt_among_fini(void)
+ 
+ module_init(ebt_among_init);
+ module_exit(ebt_among_fini);
++MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
+index 1814139..7c535be 100644
+--- a/net/bridge/netfilter/ebt_arp.c
++++ b/net/bridge/netfilter/ebt_arp.c
+@@ -18,8 +18,9 @@
+ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
+    const struct net_device *out, const void *data, unsigned int datalen)
+ {
+-	struct ebt_arp_info *info = (struct ebt_arp_info *)data;
+-	struct arphdr _arph, *ah;
++	const struct ebt_arp_info *info = data;
++	const struct arphdr *ah;
++	struct arphdr _arph;
+ 
+ 	ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ 	if (ah == NULL)
+@@ -35,7 +36,8 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
+ 		return EBT_NOMATCH;
+ 
+ 	if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
+-		__be32 saddr, daddr, *sap, *dap;
++		const __be32 *sap, *dap;
++		__be32 saddr, daddr;
+ 
+ 		if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
+ 			return EBT_NOMATCH;
+@@ -61,7 +63,8 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
+ 	}
+ 
+ 	if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
+-		unsigned char _mac[ETH_ALEN], *mp;
++		const unsigned char *mp;
++		unsigned char _mac[ETH_ALEN];
+ 		uint8_t verdict, i;
+ 
+ 		if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
+@@ -100,7 +103,7 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
+ static int ebt_arp_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_arp_info *info = (struct ebt_arp_info *)data;
++	const struct ebt_arp_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
+ 		return -EINVAL;
+@@ -113,8 +116,7 @@ static int ebt_arp_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_arp =
+-{
++static struct ebt_match filter_arp __read_mostly = {
+ 	.name		= EBT_ARP_MATCH,
+ 	.match		= ebt_filter_arp,
+ 	.check		= ebt_arp_check,
+@@ -133,4 +135,5 @@ static void __exit ebt_arp_fini(void)
+ 
+ module_init(ebt_arp_init);
+ module_exit(ebt_arp_fini);
++MODULE_DESCRIPTION("Ebtables: ARP protocol packet match");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
+index 48a80e4..0c42795 100644
+--- a/net/bridge/netfilter/ebt_arpreply.c
++++ b/net/bridge/netfilter/ebt_arpreply.c
+@@ -19,10 +19,13 @@ static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
+-	__be32 _sip, *siptr, _dip, *diptr;
+-	struct arphdr _ah, *ap;
+-	unsigned char _sha[ETH_ALEN], *shp;
++	struct ebt_arpreply_info *info = (void *)data;
++	const __be32 *siptr, *diptr;
++	__be32 _sip, _dip;
++	const struct arphdr *ap;
++	struct arphdr _ah;
++	const unsigned char *shp;
++	unsigned char _sha[ETH_ALEN];
+ 
+ 	ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
+ 	if (ap == NULL)
+@@ -58,7 +61,7 @@ static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
+ static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
++	const struct ebt_arpreply_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
+ 		return -EINVAL;
+@@ -73,8 +76,7 @@ static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_target reply_target =
+-{
++static struct ebt_target reply_target __read_mostly = {
+ 	.name		= EBT_ARPREPLY_TARGET,
+ 	.target		= ebt_target_reply,
+ 	.check		= ebt_target_reply_check,
+@@ -93,4 +95,5 @@ static void __exit ebt_arpreply_fini(void)
+ 
+ module_init(ebt_arpreply_init);
+ module_exit(ebt_arpreply_fini);
++MODULE_DESCRIPTION("Ebtables: ARP reply target");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
+index 74262e9..e700cbf 100644
+--- a/net/bridge/netfilter/ebt_dnat.c
++++ b/net/bridge/netfilter/ebt_dnat.c
+@@ -18,7 +18,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_nat_info *info = (struct ebt_nat_info *)data;
++	const struct ebt_nat_info *info = data;
+ 
+ 	if (skb_make_writable(skb, 0))
+ 		return NF_DROP;
+@@ -30,7 +30,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
+ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_nat_info *info = (struct ebt_nat_info *)data;
++	const struct ebt_nat_info *info = data;
+ 
+ 	if (BASE_CHAIN && info->target == EBT_RETURN)
+ 		return -EINVAL;
+@@ -46,8 +46,7 @@ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_target dnat =
+-{
++static struct ebt_target dnat __read_mostly = {
+ 	.name		= EBT_DNAT_TARGET,
+ 	.target		= ebt_target_dnat,
+ 	.check		= ebt_target_dnat_check,
+@@ -66,4 +65,5 @@ static void __exit ebt_dnat_fini(void)
+ 
+ module_init(ebt_dnat_init);
+ module_exit(ebt_dnat_fini);
++MODULE_DESCRIPTION("Ebtables: Destination MAC address translation");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
+index 69f7f0a..65caa00 100644
+--- a/net/bridge/netfilter/ebt_ip.c
++++ b/net/bridge/netfilter/ebt_ip.c
+@@ -28,9 +28,11 @@ static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
+    const struct net_device *out, const void *data,
+    unsigned int datalen)
+ {
+-	struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+-	struct iphdr _iph, *ih;
+-	struct tcpudphdr _ports, *pptr;
++	const struct ebt_ip_info *info = data;
++	const struct iphdr *ih;
++	struct iphdr _iph;
++	const struct tcpudphdr *pptr;
++	struct tcpudphdr _ports;
+ 
+ 	ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ 	if (ih == NULL)
+@@ -79,7 +81,7 @@ static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
+ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_ip_info *info = (struct ebt_ip_info *)data;
++	const struct ebt_ip_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
+ 		return -EINVAL;
+@@ -105,8 +107,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_ip =
+-{
++static struct ebt_match filter_ip __read_mostly = {
+ 	.name		= EBT_IP_MATCH,
+ 	.match		= ebt_filter_ip,
+ 	.check		= ebt_ip_check,
+@@ -125,4 +126,5 @@ static void __exit ebt_ip_fini(void)
+ 
+ module_init(ebt_ip_init);
+ module_exit(ebt_ip_fini);
++MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
+index d48fa5c..8cbdc01 100644
+--- a/net/bridge/netfilter/ebt_limit.c
++++ b/net/bridge/netfilter/ebt_limit.c
+@@ -69,7 +69,7 @@ user2credits(u_int32_t user)
+ static int ebt_limit_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_limit_info *info = (struct ebt_limit_info *)data;
++	struct ebt_limit_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
+ 		return -EINVAL;
+@@ -90,8 +90,7 @@ static int ebt_limit_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match ebt_limit_reg =
+-{
++static struct ebt_match ebt_limit_reg __read_mostly = {
+ 	.name		= EBT_LIMIT_MATCH,
+ 	.match		= ebt_limit_match,
+ 	.check		= ebt_limit_check,
+@@ -110,4 +109,5 @@ static void __exit ebt_limit_fini(void)
+ 
+ module_init(ebt_limit_init);
+ module_exit(ebt_limit_fini);
++MODULE_DESCRIPTION("Ebtables: Rate-limit match");
+ MODULE_LICENSE("GPL");
 diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
-index 457815f..3be9e98 100644
+index 457815f..0b209e4 100644
 --- a/net/bridge/netfilter/ebt_log.c
 +++ b/net/bridge/netfilter/ebt_log.c
-@@ -17,6 +17,7 @@
+@@ -17,13 +17,14 @@
  #include <linux/in.h>
  #include <linux/if_arp.h>
  #include <linux/spinlock.h>
@@ -844392,7 +901069,73 @@
  
  static DEFINE_SPINLOCK(ebt_log_lock);
  
-@@ -182,7 +183,7 @@ static struct ebt_watcher log =
+ static int ebt_log_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_log_info *info = (struct ebt_log_info *)data;
++	struct ebt_log_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
+ 		return -EINVAL;
+@@ -49,7 +50,7 @@ struct arppayload
+ 	unsigned char ip_dst[4];
+ };
+ 
+-static void print_MAC(unsigned char *p)
++static void print_MAC(const unsigned char *p)
+ {
+ 	int i;
+ 
+@@ -83,7 +84,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ 
+ 	if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
+ 	   htons(ETH_P_IP)){
+-		struct iphdr _iph, *ih;
++		const struct iphdr *ih;
++		struct iphdr _iph;
+ 
+ 		ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ 		if (ih == NULL) {
+@@ -98,7 +100,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ 		    ih->protocol == IPPROTO_UDPLITE ||
+ 		    ih->protocol == IPPROTO_SCTP ||
+ 		    ih->protocol == IPPROTO_DCCP) {
+-			struct tcpudphdr _ports, *pptr;
++			const struct tcpudphdr *pptr;
++			struct tcpudphdr _ports;
+ 
+ 			pptr = skb_header_pointer(skb, ih->ihl*4,
+ 						  sizeof(_ports), &_ports);
+@@ -115,7 +118,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ 	if ((bitmask & EBT_LOG_ARP) &&
+ 	    ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) ||
+ 	     (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) {
+-		struct arphdr _arph, *ah;
++		const struct arphdr *ah;
++		struct arphdr _arph;
+ 
+ 		ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ 		if (ah == NULL) {
+@@ -131,7 +135,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ 		if (ah->ar_hrd == htons(1) &&
+ 		    ah->ar_hln == ETH_ALEN &&
+ 		    ah->ar_pln == sizeof(__be32)) {
+-			struct arppayload _arpp, *ap;
++			const struct arppayload *ap;
++			struct arppayload _arpp;
+ 
+ 			ap = skb_header_pointer(skb, sizeof(_arph),
+ 						sizeof(_arpp), &_arpp);
+@@ -159,7 +164,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_log_info *info = (struct ebt_log_info *)data;
++	const struct ebt_log_info *info = data;
+ 	struct nf_loginfo li;
+ 
+ 	li.type = NF_LOG_TYPE_LOG;
+@@ -182,7 +187,7 @@ static struct ebt_watcher log =
  	.me		= THIS_MODULE,
  };
  
@@ -844401,8 +901144,287 @@
  	.name 		= "ebt_log",
  	.logfn		= &ebt_log_packet,
  	.me		= THIS_MODULE,
+@@ -207,4 +212,5 @@ static void __exit ebt_log_fini(void)
+ 
+ module_init(ebt_log_init);
+ module_exit(ebt_log_fini);
++MODULE_DESCRIPTION("Ebtables: Packet logging to syslog");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
+index 6cba543..36723f4 100644
+--- a/net/bridge/netfilter/ebt_mark.c
++++ b/net/bridge/netfilter/ebt_mark.c
+@@ -21,7 +21,7 @@ static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++	const struct ebt_mark_t_info *info = data;
+ 	int action = info->target & -16;
+ 
+ 	if (action == MARK_SET_VALUE)
+@@ -39,7 +39,7 @@ static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
+ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++	const struct ebt_mark_t_info *info = data;
+ 	int tmp;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
+@@ -57,8 +57,7 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_target mark_target =
+-{
++static struct ebt_target mark_target __read_mostly = {
+ 	.name		= EBT_MARK_TARGET,
+ 	.target		= ebt_target_mark,
+ 	.check		= ebt_target_mark_check,
+@@ -77,4 +76,5 @@ static void __exit ebt_mark_fini(void)
+ 
+ module_init(ebt_mark_init);
+ module_exit(ebt_mark_fini);
++MODULE_DESCRIPTION("Ebtables: Packet mark modification");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
+index 6b0d216..9b0a454 100644
+--- a/net/bridge/netfilter/ebt_mark_m.c
++++ b/net/bridge/netfilter/ebt_mark_m.c
+@@ -16,7 +16,7 @@ static int ebt_filter_mark(const struct sk_buff *skb,
+    const struct net_device *in, const struct net_device *out, const void *data,
+    unsigned int datalen)
+ {
+-	struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++	const struct ebt_mark_m_info *info = data;
+ 
+ 	if (info->bitmask & EBT_MARK_OR)
+ 		return !(!!(skb->mark & info->mask) ^ info->invert);
+@@ -26,7 +26,7 @@ static int ebt_filter_mark(const struct sk_buff *skb,
+ static int ebt_mark_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++	const struct ebt_mark_m_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
+ 		return -EINVAL;
+@@ -39,8 +39,7 @@ static int ebt_mark_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_mark =
+-{
++static struct ebt_match filter_mark __read_mostly = {
+ 	.name		= EBT_MARK_MATCH,
+ 	.match		= ebt_filter_mark,
+ 	.check		= ebt_mark_check,
+@@ -59,4 +58,5 @@ static void __exit ebt_mark_m_fini(void)
+ 
+ module_init(ebt_mark_m_init);
+ module_exit(ebt_mark_m_fini);
++MODULE_DESCRIPTION("Ebtables: Packet mark match");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c
+index 4fffd70..676db32 100644
+--- a/net/bridge/netfilter/ebt_pkttype.c
++++ b/net/bridge/netfilter/ebt_pkttype.c
+@@ -18,7 +18,7 @@ static int ebt_filter_pkttype(const struct sk_buff *skb,
+    const void *data,
+    unsigned int datalen)
+ {
+-	struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++	const struct ebt_pkttype_info *info = data;
+ 
+ 	return (skb->pkt_type != info->pkt_type) ^ info->invert;
+ }
+@@ -26,7 +26,7 @@ static int ebt_filter_pkttype(const struct sk_buff *skb,
+ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++	const struct ebt_pkttype_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
+ 		return -EINVAL;
+@@ -36,8 +36,7 @@ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_pkttype =
+-{
++static struct ebt_match filter_pkttype __read_mostly = {
+ 	.name		= EBT_PKTTYPE_MATCH,
+ 	.match		= ebt_filter_pkttype,
+ 	.check		= ebt_pkttype_check,
+@@ -56,4 +55,5 @@ static void __exit ebt_pkttype_fini(void)
+ 
+ module_init(ebt_pkttype_init);
+ module_exit(ebt_pkttype_fini);
++MODULE_DESCRIPTION("Ebtables: Link layer packet type match");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
+index 422cb83..bfdf2fb 100644
+--- a/net/bridge/netfilter/ebt_redirect.c
++++ b/net/bridge/netfilter/ebt_redirect.c
+@@ -19,7 +19,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
++	const struct ebt_redirect_info *info = data;
+ 
+ 	if (skb_make_writable(skb, 0))
+ 		return NF_DROP;
+@@ -36,7 +36,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
+ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
++	const struct ebt_redirect_info *info = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
+ 		return -EINVAL;
+@@ -51,8 +51,7 @@ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmas
+ 	return 0;
+ }
+ 
+-static struct ebt_target redirect_target =
+-{
++static struct ebt_target redirect_target __read_mostly = {
+ 	.name		= EBT_REDIRECT_TARGET,
+ 	.target		= ebt_target_redirect,
+ 	.check		= ebt_target_redirect_check,
+@@ -71,4 +70,5 @@ static void __exit ebt_redirect_fini(void)
+ 
+ module_init(ebt_redirect_init);
+ module_exit(ebt_redirect_fini);
++MODULE_DESCRIPTION("Ebtables: Packet redirection to localhost");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
+index 425ac92..e252dab 100644
+--- a/net/bridge/netfilter/ebt_snat.c
++++ b/net/bridge/netfilter/ebt_snat.c
+@@ -20,7 +20,7 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_nat_info *info = (struct ebt_nat_info *) data;
++	const struct ebt_nat_info *info = data;
+ 
+ 	if (skb_make_writable(skb, 0))
+ 		return NF_DROP;
+@@ -28,7 +28,8 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
+ 	memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN);
+ 	if (!(info->target & NAT_ARP_BIT) &&
+ 	    eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+-		struct arphdr _ah, *ap;
++		const struct arphdr *ap;
++		struct arphdr _ah;
+ 
+ 		ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
+ 		if (ap == NULL)
+@@ -45,7 +46,7 @@ out:
+ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_nat_info *info = (struct ebt_nat_info *) data;
++	const struct ebt_nat_info *info = data;
+ 	int tmp;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
+@@ -67,8 +68,7 @@ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_target snat =
+-{
++static struct ebt_target snat __read_mostly = {
+ 	.name		= EBT_SNAT_TARGET,
+ 	.target		= ebt_target_snat,
+ 	.check		= ebt_target_snat_check,
+@@ -87,4 +87,5 @@ static void __exit ebt_snat_fini(void)
+ 
+ module_init(ebt_snat_init);
+ module_exit(ebt_snat_fini);
++MODULE_DESCRIPTION("Ebtables: Source MAC address translation");
+ MODULE_LICENSE("GPL");
+diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
+index 31b7736..40f36d3 100644
+--- a/net/bridge/netfilter/ebt_stp.c
++++ b/net/bridge/netfilter/ebt_stp.c
+@@ -40,10 +40,10 @@ struct stp_config_pdu {
+ #define NR16(p) (p[0] << 8 | p[1])
+ #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
+ 
+-static int ebt_filter_config(struct ebt_stp_info *info,
+-   struct stp_config_pdu *stpc)
++static int ebt_filter_config(const struct ebt_stp_info *info,
++   const struct stp_config_pdu *stpc)
+ {
+-	struct ebt_stp_config_info *c;
++	const struct ebt_stp_config_info *c;
+ 	uint16_t v16;
+ 	uint32_t v32;
+ 	int verdict, i;
+@@ -122,9 +122,10 @@ static int ebt_filter_config(struct ebt_stp_info *info,
+ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in,
+    const struct net_device *out, const void *data, unsigned int datalen)
+ {
+-	struct ebt_stp_info *info = (struct ebt_stp_info *)data;
+-	struct stp_header _stph, *sp;
+-	uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
++	const struct ebt_stp_info *info = data;
++	const struct stp_header *sp;
++	struct stp_header _stph;
++	const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
+ 
+ 	sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
+ 	if (sp == NULL)
+@@ -140,7 +141,8 @@ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in
+ 
+ 	if (sp->type == BPDU_TYPE_CONFIG &&
+ 	    info->bitmask & EBT_STP_CONFIG_MASK) {
+-		struct stp_config_pdu _stpc, *st;
++		const struct stp_config_pdu *st;
++		struct stp_config_pdu _stpc;
+ 
+ 		st = skb_header_pointer(skb, sizeof(_stph),
+ 					sizeof(_stpc), &_stpc);
+@@ -154,10 +156,10 @@ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in
+ static int ebt_stp_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_stp_info *info = (struct ebt_stp_info *)data;
+-	int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
+-	uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+-	uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
++	const struct ebt_stp_info *info = data;
++	const unsigned int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
++	const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
++	const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ 
+ 	if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
+ 	    !(info->bitmask & EBT_STP_MASK))
+@@ -172,8 +174,7 @@ static int ebt_stp_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_stp =
+-{
++static struct ebt_match filter_stp __read_mostly = {
+ 	.name		= EBT_STP_MATCH,
+ 	.match		= ebt_filter_stp,
+ 	.check		= ebt_stp_check,
+@@ -192,4 +193,5 @@ static void __exit ebt_stp_fini(void)
+ 
+ module_init(ebt_stp_init);
+ module_exit(ebt_stp_fini);
++MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match");
+ MODULE_LICENSE("GPL");
 diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
-index e7cfd30..8e7b00b 100644
+index e7cfd30..2d4c9ef 100644
 --- a/net/bridge/netfilter/ebt_ulog.c
 +++ b/net/bridge/netfilter/ebt_ulog.c
 @@ -38,6 +38,7 @@
@@ -844413,7 +901435,33 @@
  #include <net/sock.h>
  #include "../br_private.h"
  
-@@ -278,7 +279,7 @@ static struct ebt_watcher ulog = {
+@@ -248,7 +249,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
+    const struct net_device *in, const struct net_device *out,
+    const void *data, unsigned int datalen)
+ {
+-	struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
++	const struct ebt_ulog_info *uloginfo = data;
+ 
+ 	ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL);
+ }
+@@ -257,7 +258,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
+ static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
+    const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
++	struct ebt_ulog_info *uloginfo = data;
+ 
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
+ 	    uloginfo->nlgroup > 31)
+@@ -271,14 +272,14 @@ static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
+ 	return 0;
+ }
+ 
+-static struct ebt_watcher ulog = {
++static struct ebt_watcher ulog __read_mostly = {
+ 	.name		= EBT_ULOG_WATCHER,
+ 	.watcher	= ebt_ulog,
+ 	.check		= ebt_ulog_check,
  	.me		= THIS_MODULE,
  };
  
@@ -844431,7 +901479,7 @@
  
  	if (ret == 0)
  		nf_log_register(PF_BRIDGE, &ebt_ulog_logger);
-@@ -332,7 +333,7 @@ static void __exit ebt_ulog_fini(void)
+@@ -332,12 +333,11 @@ static void __exit ebt_ulog_fini(void)
  		}
  		spin_unlock_bh(&ub->lock);
  	}
@@ -844440,11 +901488,24 @@
  }
  
  module_init(ebt_ulog_init);
+ module_exit(ebt_ulog_fini);
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Bart De Schuymer <bdschuym at pandora.be>");
+-MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
+-		   " frames");
++MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG");
 diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
-index a43c697..0ddf749 100644
+index a43c697..ab60b0d 100644
 --- a/net/bridge/netfilter/ebt_vlan.c
 +++ b/net/bridge/netfilter/ebt_vlan.c
-@@ -37,9 +37,7 @@ MODULE_LICENSE("GPL");
+@@ -31,15 +31,12 @@ static int debug;
+ module_param(debug, int, 0);
+ MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
+ MODULE_AUTHOR("Nick Fedchik <nick at fedchik.org.ua>");
+-MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
+-		   MODULE_VERS);
++MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match");
+ MODULE_LICENSE("GPL");
  
  
  #define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
@@ -844454,6 +901515,36 @@
  #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;}
  
  static int
+@@ -48,8 +45,9 @@ ebt_filter_vlan(const struct sk_buff *skb,
+ 		const struct net_device *out,
+ 		const void *data, unsigned int datalen)
+ {
+-	struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
+-	struct vlan_hdr _frame, *fp;
++	const struct ebt_vlan_info *info = data;
++	const struct vlan_hdr *fp;
++	struct vlan_hdr _frame;
+ 
+ 	unsigned short TCI;	/* Whole TCI, given from parsed frame */
+ 	unsigned short id;	/* VLAN ID, given from frame TCI */
+@@ -93,7 +91,7 @@ ebt_check_vlan(const char *tablename,
+ 	       unsigned int hooknr,
+ 	       const struct ebt_entry *e, void *data, unsigned int datalen)
+ {
+-	struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
++	struct ebt_vlan_info *info = data;
+ 
+ 	/* Parameters buffer overflow check */
+ 	if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
+@@ -171,7 +169,7 @@ ebt_check_vlan(const char *tablename,
+ 	return 0;
+ }
+ 
+-static struct ebt_match filter_vlan = {
++static struct ebt_match filter_vlan __read_mostly = {
+ 	.name		= EBT_VLAN_MATCH,
+ 	.match		= ebt_filter_vlan,
+ 	.check		= ebt_check_vlan,
 diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
 index 210493f..fb81090 100644
 --- a/net/bridge/netfilter/ebtable_filter.c
@@ -848683,7 +905774,7 @@
  
  EXPORT_SYMBOL(skb_kill_datagram);
 diff --git a/net/core/dev.c b/net/core/dev.c
-index 0879f52..c9c593e 100644
+index 0879f52..9549417 100644
 --- a/net/core/dev.c
 +++ b/net/core/dev.c
 @@ -150,8 +150,11 @@
@@ -848849,7 +905940,132 @@
  {
  	rcu_read_unlock();
  }
-@@ -3505,7 +3496,7 @@ static int dev_new_index(struct net *net)
+@@ -2761,12 +2752,15 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
+ 		printk(KERN_INFO "device %s %s promiscuous mode\n",
+ 		       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
+ 							       "left");
+-		audit_log(current->audit_context, GFP_ATOMIC,
+-			AUDIT_ANOM_PROMISCUOUS,
+-			"dev=%s prom=%d old_prom=%d auid=%u",
+-			dev->name, (dev->flags & IFF_PROMISC),
+-			(old_flags & IFF_PROMISC),
+-			audit_get_loginuid(current->audit_context));
++		if (audit_enabled)
++			audit_log(current->audit_context, GFP_ATOMIC,
++				AUDIT_ANOM_PROMISCUOUS,
++				"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
++				dev->name, (dev->flags & IFF_PROMISC),
++				(old_flags & IFF_PROMISC),
++				audit_get_loginuid(current),
++				current->uid, current->gid,
++				audit_get_sessionid(current));
+ 
+ 		if (dev->change_rx_flags)
+ 			dev->change_rx_flags(dev, IFF_PROMISC);
+@@ -2971,6 +2965,102 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
+ }
+ EXPORT_SYMBOL(dev_unicast_add);
+ 
++int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
++		    struct dev_addr_list **from, int *from_count)
++{
++	struct dev_addr_list *da, *next;
++	int err = 0;
++
++	da = *from;
++	while (da != NULL) {
++		next = da->next;
++		if (!da->da_synced) {
++			err = __dev_addr_add(to, to_count,
++					     da->da_addr, da->da_addrlen, 0);
++			if (err < 0)
++				break;
++			da->da_synced = 1;
++			da->da_users++;
++		} else if (da->da_users == 1) {
++			__dev_addr_delete(to, to_count,
++					  da->da_addr, da->da_addrlen, 0);
++			__dev_addr_delete(from, from_count,
++					  da->da_addr, da->da_addrlen, 0);
++		}
++		da = next;
++	}
++	return err;
++}
++
++void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
++		       struct dev_addr_list **from, int *from_count)
++{
++	struct dev_addr_list *da, *next;
++
++	da = *from;
++	while (da != NULL) {
++		next = da->next;
++		if (da->da_synced) {
++			__dev_addr_delete(to, to_count,
++					  da->da_addr, da->da_addrlen, 0);
++			da->da_synced = 0;
++			__dev_addr_delete(from, from_count,
++					  da->da_addr, da->da_addrlen, 0);
++		}
++		da = next;
++	}
++}
++
++/**
++ *	dev_unicast_sync - Synchronize device's unicast list to another device
++ *	@to: destination device
++ *	@from: source device
++ *
++ *	Add newly added addresses to the destination device and release
++ *	addresses that have no users left. The source device must be
++ *	locked by netif_tx_lock_bh.
++ *
++ *	This function is intended to be called from the dev->set_rx_mode
++ *	function of layered software devices.
++ */
++int dev_unicast_sync(struct net_device *to, struct net_device *from)
++{
++	int err = 0;
++
++	netif_tx_lock_bh(to);
++	err = __dev_addr_sync(&to->uc_list, &to->uc_count,
++			      &from->uc_list, &from->uc_count);
++	if (!err)
++		__dev_set_rx_mode(to);
++	netif_tx_unlock_bh(to);
++	return err;
++}
++EXPORT_SYMBOL(dev_unicast_sync);
++
++/**
++ *	dev_unicast_unsync - Remove synchronized addresses from the destination
++ *			     device
++ *	@to: destination device
++ *	@from: source device
++ *
++ *	Remove all addresses that were added to the destination device by
++ *	dev_unicast_sync(). This function is intended to be called from the
++ *	dev->stop function of layered software devices.
++ */
++void dev_unicast_unsync(struct net_device *to, struct net_device *from)
++{
++	netif_tx_lock_bh(from);
++	netif_tx_lock_bh(to);
++
++	__dev_addr_unsync(&to->uc_list, &to->uc_count,
++			  &from->uc_list, &from->uc_count);
++	__dev_set_rx_mode(to);
++
++	netif_tx_unlock_bh(to);
++	netif_tx_unlock_bh(from);
++}
++EXPORT_SYMBOL(dev_unicast_unsync);
++
+ static void __dev_addr_discard(struct dev_addr_list **list)
+ {
+ 	struct dev_addr_list *tmp;
+@@ -3505,7 +3595,7 @@ static int dev_new_index(struct net *net)
  
  /* Delayed registration/unregisteration */
  static DEFINE_SPINLOCK(net_todo_list_lock);
@@ -848858,7 +906074,7 @@
  
  static void net_set_todo(struct net_device *dev)
  {
-@@ -3984,6 +3975,8 @@ void synchronize_net(void)
+@@ -3984,6 +4074,8 @@ void synchronize_net(void)
  
  void unregister_netdevice(struct net_device *dev)
  {
@@ -848867,7 +906083,7 @@
  	rollback_registered(dev);
  	/* Finish processing unregister after unlock */
  	net_set_todo(dev);
-@@ -4416,7 +4409,7 @@ static int __init net_dev_init(void)
+@@ -4416,7 +4508,7 @@ static int __init net_dev_init(void)
  		goto out;
  
  	INIT_LIST_HEAD(&ptype_all);
@@ -848877,10 +906093,72 @@
  
  	if (register_pernet_subsys(&netdev_net_ops))
 diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
-index 69fff16..cadbfbf 100644
+index 69fff16..cec5825 100644
 --- a/net/core/dev_mcast.c
 +++ b/net/core/dev_mcast.c
-@@ -186,8 +186,9 @@ EXPORT_SYMBOL(dev_mc_unsync);
+@@ -113,32 +113,15 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
+  * 	locked by netif_tx_lock_bh.
+  *
+  *	This function is intended to be called from the dev->set_multicast_list
+- *	function of layered software devices.
++ *	or dev->set_rx_mode function of layered software devices.
+  */
+ int dev_mc_sync(struct net_device *to, struct net_device *from)
+ {
+-	struct dev_addr_list *da, *next;
+ 	int err = 0;
+ 
+ 	netif_tx_lock_bh(to);
+-	da = from->mc_list;
+-	while (da != NULL) {
+-		next = da->next;
+-		if (!da->da_synced) {
+-			err = __dev_addr_add(&to->mc_list, &to->mc_count,
+-					     da->da_addr, da->da_addrlen, 0);
+-			if (err < 0)
+-				break;
+-			da->da_synced = 1;
+-			da->da_users++;
+-		} else if (da->da_users == 1) {
+-			__dev_addr_delete(&to->mc_list, &to->mc_count,
+-					  da->da_addr, da->da_addrlen, 0);
+-			__dev_addr_delete(&from->mc_list, &from->mc_count,
+-					  da->da_addr, da->da_addrlen, 0);
+-		}
+-		da = next;
+-	}
++	err = __dev_addr_sync(&to->mc_list, &to->mc_count,
++			      &from->mc_list, &from->mc_count);
+ 	if (!err)
+ 		__dev_set_rx_mode(to);
+ 	netif_tx_unlock_bh(to);
+@@ -160,23 +143,11 @@ EXPORT_SYMBOL(dev_mc_sync);
+  */
+ void dev_mc_unsync(struct net_device *to, struct net_device *from)
+ {
+-	struct dev_addr_list *da, *next;
+-
+ 	netif_tx_lock_bh(from);
+ 	netif_tx_lock_bh(to);
+ 
+-	da = from->mc_list;
+-	while (da != NULL) {
+-		next = da->next;
+-		if (da->da_synced) {
+-			__dev_addr_delete(&to->mc_list, &to->mc_count,
+-					  da->da_addr, da->da_addrlen, 0);
+-			da->da_synced = 0;
+-			__dev_addr_delete(&from->mc_list, &from->mc_count,
+-					  da->da_addr, da->da_addrlen, 0);
+-		}
+-		da = next;
+-	}
++	__dev_addr_unsync(&to->mc_list, &to->mc_count,
++			  &from->mc_list, &from->mc_count);
+ 	__dev_set_rx_mode(to);
+ 
+ 	netif_tx_unlock_bh(to);
+@@ -186,8 +157,9 @@ EXPORT_SYMBOL(dev_mc_unsync);
  
  #ifdef CONFIG_PROC_FS
  static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -848891,7 +906169,7 @@
  	struct net_device *dev;
  	loff_t off = 0;
  
-@@ -206,6 +207,7 @@ static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -206,6 +178,7 @@ static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void dev_mc_seq_stop(struct seq_file *seq, void *v)
@@ -848899,7 +906177,7 @@
  {
  	read_unlock(&dev_base_lock);
  }
-@@ -241,26 +243,8 @@ static const struct seq_operations dev_mc_seq_ops = {
+@@ -241,26 +214,8 @@ static const struct seq_operations dev_mc_seq_ops = {
  
  static int dev_mc_seq_open(struct inode *inode, struct file *file)
  {
@@ -848928,7 +906206,7 @@
  }
  
  static const struct file_operations dev_mc_seq_fops = {
-@@ -268,7 +252,7 @@ static const struct file_operations dev_mc_seq_fops = {
+@@ -268,7 +223,7 @@ static const struct file_operations dev_mc_seq_fops = {
  	.open    = dev_mc_seq_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
@@ -850311,10 +907589,19 @@
  				np->dev->npinfo = NULL;
  			}
 diff --git a/net/core/pktgen.c b/net/core/pktgen.c
-index 285ec3e..eebccdb 100644
+index 285ec3e..bfcdfae 100644
 --- a/net/core/pktgen.c
 +++ b/net/core/pktgen.c
-@@ -397,62 +397,6 @@ struct pktgen_thread {
+@@ -170,8 +170,6 @@
+ 
+ #define VERSION  "pktgen v2.69: Packet Generator for packet performance testing.\n"
+ 
+-/* The buckets are exponential in 'width' */
+-#define LAT_BUCKETS_MAX 32
+ #define IP_NAME_SZ 32
+ #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
+ #define MPLS_STACK_BOTTOM htonl(0x00000100)
+@@ -397,62 +395,6 @@ struct pktgen_thread {
  #define REMOVE 1
  #define FIND   0
  
@@ -850377,7 +907664,7 @@
  /** Convert to micro-seconds */
  static inline __u64 tv_to_us(const struct timeval *tv)
  {
-@@ -461,51 +405,13 @@ static inline __u64 tv_to_us(const struct timeval *tv)
+@@ -461,51 +403,13 @@ static inline __u64 tv_to_us(const struct timeval *tv)
  	return us;
  }
  
@@ -850430,7 +907717,15 @@
  /* old include end */
  
  static char version[] __initdata = VERSION;
-@@ -2358,9 +2264,11 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
+@@ -2138,7 +2042,6 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
+ 	__u64 now;
+ 
+ 	start = now = getCurUs();
+-	printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
+ 	while (now < spin_until_us) {
+ 		/* TODO: optimize sleeping behavior */
+ 		if (spin_until_us - now > jiffies_to_usecs(1) + 1)
+@@ -2358,9 +2261,11 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
  					t = random32() % (imx - imn) + imn;
  					s = htonl(t);
  
@@ -850906,7 +908201,7 @@
   *	skb_store_bits - store bits from kernel buffer to skb
   *	@skb: destination buffer
 diff --git a/net/core/sock.c b/net/core/sock.c
-index c519b43..1c4b1cd 100644
+index c519b43..433715f 100644
 --- a/net/core/sock.c
 +++ b/net/core/sock.c
 @@ -154,7 +154,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
@@ -850980,7 +908275,32 @@
  		break;
  	case SO_BROADCAST:
  		sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
-@@ -1105,7 +1112,9 @@ void sock_rfree(struct sk_buff *skb)
+@@ -660,6 +667,13 @@ set_rcvbuf:
+ 		else
+ 			clear_bit(SOCK_PASSSEC, &sock->flags);
+ 		break;
++	case SO_MARK:
++		if (!capable(CAP_NET_ADMIN))
++			ret = -EPERM;
++		else {
++			sk->sk_mark = val;
++		}
++		break;
+ 
+ 		/* We implement the SO_SNDLOWAT etc to
+ 		   not be settable (1003.1g 5.3) */
+@@ -829,6 +843,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
+ 	case SO_PEERSEC:
+ 		return security_socket_getpeersec_stream(sock, optval, optlen, len);
+ 
++	case SO_MARK:
++		v.val = sk->sk_mark;
++		break;
++
+ 	default:
+ 		return -ENOPROTOOPT;
+ 	}
+@@ -1105,7 +1123,9 @@ void sock_rfree(struct sk_buff *skb)
  {
  	struct sock *sk = skb->sk;
  
@@ -850990,7 +908310,7 @@
  }
  
  
-@@ -1382,6 +1391,103 @@ int sk_wait_data(struct sock *sk, long *timeo)
+@@ -1382,6 +1402,103 @@ int sk_wait_data(struct sock *sk, long *timeo)
  
  EXPORT_SYMBOL(sk_wait_data);
  
@@ -851094,7 +908414,7 @@
  /*
   * Set of default routines for initialising struct proto_ops when
   * the protocol does not support a particular function. In certain
-@@ -1496,7 +1602,7 @@ static void sock_def_error_report(struct sock *sk)
+@@ -1496,7 +1613,7 @@ static void sock_def_error_report(struct sock *sk)
  	read_lock(&sk->sk_callback_lock);
  	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
  		wake_up_interruptible(sk->sk_sleep);
@@ -851103,7 +908423,7 @@
  	read_unlock(&sk->sk_callback_lock);
  }
  
-@@ -1505,7 +1611,7 @@ static void sock_def_readable(struct sock *sk, int len)
+@@ -1505,7 +1622,7 @@ static void sock_def_readable(struct sock *sk, int len)
  	read_lock(&sk->sk_callback_lock);
  	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
  		wake_up_interruptible(sk->sk_sleep);
@@ -851112,7 +908432,7 @@
  	read_unlock(&sk->sk_callback_lock);
  }
  
-@@ -1522,7 +1628,7 @@ static void sock_def_write_space(struct sock *sk)
+@@ -1522,7 +1639,7 @@ static void sock_def_write_space(struct sock *sk)
  
  		/* Should agree with poll, otherwise some programs break */
  		if (sock_writeable(sk))
@@ -851121,7 +908441,7 @@
  	}
  
  	read_unlock(&sk->sk_callback_lock);
-@@ -1537,7 +1643,7 @@ void sk_send_sigurg(struct sock *sk)
+@@ -1537,7 +1654,7 @@ void sk_send_sigurg(struct sock *sk)
  {
  	if (sk->sk_socket && sk->sk_socket->file)
  		if (send_sigurg(&sk->sk_socket->file->f_owner))
@@ -851130,7 +908450,7 @@
  }
  
  void sk_reset_timer(struct sock *sk, struct timer_list* timer,
-@@ -1611,6 +1717,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
+@@ -1611,6 +1728,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
  	sk->sk_stamp = ktime_set(-1L, -1L);
  
  	atomic_set(&sk->sk_refcnt, 1);
@@ -851138,7 +908458,7 @@
  }
  
  void fastcall lock_sock_nested(struct sock *sk, int subclass)
-@@ -1801,65 +1908,15 @@ EXPORT_SYMBOL(sk_common_release);
+@@ -1801,65 +1919,15 @@ EXPORT_SYMBOL(sk_common_release);
  static DEFINE_RWLOCK(proto_list_lock);
  static LIST_HEAD(proto_list);
  
@@ -851207,7 +908527,7 @@
  
  	if (alloc_slab) {
  		prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
-@@ -1927,7 +1984,7 @@ out_free_sock_slab:
+@@ -1927,7 +1995,7 @@ out_free_sock_slab:
  	kmem_cache_destroy(prot->slab);
  	prot->slab = NULL;
  out_free_inuse:
@@ -851216,7 +908536,7 @@
  out:
  	return -ENOBUFS;
  }
-@@ -1940,7 +1997,8 @@ void proto_unregister(struct proto *prot)
+@@ -1940,7 +2008,8 @@ void proto_unregister(struct proto *prot)
  	list_del(&prot->node);
  	write_unlock(&proto_list_lock);
  
@@ -851226,7 +908546,7 @@
  	if (prot->slab != NULL) {
  		kmem_cache_destroy(prot->slab);
  		prot->slab = NULL;
-@@ -1967,6 +2025,7 @@ EXPORT_SYMBOL(proto_unregister);
+@@ -1967,6 +2036,7 @@ EXPORT_SYMBOL(proto_unregister);
  
  #ifdef CONFIG_PROC_FS
  static void *proto_seq_start(struct seq_file *seq, loff_t *pos)
@@ -851234,7 +908554,7 @@
  {
  	read_lock(&proto_list_lock);
  	return seq_list_start_head(&proto_list, *pos);
-@@ -1978,6 +2037,7 @@ static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1978,6 +2048,7 @@ static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void proto_seq_stop(struct seq_file *seq, void *v)
@@ -855805,9 +913125,18 @@
  		}
  	} else if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) {
 diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
-index db17b83..9e38b0d 100644
+index db17b83..c982ad8 100644
 --- a/net/dccp/ipv4.c
 +++ b/net/dccp/ipv4.c
+@@ -218,7 +218,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
+ 		return;
+ 	}
+ 
+-	sk = inet_lookup(&dccp_hashinfo, iph->daddr, dh->dccph_dport,
++	sk = inet_lookup(&init_net, &dccp_hashinfo, iph->daddr, dh->dccph_dport,
+ 			 iph->saddr, dh->dccph_sport, inet_iif(skb));
+ 	if (sk == NULL) {
+ 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
 @@ -408,7 +408,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
  
  	dccp_sync_mss(newsk, dst_mtu(dst));
@@ -855817,6 +913146,15 @@
  	__inet_inherit_port(&dccp_hashinfo, sk, newsk);
  
  	return newsk;
+@@ -436,7 +436,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
+ 	if (req != NULL)
+ 		return dccp_check_req(sk, skb, req, prev);
+ 
+-	nsk = inet_lookup_established(&dccp_hashinfo,
++	nsk = inet_lookup_established(&init_net, &dccp_hashinfo,
+ 				      iph->saddr, dh->dccph_sport,
+ 				      iph->daddr, dh->dccph_dport,
+ 				      inet_iif(skb));
 @@ -469,7 +469,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
  			  };
  
@@ -855850,10 +913188,39 @@
  	dreq->dreq_isr	   = dcb->dccpd_seq;
  	dreq->dreq_iss	   = dccp_v4_init_sequence(skb);
  	dreq->dreq_service = service;
+@@ -817,7 +817,7 @@ static int dccp_v4_rcv(struct sk_buff *skb)
+ 
+ 	/* Step 2:
+ 	 *	Look up flow ID in table and get corresponding socket */
+-	sk = __inet_lookup(&dccp_hashinfo,
++	sk = __inet_lookup(&init_net, &dccp_hashinfo,
+ 			   iph->saddr, dh->dccph_sport,
+ 			   iph->daddr, dh->dccph_dport, inet_iif(skb));
+ 	/*
 diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
-index 87c98fb..f42b75c 100644
+index 87c98fb..ed0a005 100644
 --- a/net/dccp/ipv6.c
 +++ b/net/dccp/ipv6.c
+@@ -101,8 +101,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	int err;
+ 	__u64 seq;
+ 
+-	sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
+-			  &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
++	sk = inet6_lookup(&init_net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
++			&hdr->saddr, dh->dccph_sport, inet6_iif(skb));
+ 
+ 	if (sk == NULL) {
+ 		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+@@ -366,7 +366,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
+ 	if (req != NULL)
+ 		return dccp_check_req(sk, skb, req, prev);
+ 
+-	nsk = __inet6_lookup_established(&dccp_hashinfo,
++	nsk = __inet6_lookup_established(&init_net, &dccp_hashinfo,
+ 					 &iph->saddr, dh->dccph_sport,
+ 					 &iph->daddr, ntohs(dh->dccph_dport),
+ 					 inet6_iif(skb));
 @@ -415,11 +415,12 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
  	if (req == NULL)
  		goto drop;
@@ -855878,6 +913245,15 @@
  	dreq->dreq_isr	   = dcb->dccpd_seq;
  	dreq->dreq_iss	   = dccp_v6_init_sequence(skb);
  	dreq->dreq_service = service;
+@@ -797,7 +797,7 @@ static int dccp_v6_rcv(struct sk_buff *skb)
+ 
+ 	/* Step 2:
+ 	 *	Look up flow ID in table and get corresponding socket */
+-	sk = __inet6_lookup(&dccp_hashinfo, &ipv6_hdr(skb)->saddr,
++	sk = __inet6_lookup(&init_net, &dccp_hashinfo, &ipv6_hdr(skb)->saddr,
+ 			    dh->dccph_sport,
+ 			    &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
+ 			    inet6_iif(skb));
 @@ -994,7 +994,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
  	if (final_p)
  		ipv6_addr_copy(&fl.fl6_dst, final_p);
@@ -857634,7 +915010,7 @@
  	/* PBCC */
  	/* Not widely used */
 diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
-index 9f9fd2c..24e2b72 100644
+index 9f9fd2c..19880b0 100644
 --- a/net/ipv4/Kconfig
 +++ b/net/ipv4/Kconfig
 @@ -85,6 +85,13 @@ endchoice
@@ -857651,6 +915027,14 @@
  config IP_MULTIPLE_TABLES
  	bool "IP: policy routing"
  	depends on IP_ADVANCED_ROUTER
+@@ -336,6 +343,7 @@ config INET_ESP
+ 	tristate "IP: ESP transformation"
+ 	select XFRM
+ 	select CRYPTO
++	select CRYPTO_AEAD
+ 	select CRYPTO_HMAC
+ 	select CRYPTO_MD5
+ 	select CRYPTO_CBC
 diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
 index 93fe396..ad40ef3 100644
 --- a/net/ipv4/Makefile
@@ -857814,7 +915198,7 @@
  out_udp:
  	tcp4_proc_exit();
 diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
-index 5fc346d..d76803a 100644
+index 5fc346d..9d4555e 100644
 --- a/net/ipv4/ah4.c
 +++ b/net/ipv4/ah4.c
 @@ -169,6 +169,8 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
@@ -857849,8 +915233,17 @@
  	skb->network_header += ah_hlen;
  	memcpy(skb_network_header(skb), work_buf, ihl);
  	skb->transport_header = skb->network_header;
+@@ -295,7 +300,7 @@ static void ah_destroy(struct xfrm_state *x)
+ }
+ 
+ 
+-static struct xfrm_type ah_type =
++static const struct xfrm_type ah_type =
+ {
+ 	.description	= "AH4",
+ 	.owner		= THIS_MODULE,
 diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
-index 08174a2..5976c59 100644
+index 08174a2..8e17f65 100644
 --- a/net/ipv4/arp.c
 +++ b/net/ipv4/arp.c
 @@ -211,7 +211,7 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
@@ -857942,7 +915335,30 @@
  		return 0;
  
  	n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
-@@ -777,7 +775,7 @@ static int arp_process(struct sk_buff *skb)
+@@ -560,8 +558,9 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
+  */
+ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ 			   struct net_device *dev, __be32 src_ip,
+-			   unsigned char *dest_hw, unsigned char *src_hw,
+-			   unsigned char *target_hw)
++			   const unsigned char *dest_hw,
++			   const unsigned char *src_hw,
++			   const unsigned char *target_hw)
+ {
+ 	struct sk_buff *skb;
+ 	struct arphdr *arp;
+@@ -674,8 +673,8 @@ void arp_xmit(struct sk_buff *skb)
+  */
+ void arp_send(int type, int ptype, __be32 dest_ip,
+ 	      struct net_device *dev, __be32 src_ip,
+-	      unsigned char *dest_hw, unsigned char *src_hw,
+-	      unsigned char *target_hw)
++	      const unsigned char *dest_hw, const unsigned char *src_hw,
++	      const unsigned char *target_hw)
+ {
+ 	struct sk_buff *skb;
+ 
+@@ -777,7 +776,7 @@ static int arp_process(struct sk_buff *skb)
   *	Check for bad requests for 127.x.x.x and requests for multicast
   *	addresses.  If this is one such, delete it.
   */
@@ -857951,7 +915367,7 @@
  		goto out;
  
  /*
-@@ -806,8 +804,8 @@ static int arp_process(struct sk_buff *skb)
+@@ -806,8 +805,8 @@ static int arp_process(struct sk_buff *skb)
  	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
  	if (sip == 0) {
  		if (arp->ar_op == htons(ARPOP_REQUEST) &&
@@ -857962,7 +915378,7 @@
  			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
  				 dev->dev_addr, sha);
  		goto out;
-@@ -825,7 +823,7 @@ static int arp_process(struct sk_buff *skb)
+@@ -825,7 +824,7 @@ static int arp_process(struct sk_buff *skb)
  				int dont_send = 0;
  
  				if (!dont_send)
@@ -857971,7 +915387,7 @@
  				if (!dont_send && IN_DEV_ARPFILTER(in_dev))
  					dont_send |= arp_filter(sip,tip,dev);
  				if (!dont_send)
-@@ -835,9 +833,8 @@ static int arp_process(struct sk_buff *skb)
+@@ -835,9 +834,8 @@ static int arp_process(struct sk_buff *skb)
  			}
  			goto out;
  		} else if (IN_DEV_FORWARD(in_dev)) {
@@ -857983,7 +915399,7 @@
  				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
  				if (n)
  					neigh_release(n);
-@@ -860,14 +857,14 @@ static int arp_process(struct sk_buff *skb)
+@@ -860,14 +858,14 @@ static int arp_process(struct sk_buff *skb)
  
  	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
  
@@ -858000,7 +915416,7 @@
  			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
  	}
  
-@@ -952,44 +949,60 @@ out_of_mem:
+@@ -952,44 +950,60 @@ out_of_mem:
   *	Set (create) an ARP cache entry.
   */
  
@@ -858088,7 +915504,7 @@
  			return err;
  		dev = rt->u.dst.dev;
  		ip_rt_put(rt);
-@@ -1066,37 +1079,37 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
+@@ -1066,37 +1080,37 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
  	return err;
  }
  
@@ -858148,7 +915564,7 @@
  			return err;
  		dev = rt->u.dst.dev;
  		ip_rt_put(rt);
-@@ -1119,7 +1132,7 @@ static int arp_req_delete(struct arpreq *r, struct net_device * dev)
+@@ -1119,7 +1133,7 @@ static int arp_req_delete(struct arpreq *r, struct net_device * dev)
   *	Handle an ARP layer I/O control request.
   */
  
@@ -858157,7 +915573,7 @@
  {
  	int err;
  	struct arpreq r;
-@@ -1151,7 +1164,7 @@ int arp_ioctl(unsigned int cmd, void __user *arg)
+@@ -1151,7 +1165,7 @@ int arp_ioctl(unsigned int cmd, void __user *arg)
  	rtnl_lock();
  	if (r.arp_dev[0]) {
  		err = -ENODEV;
@@ -858166,7 +915582,7 @@
  			goto out;
  
  		/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
-@@ -1167,10 +1180,10 @@ int arp_ioctl(unsigned int cmd, void __user *arg)
+@@ -1167,10 +1181,10 @@ int arp_ioctl(unsigned int cmd, void __user *arg)
  
  	switch (cmd) {
  	case SIOCDARP:
@@ -858179,7 +915595,7 @@
  		break;
  	case SIOCGARP:
  		err = arp_req_get(&r, dev);
-@@ -1359,8 +1372,8 @@ static const struct seq_operations arp_seq_ops = {
+@@ -1359,8 +1373,8 @@ static const struct seq_operations arp_seq_ops = {
  
  static int arp_seq_open(struct inode *inode, struct file *file)
  {
@@ -858190,7 +915606,7 @@
  }
  
  static const struct file_operations arp_seq_fops = {
-@@ -1368,7 +1381,7 @@ static const struct file_operations arp_seq_fops = {
+@@ -1368,7 +1382,7 @@ static const struct file_operations arp_seq_fops = {
  	.open           = arp_seq_open,
  	.read           = seq_read,
  	.llseek         = seq_lseek,
@@ -858420,17 +915836,20 @@
  			oif = inet->mc_index;
  		if (!saddr)
 diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
-index b42f746..21f71bf 100644
+index b42f746..f282b26 100644
 --- a/net/ipv4/devinet.c
 +++ b/net/ipv4/devinet.c
-@@ -62,6 +62,7 @@
+@@ -62,8 +62,9 @@
  #include <net/route.h>
  #include <net/ip_fib.h>
  #include <net/rtnetlink.h>
 +#include <net/net_namespace.h>
  
- struct ipv4_devconf ipv4_devconf = {
+-struct ipv4_devconf ipv4_devconf = {
++static struct ipv4_devconf ipv4_devconf = {
  	.data = {
+ 		[NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
+ 		[NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
 @@ -82,7 +83,8 @@ static struct ipv4_devconf ipv4_devconf_dflt = {
  	},
  };
@@ -858551,7 +915970,64 @@
  	if (in_dev == NULL) {
  		err = -ENODEV;
  		goto errout;
-@@ -560,10 +560,14 @@ errout:
+@@ -485,46 +485,41 @@ errout:
+ 	return err;
+ }
+ 
+-static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
++static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
+ {
+ 	struct nlattr *tb[IFA_MAX+1];
+ 	struct in_ifaddr *ifa;
+ 	struct ifaddrmsg *ifm;
+ 	struct net_device *dev;
+ 	struct in_device *in_dev;
+-	int err = -EINVAL;
++	int err;
+ 
+ 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
+ 	if (err < 0)
+ 		goto errout;
+ 
+ 	ifm = nlmsg_data(nlh);
+-	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
+-		err = -EINVAL;
++	err = -EINVAL;
++	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
+ 		goto errout;
+-	}
+ 
+-	dev = __dev_get_by_index(&init_net, ifm->ifa_index);
+-	if (dev == NULL) {
+-		err = -ENODEV;
++	dev = __dev_get_by_index(net, ifm->ifa_index);
++	err = -ENODEV;
++	if (dev == NULL)
+ 		goto errout;
+-	}
+ 
+ 	in_dev = __in_dev_get_rtnl(dev);
+-	if (in_dev == NULL) {
+-		err = -ENOBUFS;
++	err = -ENOBUFS;
++	if (in_dev == NULL)
+ 		goto errout;
+-	}
+ 
+ 	ifa = inet_alloc_ifa();
+-	if (ifa == NULL) {
++	if (ifa == NULL)
+ 		/*
+ 		 * A potential indev allocation can be left alive, it stays
+ 		 * assigned to its device and is destroy with it.
+ 		 */
+-		err = -ENOBUFS;
+ 		goto errout;
+-	}
+ 
+ 	ipv4_devconf_setall(in_dev);
+ 	in_dev_hold(in_dev);
+@@ -560,11 +555,15 @@ errout:
  
  static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  {
@@ -858560,13 +916036,15 @@
  
  	ASSERT_RTNL();
  
+-	ifa = rtm_to_ifaddr(nlh);
 +	if (net != &init_net)
 +		return -EINVAL;
 +
- 	ifa = rtm_to_ifaddr(nlh);
++	ifa = rtm_to_ifaddr(net, nlh);
  	if (IS_ERR(ifa))
  		return PTR_ERR(ifa);
-@@ -579,7 +583,7 @@ static __inline__ int inet_abc_len(__be32 addr)
+ 
+@@ -579,7 +578,7 @@ static __inline__ int inet_abc_len(__be32 addr)
  {
  	int rc = -1;	/* Something else, probably a multicast. */
  
@@ -858575,7 +916053,7 @@
  		rc = 0;
  	else {
  		__u32 haddr = ntohl(addr);
-@@ -964,28 +968,25 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
+@@ -964,28 +963,25 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
  
  /*
   * Confirm that local IP address exists using wildcards:
@@ -858613,7 +916091,7 @@
  		if ((in_dev = __in_dev_get_rcu(dev))) {
  			addr = confirm_addr_indev(in_dev, dst, local, scope);
  			if (addr)
-@@ -1106,13 +1107,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
+@@ -1106,13 +1102,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
  		 */
  		inetdev_changename(dev, in_dev);
  
@@ -858629,7 +916107,7 @@
  		break;
  	}
  out:
-@@ -1174,12 +1170,16 @@ nla_put_failure:
+@@ -1174,15 +1165,19 @@ nla_put_failure:
  
  static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
  {
@@ -858645,17 +916123,31 @@
 +
  	s_ip_idx = ip_idx = cb->args[1];
  	idx = 0;
- 	for_each_netdev(&init_net, dev) {
-@@ -1228,28 +1228,50 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
+-	for_each_netdev(&init_net, dev) {
++	for_each_netdev(net, dev) {
+ 		if (idx < s_idx)
+ 			goto cont;
+ 		if (idx > s_idx)
+@@ -1216,7 +1211,9 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
+ 	struct sk_buff *skb;
+ 	u32 seq = nlh ? nlh->nlmsg_seq : 0;
+ 	int err = -ENOBUFS;
++	struct net *net;
+ 
++	net = ifa->ifa_dev->dev->nd_net;
+ 	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
+ 	if (skb == NULL)
+ 		goto errout;
+@@ -1228,30 +1225,52 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
  		kfree_skb(skb);
  		goto errout;
  	}
 -	err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
-+	err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
++	err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
  errout:
  	if (err < 0)
 -		rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
-+		rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_IFADDR, err);
++		rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
  }
  
  #ifdef CONFIG_SYSCTL
@@ -858674,11 +916166,11 @@
  		if (in_dev && !test_bit(i, in_dev->cnf.state))
 -			in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];
 +			in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
-+		rcu_read_unlock();
-+	}
-+	read_unlock(&dev_base_lock);
-+}
-+
+ 		rcu_read_unlock();
+ 	}
+ 	read_unlock(&dev_base_lock);
+ }
+ 
 +static void inet_forward_change(struct net *net)
 +{
 +	struct net_device *dev;
@@ -858694,15 +916186,17 @@
 +		in_dev = __in_dev_get_rcu(dev);
 +		if (in_dev)
 +			IN_DEV_CONF_SET(in_dev, FORWARDING, on);
- 		rcu_read_unlock();
- 	}
- 	read_unlock(&dev_base_lock);
++		rcu_read_unlock();
++	}
++	read_unlock(&dev_base_lock);
 +
 +	rt_cache_flush(0);
- }
- 
++}
++
  static int devinet_conf_proc(ctl_table *ctl, int write,
-@@ -1260,12 +1282,13 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
+ 			     struct file* filp, void __user *buffer,
+ 			     size_t *lenp, loff_t *ppos)
+@@ -1260,12 +1279,13 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
  
  	if (write) {
  		struct ipv4_devconf *cnf = ctl->extra1;
@@ -858718,7 +916212,7 @@
  	}
  
  	return ret;
-@@ -1276,6 +1299,7 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
+@@ -1276,6 +1296,7 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
  			       void __user *newval, size_t newlen)
  {
  	struct ipv4_devconf *cnf;
@@ -858726,7 +916220,7 @@
  	int *valp = table->data;
  	int new;
  	int i;
-@@ -1311,38 +1335,17 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
+@@ -1311,38 +1332,17 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
  	*valp = new;
  
  	cnf = table->extra1;
@@ -858768,7 +916262,7 @@
  static int devinet_sysctl_forward(ctl_table *ctl, int write,
  				  struct file* filp, void __user *buffer,
  				  size_t *lenp, loff_t *ppos)
-@@ -1352,9 +1355,11 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
+@@ -1352,9 +1352,11 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
  	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
  
  	if (write && *valp != val) {
@@ -858783,7 +916277,7 @@
  			rt_cache_flush(0);
  	}
  
-@@ -1419,11 +1424,8 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
+@@ -1419,11 +1421,8 @@ int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
  
  static struct devinet_sysctl_table {
  	struct ctl_table_header *sysctl_header;
@@ -858797,7 +916291,7 @@
  } devinet_sysctl = {
  	.devinet_vars = {
  		DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
-@@ -1455,62 +1457,32 @@ static struct devinet_sysctl_table {
+@@ -1455,62 +1454,32 @@ static struct devinet_sysctl_table {
  		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
  					      "promote_secondaries"),
  	},
@@ -858877,7 +916371,7 @@
  	}
  
  	/*
-@@ -1518,56 +1490,183 @@ static void devinet_sysctl_register(struct in_device *in_dev,
+@@ -1518,56 +1487,183 @@ static void devinet_sysctl_register(struct in_device *in_dev,
  	 * by sysctl and we wouldn't want anyone to change it under our feet
  	 * (see SIOCSIFNAME).
  	 */
@@ -858922,7 +916416,13 @@
  
 -static void devinet_sysctl_unregister(struct ipv4_devconf *p)
 +static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
-+{
+ {
+-	if (p->sysctl) {
+-		struct devinet_sysctl_table *t = p->sysctl;
+-		p->sysctl = NULL;
+-		unregister_sysctl_table(t->sysctl_header);
+-		kfree(t->devinet_dev[0].procname);
+-		kfree(t);
 +	struct devinet_sysctl_table *t = cnf->sysctl;
 +
 +	if (t == NULL)
@@ -858972,13 +916472,7 @@
 +#endif
 +
 +static __net_init int devinet_init_net(struct net *net)
- {
--	if (p->sysctl) {
--		struct devinet_sysctl_table *t = p->sysctl;
--		p->sysctl = NULL;
--		unregister_sysctl_table(t->sysctl_header);
--		kfree(t->devinet_dev[0].procname);
--		kfree(t);
++{
 +	int err;
 +	struct ipv4_devconf *all, *dflt;
 +#ifdef CONFIG_SYSCTL
@@ -859090,78 +916584,358 @@
  
  EXPORT_SYMBOL(in_dev_finish_destroy);
 diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
-index 1738113..28ea5c7 100644
+index 1738113..258d176 100644
 --- a/net/ipv4/esp4.c
 +++ b/net/ipv4/esp4.c
-@@ -163,7 +163,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
- 	u8 nexthdr[2];
- 	struct scatterlist *sg;
- 	int padlen;
--	int err;
-+	int err = -EINVAL;
- 
- 	if (!pskb_may_pull(skb, sizeof(*esph)))
- 		goto out;
-@@ -171,28 +171,31 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
- 	if (elen <= 0 || (elen & (blksize-1)))
- 		goto out;
+@@ -1,27 +1,118 @@
++#include <crypto/aead.h>
++#include <crypto/authenc.h>
+ #include <linux/err.h>
+ #include <linux/module.h>
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+ #include <net/esp.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+ #include <linux/kernel.h>
+ #include <linux/pfkeyv2.h>
+-#include <linux/random.h>
++#include <linux/rtnetlink.h>
++#include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <linux/in6.h>
+ #include <net/icmp.h>
+ #include <net/protocol.h>
+ #include <net/udp.h>
  
-+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
-+		goto out;
-+	nfrags = err;
++struct esp_skb_cb {
++	struct xfrm_skb_cb xfrm;
++	void *tmp;
++};
 +
-+	skb->ip_summed = CHECKSUM_NONE;
++#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
 +
-+	spin_lock(&x->lock);
++/*
++ * Allocate an AEAD request structure with extra space for SG and IV.
++ *
++ * For alignment considerations the IV is placed at the front, followed
++ * by the request and finally the SG list.
++ *
++ * TODO: Use spare space in skb for this where possible.
++ */
++static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
++{
++	unsigned int len;
++
++	len = crypto_aead_ivsize(aead);
++	if (len) {
++		len += crypto_aead_alignmask(aead) &
++		       ~(crypto_tfm_ctx_alignment() - 1);
++		len = ALIGN(len, crypto_tfm_ctx_alignment());
++	}
++
++	len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
++	len = ALIGN(len, __alignof__(struct scatterlist));
++
++	len += sizeof(struct scatterlist) * nfrags;
++
++	return kmalloc(len, GFP_ATOMIC);
++}
++
++static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
++{
++	return crypto_aead_ivsize(aead) ?
++	       PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
++}
++
++static inline struct aead_givcrypt_request *esp_tmp_givreq(
++	struct crypto_aead *aead, u8 *iv)
++{
++	struct aead_givcrypt_request *req;
++
++	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
++				crypto_tfm_ctx_alignment());
++	aead_givcrypt_set_tfm(req, aead);
++	return req;
++}
++
++static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
++{
++	struct aead_request *req;
++
++	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
++				crypto_tfm_ctx_alignment());
++	aead_request_set_tfm(req, aead);
++	return req;
++}
++
++static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
++					     struct aead_request *req)
++{
++	return (void *)ALIGN((unsigned long)(req + 1) +
++			     crypto_aead_reqsize(aead),
++			     __alignof__(struct scatterlist));
++}
++
++static inline struct scatterlist *esp_givreq_sg(
++	struct crypto_aead *aead, struct aead_givcrypt_request *req)
++{
++	return (void *)ALIGN((unsigned long)(req + 1) +
++			     crypto_aead_reqsize(aead),
++			     __alignof__(struct scatterlist));
++}
++
++static void esp_output_done(struct crypto_async_request *base, int err)
++{
++	struct sk_buff *skb = base->data;
 +
- 	/* If integrity check is required, do this. */
- 	if (esp->auth.icv_full_len) {
- 		u8 sum[alen];
++	kfree(ESP_SKB_CB(skb)->tmp);
++	xfrm_output_resume(skb, err);
++}
++
+ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+ 	int err;
+ 	struct ip_esp_hdr *esph;
+-	struct crypto_blkcipher *tfm;
+-	struct blkcipher_desc desc;
++	struct crypto_aead *aead;
++	struct aead_givcrypt_request *req;
++	struct scatterlist *sg;
++	struct scatterlist *asg;
+ 	struct esp_data *esp;
+ 	struct sk_buff *trailer;
++	void *tmp;
++	u8 *iv;
+ 	u8 *tail;
+ 	int blksize;
+ 	int clen;
+@@ -36,18 +127,27 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
+ 	clen = skb->len;
+ 
+ 	esp = x->data;
+-	alen = esp->auth.icv_trunc_len;
+-	tfm = esp->conf.tfm;
+-	desc.tfm = tfm;
+-	desc.flags = 0;
+-	blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
++	aead = esp->aead;
++	alen = crypto_aead_authsize(aead);
++
++	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
+ 	clen = ALIGN(clen + 2, blksize);
+-	if (esp->conf.padlen)
+-		clen = ALIGN(clen, esp->conf.padlen);
++	if (esp->padlen)
++		clen = ALIGN(clen, esp->padlen);
++
++	if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
++		goto error;
++	nfrags = err;
  
- 		err = esp_mac_digest(esp, skb, 0, skb->len - alen);
- 		if (err)
--			goto out;
-+			goto unlock;
+-	if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0)
++	tmp = esp_alloc_tmp(aead, nfrags + 1);
++	if (!tmp)
+ 		goto error;
  
- 		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
- 			BUG();
++	iv = esp_tmp_iv(aead, tmp);
++	req = esp_tmp_givreq(aead, iv);
++	asg = esp_givreq_sg(aead, req);
++	sg = asg + 1;
++
+ 	/* Fill padding... */
+ 	tail = skb_tail_pointer(trailer);
+ 	do {
+@@ -56,28 +156,34 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
+ 			tail[i] = i + 1;
+ 	} while (0);
+ 	tail[clen - skb->len - 2] = (clen - skb->len) - 2;
+-	pskb_put(skb, trailer, clen - skb->len);
++	tail[clen - skb->len - 1] = *skb_mac_header(skb);
++	pskb_put(skb, trailer, clen - skb->len + alen);
+ 
+ 	skb_push(skb, -skb_network_offset(skb));
+ 	esph = ip_esp_hdr(skb);
+-	*(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
+ 	*skb_mac_header(skb) = IPPROTO_ESP;
+ 
+-	spin_lock_bh(&x->lock);
+-
+ 	/* this is non-NULL only with UDP Encapsulation */
+ 	if (x->encap) {
+ 		struct xfrm_encap_tmpl *encap = x->encap;
+ 		struct udphdr *uh;
+ 		__be32 *udpdata32;
++		unsigned int sport, dport;
++		int encap_type;
++
++		spin_lock_bh(&x->lock);
++		sport = encap->encap_sport;
++		dport = encap->encap_dport;
++		encap_type = encap->encap_type;
++		spin_unlock_bh(&x->lock);
+ 
+ 		uh = (struct udphdr *)esph;
+-		uh->source = encap->encap_sport;
+-		uh->dest = encap->encap_dport;
+-		uh->len = htons(skb->len + alen - skb_transport_offset(skb));
++		uh->source = sport;
++		uh->dest = dport;
++		uh->len = htons(skb->len - skb_transport_offset(skb));
+ 		uh->check = 0;
  
- 		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
--			x->stats.integrity_failed++;
--			goto out;
-+			err = -EBADMSG;
-+			goto unlock;
- 		}
- 	}
+-		switch (encap->encap_type) {
++		switch (encap_type) {
+ 		default:
+ 		case UDP_ENCAP_ESPINUDP:
+ 			esph = (struct ip_esp_hdr *)(uh + 1);
+@@ -95,140 +201,59 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
+ 	esph->spi = x->id.spi;
+ 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
+ 
+-	if (esp->conf.ivlen) {
+-		if (unlikely(!esp->conf.ivinitted)) {
+-			get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
+-			esp->conf.ivinitted = 1;
+-		}
+-		crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+-	}
+-
+-	do {
+-		struct scatterlist *sg = &esp->sgbuf[0];
+-
+-		if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
+-			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+-			if (!sg)
+-				goto unlock;
+-		}
+-		sg_init_table(sg, nfrags);
+-		skb_to_sgvec(skb, sg,
+-			     esph->enc_data +
+-			     esp->conf.ivlen -
+-			     skb->data, clen);
+-		err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
+-		if (unlikely(sg != &esp->sgbuf[0]))
+-			kfree(sg);
+-	} while (0);
+-
+-	if (unlikely(err))
+-		goto unlock;
+-
+-	if (esp->conf.ivlen) {
+-		memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
+-		crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+-	}
++	sg_init_table(sg, nfrags);
++	skb_to_sgvec(skb, sg,
++		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
++		     clen + alen);
++	sg_init_one(asg, esph, sizeof(*esph));
++
++	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
++	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
++	aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
++	aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
++
++	ESP_SKB_CB(skb)->tmp = tmp;
++	err = crypto_aead_givencrypt(req);
++	if (err == -EINPROGRESS)
++		goto error;
  
--	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
+-	if (esp->auth.icv_full_len) {
+-		err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
+-				     sizeof(*esph) + esp->conf.ivlen + clen);
+-		memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
+-	}
++	if (err == -EBUSY)
++		err = NET_XMIT_DROP;
+ 
+-unlock:
+-	spin_unlock_bh(&x->lock);
++	kfree(tmp);
+ 
+ error:
+ 	return err;
+ }
+ 
+-/*
+- * Note: detecting truncated vs. non-truncated authentication data is very
+- * expensive, so we only support truncated data, which is the recommended
+- * and common case.
+- */
+-static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
++static int esp_input_done2(struct sk_buff *skb, int err)
+ {
+ 	struct iphdr *iph;
+-	struct ip_esp_hdr *esph;
++	struct xfrm_state *x = xfrm_input_state(skb);
+ 	struct esp_data *esp = x->data;
+-	struct crypto_blkcipher *tfm = esp->conf.tfm;
+-	struct blkcipher_desc desc = { .tfm = tfm };
+-	struct sk_buff *trailer;
+-	int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+-	int alen = esp->auth.icv_trunc_len;
+-	int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
+-	int nfrags;
++	struct crypto_aead *aead = esp->aead;
++	int alen = crypto_aead_authsize(aead);
++	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
++	int elen = skb->len - hlen;
+ 	int ihl;
+ 	u8 nexthdr[2];
+-	struct scatterlist *sg;
+ 	int padlen;
+-	int err;
+-
+-	if (!pskb_may_pull(skb, sizeof(*esph)))
 -		goto out;
 -
--	skb->ip_summed = CHECKSUM_NONE;
+-	if (elen <= 0 || (elen & (blksize-1)))
+-		goto out;
 -
- 	esph = (struct ip_esp_hdr *)skb->data;
+-	/* If integrity check is required, do this. */
+-	if (esp->auth.icv_full_len) {
+-		u8 sum[alen];
+-
+-		err = esp_mac_digest(esp, skb, 0, skb->len - alen);
+-		if (err)
+-			goto out;
+-
+-		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
+-			BUG();
+-
+-		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
+-			x->stats.integrity_failed++;
+-			goto out;
+-		}
+-	}
+-
+-	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
+-		goto out;
  
- 	/* Get ivec. This can be wrong, check against another impls. */
-@@ -202,9 +205,10 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
- 	sg = &esp->sgbuf[0];
+-	skb->ip_summed = CHECKSUM_NONE;
++	kfree(ESP_SKB_CB(skb)->tmp);
  
- 	if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
-+		err = -ENOMEM;
- 		sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- 		if (!sg)
+-	esph = (struct ip_esp_hdr *)skb->data;
+-
+-	/* Get ivec. This can be wrong, check against another impls. */
+-	if (esp->conf.ivlen)
+-		crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
+-
+-	sg = &esp->sgbuf[0];
+-
+-	if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
+-		sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+-		if (!sg)
 -			goto out;
-+			goto unlock;
- 	}
- 	sg_init_table(sg, nfrags);
- 	skb_to_sgvec(skb, sg,
-@@ -213,12 +217,17 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
- 	err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
- 	if (unlikely(sg != &esp->sgbuf[0]))
- 		kfree(sg);
-+
-+unlock:
-+	spin_unlock(&x->lock);
-+
+-	}
+-	sg_init_table(sg, nfrags);
+-	skb_to_sgvec(skb, sg,
+-		     sizeof(*esph) + esp->conf.ivlen,
+-		     elen);
+-	err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
+-	if (unlikely(sg != &esp->sgbuf[0]))
+-		kfree(sg);
  	if (unlikely(err))
 -		return err;
 +		goto out;
@@ -859171,10 +916945,106 @@
  
 +	err = -EINVAL;
  	padlen = nexthdr[0];
- 	if (padlen+2 >= elen)
+-	if (padlen+2 >= elen)
++	if (padlen + 2 + alen >= elen)
  		goto out;
-@@ -276,7 +285,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
- 	return nexthdr[1];
+ 
+ 	/* ... check padding bits here. Silly. :-) */
+ 
+-	/* RFC4303: Drop dummy packets without any error */
+-	if (nexthdr[1] == IPPROTO_NONE)
+-		goto out;
+-
+ 	iph = ip_hdr(skb);
+ 	ihl = iph->ihl * 4;
+ 
+@@ -270,23 +295,100 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+ 	}
+ 
+ 	pskb_trim(skb, skb->len - alen - padlen - 2);
+-	__skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
++	__skb_pull(skb, hlen);
+ 	skb_set_transport_header(skb, -ihl);
+ 
+-	return nexthdr[1];
++	err = nexthdr[1];
++
++	/* RFC4303: Drop dummy packets without any error */
++	if (err == IPPROTO_NONE)
++		err = -EINVAL;
++
++out:
++	return err;
++}
++
++static void esp_input_done(struct crypto_async_request *base, int err)
++{
++	struct sk_buff *skb = base->data;
++
++	xfrm_input_resume(skb, esp_input_done2(skb, err));
++}
++
++/*
++ * Note: detecting truncated vs. non-truncated authentication data is very
++ * expensive, so we only support truncated data, which is the recommended
++ * and common case.
++ */
++static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++	struct ip_esp_hdr *esph;
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead = esp->aead;
++	struct aead_request *req;
++	struct sk_buff *trailer;
++	int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
++	int nfrags;
++	void *tmp;
++	u8 *iv;
++	struct scatterlist *sg;
++	struct scatterlist *asg;
++	int err = -EINVAL;
++
++	if (!pskb_may_pull(skb, sizeof(*esph)))
++		goto out;
++
++	if (elen <= 0)
++		goto out;
++
++	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
++		goto out;
++	nfrags = err;
++
++	err = -ENOMEM;
++	tmp = esp_alloc_tmp(aead, nfrags + 1);
++	if (!tmp)
++		goto out;
++
++	ESP_SKB_CB(skb)->tmp = tmp;
++	iv = esp_tmp_iv(aead, tmp);
++	req = esp_tmp_req(aead, iv);
++	asg = esp_req_sg(aead, req);
++	sg = asg + 1;
++
++	skb->ip_summed = CHECKSUM_NONE;
++
++	esph = (struct ip_esp_hdr *)skb->data;
++
++	/* Get ivec. This can be wrong, check against another impls. */
++	iv = esph->enc_data;
++
++	sg_init_table(sg, nfrags);
++	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
++	sg_init_one(asg, esph, sizeof(*esph));
++
++	aead_request_set_callback(req, 0, esp_input_done, skb);
++	aead_request_set_crypt(req, sg, sg, elen, iv);
++	aead_request_set_assoc(req, asg, sizeof(*esph));
++
++	err = crypto_aead_decrypt(req);
++	if (err == -EINPROGRESS)
++		goto out;
++
++	err = esp_input_done2(skb, err);
  
  out:
 -	return -EINVAL;
@@ -859182,8 +917052,243 @@
  }
  
  static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
+ {
+ 	struct esp_data *esp = x->data;
+-	u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+-	u32 align = max_t(u32, blksize, esp->conf.padlen);
++	u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
++	u32 align = max_t(u32, blksize, esp->padlen);
+ 	u32 rem;
+ 
+-	mtu -= x->props.header_len + esp->auth.icv_trunc_len;
++	mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
+ 	rem = mtu & (align - 1);
+ 	mtu &= ~(align - 1);
+ 
+@@ -333,80 +435,143 @@ static void esp_destroy(struct xfrm_state *x)
+ 	if (!esp)
+ 		return;
+ 
+-	crypto_free_blkcipher(esp->conf.tfm);
+-	esp->conf.tfm = NULL;
+-	kfree(esp->conf.ivec);
+-	esp->conf.ivec = NULL;
+-	crypto_free_hash(esp->auth.tfm);
+-	esp->auth.tfm = NULL;
+-	kfree(esp->auth.work_icv);
+-	esp->auth.work_icv = NULL;
++	crypto_free_aead(esp->aead);
+ 	kfree(esp);
+ }
+ 
+-static int esp_init_state(struct xfrm_state *x)
++static int esp_init_aead(struct xfrm_state *x)
+ {
+-	struct esp_data *esp = NULL;
+-	struct crypto_blkcipher *tfm;
+-	u32 align;
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead;
++	int err;
++
++	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
++	err = PTR_ERR(aead);
++	if (IS_ERR(aead))
++		goto error;
++
++	esp->aead = aead;
+ 
++	err = crypto_aead_setkey(aead, x->aead->alg_key,
++				 (x->aead->alg_key_len + 7) / 8);
++	if (err)
++		goto error;
++
++	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
++	if (err)
++		goto error;
++
++error:
++	return err;
++}
++
++static int esp_init_authenc(struct xfrm_state *x)
++{
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead;
++	struct crypto_authenc_key_param *param;
++	struct rtattr *rta;
++	char *key;
++	char *p;
++	char authenc_name[CRYPTO_MAX_ALG_NAME];
++	unsigned int keylen;
++	int err;
++
++	err = -EINVAL;
+ 	if (x->ealg == NULL)
+ 		goto error;
+ 
+-	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+-	if (esp == NULL)
+-		return -ENOMEM;
++	err = -ENAMETOOLONG;
++	if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
++		     x->aalg ? x->aalg->alg_name : "digest_null",
++		     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
++		goto error;
++
++	aead = crypto_alloc_aead(authenc_name, 0, 0);
++	err = PTR_ERR(aead);
++	if (IS_ERR(aead))
++		goto error;
++
++	esp->aead = aead;
++
++	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
++		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
++	err = -ENOMEM;
++	key = kmalloc(keylen, GFP_KERNEL);
++	if (!key)
++		goto error;
++
++	p = key;
++	rta = (void *)p;
++	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
++	rta->rta_len = RTA_LENGTH(sizeof(*param));
++	param = RTA_DATA(rta);
++	p += RTA_SPACE(sizeof(*param));
+ 
+ 	if (x->aalg) {
+ 		struct xfrm_algo_desc *aalg_desc;
+-		struct crypto_hash *hash;
+-
+-		hash = crypto_alloc_hash(x->aalg->alg_name, 0,
+-					 CRYPTO_ALG_ASYNC);
+-		if (IS_ERR(hash))
+-			goto error;
+ 
+-		esp->auth.tfm = hash;
+-		if (crypto_hash_setkey(hash, x->aalg->alg_key,
+-				       (x->aalg->alg_key_len + 7) / 8))
+-			goto error;
++		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
++		p += (x->aalg->alg_key_len + 7) / 8;
+ 
+ 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ 		BUG_ON(!aalg_desc);
+ 
++		err = -EINVAL;
+ 		if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+-		    crypto_hash_digestsize(hash)) {
++		    crypto_aead_authsize(aead)) {
+ 			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
+ 				 x->aalg->alg_name,
+-				 crypto_hash_digestsize(hash),
++				 crypto_aead_authsize(aead),
+ 				 aalg_desc->uinfo.auth.icv_fullbits/8);
+-			goto error;
++			goto free_key;
+ 		}
+ 
+-		esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
+-		esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
+-
+-		esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
+-		if (!esp->auth.work_icv)
+-			goto error;
++		err = crypto_aead_setauthsize(
++			aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
++		if (err)
++			goto free_key;
+ 	}
+ 
+-	tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
+-	if (IS_ERR(tfm))
+-		goto error;
+-	esp->conf.tfm = tfm;
+-	esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
+-	esp->conf.padlen = 0;
+-	if (esp->conf.ivlen) {
+-		esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
+-		if (unlikely(esp->conf.ivec == NULL))
+-			goto error;
+-		esp->conf.ivinitted = 0;
+-	}
+-	if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
+-				    (x->ealg->alg_key_len + 7) / 8))
++	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
++	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
++
++	err = crypto_aead_setkey(aead, key, keylen);
++
++free_key:
++	kfree(key);
++
++error:
++	return err;
++}
++
++static int esp_init_state(struct xfrm_state *x)
++{
++	struct esp_data *esp;
++	struct crypto_aead *aead;
++	u32 align;
++	int err;
++
++	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
++	if (esp == NULL)
++		return -ENOMEM;
++
++	x->data = esp;
++
++	if (x->aead)
++		err = esp_init_aead(x);
++	else
++		err = esp_init_authenc(x);
++
++	if (err)
+ 		goto error;
+-	x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
++
++	aead = esp->aead;
++
++	esp->padlen = 0;
++
++	x->props.header_len = sizeof(struct ip_esp_hdr) +
++			      crypto_aead_ivsize(aead);
+ 	if (x->props.mode == XFRM_MODE_TUNNEL)
+ 		x->props.header_len += sizeof(struct iphdr);
+ 	else if (x->props.mode == XFRM_MODE_BEET)
+@@ -425,21 +590,17 @@ static int esp_init_state(struct xfrm_state *x)
+ 			break;
+ 		}
+ 	}
+-	x->data = esp;
+-	align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+-	if (esp->conf.padlen)
+-		align = max_t(u32, align, esp->conf.padlen);
+-	x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len;
+-	return 0;
++
++	align = ALIGN(crypto_aead_blocksize(aead), 4);
++	if (esp->padlen)
++		align = max_t(u32, align, esp->padlen);
++	x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
+ 
+ error:
+-	x->data = esp;
+-	esp_destroy(x);
+-	x->data = NULL;
+-	return -EINVAL;
++	return err;
+ }
+ 
+-static struct xfrm_type esp_type =
++static const struct xfrm_type esp_type =
+ {
+ 	.description	= "ESP4",
+ 	.owner		= THIS_MODULE,
 diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
-index 97abf93..d282618 100644
+index 97abf93..86ff271 100644
 --- a/net/ipv4/fib_frontend.c
 +++ b/net/ipv4/fib_frontend.c
 @@ -47,59 +47,65 @@
@@ -859609,7 +917714,7 @@
  			return;
  		}
  	}
-@@ -747,7 +801,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
+@@ -747,15 +801,15 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
  		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
  
  		/* Check, that this local address finally disappeared. */
@@ -859618,11 +917723,12 @@
  			/* And the last, but not the least thing.
  			   We must flush stray FIB entries.
  
-@@ -755,7 +809,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
+ 			   First of all, we scan fib_info list searching
  			   for stray nexthop entries, then ignite fib_flush.
  			*/
- 			if (fib_sync_down(ifa->ifa_local, NULL, 0))
+-			if (fib_sync_down(ifa->ifa_local, NULL, 0))
 -				fib_flush();
++			if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local))
 +				fib_flush(dev->nd_net);
  		}
  	}
@@ -859655,10 +917761,13 @@
  	NETLINK_CB(skb).dst_group = 0;  /* unicast */
 -	netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT);
 +	netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
-+}
-+
+ }
+ 
+-static void nl_fib_lookup_init(void)
 +static int nl_fib_lookup_init(struct net *net)
-+{
+ {
+-	fibnl = netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0,
+-				      nl_fib_input, NULL, THIS_MODULE);
 +	struct sock *sk;
 +	sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
 +				   nl_fib_input, NULL, THIS_MODULE);
@@ -859666,21 +917775,19 @@
 +		return -EAFNOSUPPORT;
 +	net->ipv4.fibnl = sk;
 +	return 0;
- }
- 
--static void nl_fib_lookup_init(void)
++}
++
 +static void nl_fib_lookup_exit(struct net *net)
- {
--	fibnl = netlink_kernel_create(&init_net, NETLINK_FIB_LOOKUP, 0,
--				      nl_fib_input, NULL, THIS_MODULE);
++{
 +	netlink_kernel_release(net->ipv4.fibnl);
 +	net->ipv4.fibnl = NULL;
  }
  
  static void fib_disable_ip(struct net_device *dev, int force)
  {
- 	if (fib_sync_down(0, dev, force))
+-	if (fib_sync_down(0, dev, force))
 -		fib_flush();
++	if (fib_sync_down_dev(dev, force))
 +		fib_flush(dev->nd_net);
  	rt_cache_flush(0);
  	arp_ifdown(dev);
@@ -859695,13 +917802,14 @@
  	if (event == NETDEV_UNREGISTER) {
  		fib_disable_ip(dev, 2);
  		return NOTIFY_DONE;
-@@ -909,23 +973,92 @@ static struct notifier_block fib_netdev_notifier = {
+@@ -909,23 +973,100 @@ static struct notifier_block fib_netdev_notifier = {
  	.notifier_call =fib_netdev_event,
  };
  
 -void __init ip_fib_init(void)
 +static int __net_init ip_fib_net_init(struct net *net)
  {
++	int err;
  	unsigned int i;
  
 +	net->ipv4.fib_table_hash = kzalloc(
@@ -859712,9 +917820,16 @@
  	for (i = 0; i < FIB_TABLE_HASHSZ; i++)
 -		INIT_HLIST_HEAD(&fib_table_hash[i]);
 +		INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
++
++	err = fib4_rules_init(net);
++	if (err < 0)
++		goto fail;
++	return 0;
  
 -	fib4_rules_init();
-+	return fib4_rules_init(net);
++fail:
++	kfree(net->ipv4.fib_table_hash);
++	return err;
 +}
  
 -	register_netdevice_notifier(&fib_netdev_notifier);
@@ -859727,7 +917842,7 @@
 +#ifdef CONFIG_IP_MULTIPLE_TABLES
 +	fib4_rules_exit(net);
 +#endif
- 
++
 +	for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
 +		struct fib_table *tb;
 +		struct hlist_head *head;
@@ -859772,7 +917887,7 @@
 +	nl_fib_lookup_exit(net);
 +	ip_fib_net_exit(net);
 +}
-+
+ 
 +static struct pernet_operations fib_net_ops = {
 +	.init = fib_net_init,
 +	.exit = fib_net_exit,
@@ -859795,7 +917910,7 @@
 +EXPORT_SYMBOL(inet_dev_addr_type);
  EXPORT_SYMBOL(ip_dev_find);
 diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
-index 0dfee27..a15b2f1 100644
+index 0dfee27..76b9c68 100644
 --- a/net/ipv4/fib_hash.c
 +++ b/net/ipv4/fib_hash.c
 @@ -52,6 +52,7 @@ struct fib_node {
@@ -859921,7 +918036,79 @@
  out:
  	read_unlock(&fib_hash_lock);
  }
-@@ -490,15 +480,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+@@ -434,19 +424,43 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+ 
+ 	if (fa && fa->fa_tos == tos &&
+ 	    fa->fa_info->fib_priority == fi->fib_priority) {
+-		struct fib_alias *fa_orig;
++		struct fib_alias *fa_first, *fa_match;
+ 
+ 		err = -EEXIST;
+ 		if (cfg->fc_nlflags & NLM_F_EXCL)
+ 			goto out;
+ 
++		/* We have 2 goals:
++		 * 1. Find exact match for type, scope, fib_info to avoid
++		 * duplicate routes
++		 * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
++		 */
++		fa_match = NULL;
++		fa_first = fa;
++		fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
++		list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
++			if (fa->fa_tos != tos)
++				break;
++			if (fa->fa_info->fib_priority != fi->fib_priority)
++				break;
++			if (fa->fa_type == cfg->fc_type &&
++			    fa->fa_scope == cfg->fc_scope &&
++			    fa->fa_info == fi) {
++				fa_match = fa;
++				break;
++			}
++		}
++
+ 		if (cfg->fc_nlflags & NLM_F_REPLACE) {
+ 			struct fib_info *fi_drop;
+ 			u8 state;
+ 
+-			if (fi->fib_treeref > 1)
++			fa = fa_first;
++			if (fa_match) {
++				if (fa == fa_match)
++					err = 0;
+ 				goto out;
+-
++			}
+ 			write_lock_bh(&fib_hash_lock);
+ 			fi_drop = fa->fa_info;
+ 			fa->fa_info = fi;
+@@ -469,20 +483,11 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+ 		 * uses the same scope, type, and nexthop
+ 		 * information.
+ 		 */
+-		fa_orig = fa;
+-		fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
+-		list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
+-			if (fa->fa_tos != tos)
+-				break;
+-			if (fa->fa_info->fib_priority != fi->fib_priority)
+-				break;
+-			if (fa->fa_type == cfg->fc_type &&
+-			    fa->fa_scope == cfg->fc_scope &&
+-			    fa->fa_info == fi)
+-				goto out;
+-		}
++		if (fa_match)
++			goto out;
++
+ 		if (!(cfg->fc_nlflags & NLM_F_APPEND))
+-			fa = fa_orig;
++			fa = fa_first;
+ 	}
+ 
+ 	err = -ENOENT;
+@@ -490,15 +495,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
  		goto out;
  
  	err = -ENOBUFS;
@@ -859939,7 +918126,7 @@
  
  		INIT_HLIST_NODE(&new_f->fn_hash);
  		INIT_LIST_HEAD(&new_f->fn_alias);
-@@ -506,6 +493,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+@@ -506,6 +508,12 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
  		f = new_f;
  	}
  
@@ -859952,7 +918139,7 @@
  	new_fa->fa_info = fi;
  	new_fa->fa_tos = tos;
  	new_fa->fa_type = cfg->fc_type;
-@@ -532,8 +525,8 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+@@ -532,8 +540,8 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
  		  &cfg->fc_nlinfo, 0);
  	return 0;
  
@@ -859963,7 +918150,7 @@
  out:
  	fib_release_info(fi);
  	return err;
-@@ -609,7 +602,7 @@ static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
+@@ -609,7 +617,7 @@ static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
  
  		if (fa->fa_state & FA_S_ACCESSED)
  			rt_cache_flush(-1);
@@ -859972,7 +918159,7 @@
  		if (kill_fn) {
  			fn_free_node(f);
  			fz->fz_nent--;
-@@ -645,7 +638,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
+@@ -645,7 +653,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
  				fib_hash_genid++;
  				write_unlock_bh(&fib_hash_lock);
  
@@ -859981,7 +918168,7 @@
  				found++;
  			}
  		}
-@@ -761,25 +754,19 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
+@@ -761,25 +769,19 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin
  	return skb->len;
  }
  
@@ -859995,29 +918182,29 @@
 -	struct fib_table *tb;
 +	fn_hash_kmem = kmem_cache_create("ip_fib_hash", sizeof(struct fib_node),
 +					 0, SLAB_PANIC, NULL);
++
++	fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias),
++					  0, SLAB_PANIC, NULL);
  
 -	if (fn_hash_kmem == NULL)
 -		fn_hash_kmem = kmem_cache_create("ip_fib_hash",
 -						 sizeof(struct fib_node),
 -						 0, SLAB_HWCACHE_ALIGN,
 -						 NULL);
-+	fn_alias_kmem = kmem_cache_create("ip_fib_alias", sizeof(struct fib_alias),
-+					  0, SLAB_PANIC, NULL);
++}
  
 -	if (fn_alias_kmem == NULL)
 -		fn_alias_kmem = kmem_cache_create("ip_fib_alias",
 -						  sizeof(struct fib_alias),
 -						  0, SLAB_HWCACHE_ALIGN,
 -						  NULL);
-+}
-+
 +struct fib_table *fib_hash_table(u32 id)
 +{
 +	struct fib_table *tb;
  
  	tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash),
  		     GFP_KERNEL);
-@@ -787,6 +774,7 @@ struct fib_table * __init fib_hash_init(u32 id)
+@@ -787,6 +789,7 @@ struct fib_table * __init fib_hash_init(u32 id)
  		return NULL;
  
  	tb->tb_id = id;
@@ -860025,7 +918212,7 @@
  	tb->tb_lookup = fn_hash_lookup;
  	tb->tb_insert = fn_hash_insert;
  	tb->tb_delete = fn_hash_delete;
-@@ -801,6 +789,7 @@ struct fib_table * __init fib_hash_init(u32 id)
+@@ -801,6 +804,7 @@ struct fib_table * __init fib_hash_init(u32 id)
  #ifdef CONFIG_PROC_FS
  
  struct fib_iter_state {
@@ -860033,7 +918220,7 @@
  	struct fn_zone	*zone;
  	int		bucket;
  	struct hlist_head *hash_head;
-@@ -814,7 +803,11 @@ struct fib_iter_state {
+@@ -814,7 +818,11 @@ struct fib_iter_state {
  static struct fib_alias *fib_get_first(struct seq_file *seq)
  {
  	struct fib_iter_state *iter = seq->private;
@@ -860046,7 +918233,7 @@
  
  	iter->bucket    = 0;
  	iter->hash_head = NULL;
-@@ -949,11 +942,13 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
+@@ -949,11 +957,13 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
  }
  
  static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
@@ -860061,7 +918248,7 @@
  		v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
  	return v;
  }
-@@ -965,6 +960,7 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -965,6 +975,7 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void fib_seq_stop(struct seq_file *seq, void *v)
@@ -860069,7 +918256,7 @@
  {
  	read_unlock(&fib_hash_lock);
  }
-@@ -1040,8 +1036,8 @@ static const struct seq_operations fib_seq_ops = {
+@@ -1040,8 +1051,8 @@ static const struct seq_operations fib_seq_ops = {
  
  static int fib_seq_open(struct inode *inode, struct file *file)
  {
@@ -860080,7 +918267,7 @@
  }
  
  static const struct file_operations fib_seq_fops = {
-@@ -1049,18 +1045,18 @@ static const struct file_operations fib_seq_fops = {
+@@ -1049,18 +1060,18 @@ static const struct file_operations fib_seq_fops = {
  	.open           = fib_seq_open,
  	.read           = seq_read,
  	.llseek         = seq_lseek,
@@ -860326,7 +918513,7 @@
 +	kfree(net->ipv4.rules_ops);
  }
 diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
-index 1351a26..c791286 100644
+index 1351a26..a13c847 100644
 --- a/net/ipv4/fib_semantics.c
 +++ b/net/ipv4/fib_semantics.c
 @@ -47,8 +47,6 @@
@@ -860373,7 +918560,16 @@
  
  	return (val ^ (val >> 7) ^ (val >> 12)) & mask;
  }
-@@ -234,15 +244,6 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
+@@ -219,6 +229,8 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
+ 	head = &fib_info_hash[hash];
+ 
+ 	hlist_for_each_entry(fi, node, head, fib_hash) {
++		if (fi->fib_net != nfi->fib_net)
++			continue;
+ 		if (fi->fib_nhs != nfi->fib_nhs)
+ 			continue;
+ 		if (nfi->fib_protocol == fi->fib_protocol &&
+@@ -234,15 +246,6 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
  	return NULL;
  }
  
@@ -860389,7 +918585,7 @@
  /* Check, that the gateway is already configured.
     Used only by redirect accept routine.
   */
-@@ -320,11 +321,11 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
+@@ -320,11 +323,11 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
  		kfree_skb(skb);
  		goto errout;
  	}
@@ -860403,7 +918599,7 @@
  }
  
  /* Return the first fib alias matching TOS with
-@@ -346,7 +347,7 @@ struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
+@@ -346,7 +349,7 @@ struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
  }
  
  int fib_detect_death(struct fib_info *fi, int order,
@@ -860412,7 +918608,7 @@
  {
  	struct neighbour *n;
  	int state = NUD_NONE;
-@@ -358,10 +359,10 @@ int fib_detect_death(struct fib_info *fi, int order,
+@@ -358,10 +361,10 @@ int fib_detect_death(struct fib_info *fi, int order,
  	}
  	if (state==NUD_REACHABLE)
  		return 0;
@@ -860425,7 +918621,7 @@
  		*last_resort = fi;
  		*last_idx = order;
  	}
-@@ -518,7 +519,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
+@@ -518,7 +521,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
  			struct fib_nh *nh)
  {
  	int err;
@@ -860435,7 +918631,7 @@
  	if (nh->nh_gw) {
  		struct fib_result res;
  
-@@ -531,9 +534,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
+@@ -531,9 +536,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
  
  			if (cfg->fc_scope >= RT_SCOPE_LINK)
  				return -EINVAL;
@@ -860447,7 +918643,7 @@
  				return -ENODEV;
  			if (!(dev->flags&IFF_UP))
  				return -ENETDOWN;
-@@ -556,7 +559,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
+@@ -556,7 +561,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
  			/* It is not necessary, but requires a bit of thinking */
  			if (fl.fl4_scope < RT_SCOPE_LINK)
  				fl.fl4_scope = RT_SCOPE_LINK;
@@ -860456,7 +918652,7 @@
  				return err;
  		}
  		err = -EINVAL;
-@@ -580,7 +583,7 @@ out:
+@@ -580,7 +585,7 @@ out:
  		if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
  			return -EINVAL;
  
@@ -860465,7 +918661,7 @@
  		if (in_dev == NULL)
  			return -ENODEV;
  		if (!(in_dev->dev->flags&IFF_UP)) {
-@@ -605,10 +608,10 @@ static inline unsigned int fib_laddr_hashfn(__be32 val)
+@@ -605,10 +610,10 @@ static inline unsigned int fib_laddr_hashfn(__be32 val)
  static struct hlist_head *fib_hash_alloc(int bytes)
  {
  	if (bytes <= PAGE_SIZE)
@@ -860478,7 +918674,15 @@
  }
  
  static void fib_hash_free(struct hlist_head *hash, int bytes)
-@@ -712,12 +715,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
+@@ -684,6 +689,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
+ 	struct fib_info *fi = NULL;
+ 	struct fib_info *ofi;
+ 	int nhs = 1;
++	struct net *net = cfg->fc_nlinfo.nl_net;
+ 
+ 	/* Fast check to catch the most weird cases */
+ 	if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
+@@ -712,12 +718,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
  		if (!new_info_hash || !new_laddrhash) {
  			fib_hash_free(new_info_hash, bytes);
  			fib_hash_free(new_laddrhash, bytes);
@@ -860492,27 +918696,33 @@
  
  		if (!fib_hash_size)
  			goto failure;
-@@ -799,7 +798,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
+@@ -728,6 +730,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
+ 		goto failure;
+ 	fib_info_cnt++;
+ 
++	fi->fib_net = net;
+ 	fi->fib_protocol = cfg->fc_protocol;
+ 	fi->fib_flags = cfg->fc_flags;
+ 	fi->fib_priority = cfg->fc_priority;
+@@ -799,7 +802,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
  		if (nhs != 1 || nh->nh_gw)
  			goto err_inval;
  		nh->nh_scope = RT_SCOPE_NOWHERE;
 -		nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
-+		nh->nh_dev = dev_get_by_index(cfg->fc_nlinfo.nl_net,
-+					      fi->fib_nh->nh_oif);
++		nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif);
  		err = -ENODEV;
  		if (nh->nh_dev == NULL)
  			goto failure;
-@@ -813,7 +813,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
+@@ -813,7 +816,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
  	if (fi->fib_prefsrc) {
  		if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
  		    fi->fib_prefsrc != cfg->fc_dst)
 -			if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
-+			if (inet_addr_type(cfg->fc_nlinfo.nl_net,
-+					   fi->fib_prefsrc) != RTN_LOCAL)
++			if (inet_addr_type(net, fi->fib_prefsrc) != RTN_LOCAL)
  				goto err_inval;
  	}
  
-@@ -914,7 +915,8 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
+@@ -914,7 +917,8 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
  				continue;
  
  			default:
@@ -860522,8 +918732,134 @@
  				return -EINVAL;
  			}
  		}
+@@ -1029,70 +1033,74 @@ nla_put_failure:
+      referring to it.
+    - device went down -> we must shutdown all nexthops going via it.
+  */
+-
+-int fib_sync_down(__be32 local, struct net_device *dev, int force)
++int fib_sync_down_addr(struct net *net, __be32 local)
+ {
+ 	int ret = 0;
+-	int scope = RT_SCOPE_NOWHERE;
+-
+-	if (force)
+-		scope = -1;
++	unsigned int hash = fib_laddr_hashfn(local);
++	struct hlist_head *head = &fib_info_laddrhash[hash];
++	struct hlist_node *node;
++	struct fib_info *fi;
+ 
+-	if (local && fib_info_laddrhash) {
+-		unsigned int hash = fib_laddr_hashfn(local);
+-		struct hlist_head *head = &fib_info_laddrhash[hash];
+-		struct hlist_node *node;
+-		struct fib_info *fi;
++	if (fib_info_laddrhash == NULL || local == 0)
++		return 0;
+ 
+-		hlist_for_each_entry(fi, node, head, fib_lhash) {
+-			if (fi->fib_prefsrc == local) {
+-				fi->fib_flags |= RTNH_F_DEAD;
+-				ret++;
+-			}
++	hlist_for_each_entry(fi, node, head, fib_lhash) {
++		if (fi->fib_net != net)
++			continue;
++		if (fi->fib_prefsrc == local) {
++			fi->fib_flags |= RTNH_F_DEAD;
++			ret++;
+ 		}
+ 	}
++	return ret;
++}
+ 
+-	if (dev) {
+-		struct fib_info *prev_fi = NULL;
+-		unsigned int hash = fib_devindex_hashfn(dev->ifindex);
+-		struct hlist_head *head = &fib_info_devhash[hash];
+-		struct hlist_node *node;
+-		struct fib_nh *nh;
++int fib_sync_down_dev(struct net_device *dev, int force)
++{
++	int ret = 0;
++	int scope = RT_SCOPE_NOWHERE;
++	struct fib_info *prev_fi = NULL;
++	unsigned int hash = fib_devindex_hashfn(dev->ifindex);
++	struct hlist_head *head = &fib_info_devhash[hash];
++	struct hlist_node *node;
++	struct fib_nh *nh;
+ 
+-		hlist_for_each_entry(nh, node, head, nh_hash) {
+-			struct fib_info *fi = nh->nh_parent;
+-			int dead;
++	if (force)
++		scope = -1;
+ 
+-			BUG_ON(!fi->fib_nhs);
+-			if (nh->nh_dev != dev || fi == prev_fi)
+-				continue;
+-			prev_fi = fi;
+-			dead = 0;
+-			change_nexthops(fi) {
+-				if (nh->nh_flags&RTNH_F_DEAD)
+-					dead++;
+-				else if (nh->nh_dev == dev &&
+-					 nh->nh_scope != scope) {
+-					nh->nh_flags |= RTNH_F_DEAD;
++	hlist_for_each_entry(nh, node, head, nh_hash) {
++		struct fib_info *fi = nh->nh_parent;
++		int dead;
++
++		BUG_ON(!fi->fib_nhs);
++		if (nh->nh_dev != dev || fi == prev_fi)
++			continue;
++		prev_fi = fi;
++		dead = 0;
++		change_nexthops(fi) {
++			if (nh->nh_flags&RTNH_F_DEAD)
++				dead++;
++			else if (nh->nh_dev == dev &&
++					nh->nh_scope != scope) {
++				nh->nh_flags |= RTNH_F_DEAD;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+-					spin_lock_bh(&fib_multipath_lock);
+-					fi->fib_power -= nh->nh_power;
+-					nh->nh_power = 0;
+-					spin_unlock_bh(&fib_multipath_lock);
++				spin_lock_bh(&fib_multipath_lock);
++				fi->fib_power -= nh->nh_power;
++				nh->nh_power = 0;
++				spin_unlock_bh(&fib_multipath_lock);
+ #endif
+-					dead++;
+-				}
++				dead++;
++			}
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+-				if (force > 1 && nh->nh_dev == dev) {
+-					dead = fi->fib_nhs;
+-					break;
+-				}
+-#endif
+-			} endfor_nexthops(fi)
+-			if (dead == fi->fib_nhs) {
+-				fi->fib_flags |= RTNH_F_DEAD;
+-				ret++;
++			if (force > 1 && nh->nh_dev == dev) {
++				dead = fi->fib_nhs;
++				break;
+ 			}
++#endif
++		} endfor_nexthops(fi)
++		if (dead == fi->fib_nhs) {
++			fi->fib_flags |= RTNH_F_DEAD;
++			ret++;
+ 		}
+ 	}
+ 
 diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
-index 1010b46..f2f4703 100644
+index 1010b46..35851c9 100644
 --- a/net/ipv4/fib_trie.c
 +++ b/net/ipv4/fib_trie.c
 @@ -82,7 +82,6 @@
@@ -860619,11 +918955,11 @@
 +static inline struct node *tnode_get_child(struct tnode *tn, unsigned int i)
 +{
 +	BUG_ON(i >= 1U << tn->bits);
-+
-+	return tn->child[i];
-+}
  
 -static inline struct node *tnode_get_child(struct tnode *tn, int i)
++	return tn->child[i];
++}
++
 +static inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
  {
 -	BUG_ON(i >= 1 << tn->bits);
@@ -861006,20 +919342,91 @@
  	return fa_head;
  }
  
-@@ -1253,10 +1255,10 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
- 				break;
- 			if (fa->fa_type == cfg->fc_type &&
- 			    fa->fa_scope == cfg->fc_scope &&
--			    fa->fa_info == fi) {
-+			    fa->fa_info == fi)
+@@ -1203,20 +1205,45 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+ 	 * and we need to allocate a new one of those as well.
+ 	 */
+ 
+-	if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
+-		struct fib_alias *fa_orig;
++	if (fa && fa->fa_tos == tos &&
++	    fa->fa_info->fib_priority == fi->fib_priority) {
++		struct fib_alias *fa_first, *fa_match;
+ 
+ 		err = -EEXIST;
+ 		if (cfg->fc_nlflags & NLM_F_EXCL)
+ 			goto out;
+ 
++		/* We have 2 goals:
++		 * 1. Find exact match for type, scope, fib_info to avoid
++		 * duplicate routes
++		 * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
++		 */
++		fa_match = NULL;
++		fa_first = fa;
++		fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
++		list_for_each_entry_continue(fa, fa_head, fa_list) {
++			if (fa->fa_tos != tos)
++				break;
++			if (fa->fa_info->fib_priority != fi->fib_priority)
++				break;
++			if (fa->fa_type == cfg->fc_type &&
++			    fa->fa_scope == cfg->fc_scope &&
++			    fa->fa_info == fi) {
++				fa_match = fa;
++				break;
++			}
++		}
++
+ 		if (cfg->fc_nlflags & NLM_F_REPLACE) {
+ 			struct fib_info *fi_drop;
+ 			u8 state;
+ 
+-			if (fi->fib_treeref > 1)
++			fa = fa_first;
++			if (fa_match) {
++				if (fa == fa_match)
++					err = 0;
  				goto out;
+-
++			}
+ 			err = -ENOBUFS;
+ 			new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
+ 			if (new_fa == NULL)
+@@ -1228,7 +1255,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+ 			new_fa->fa_type = cfg->fc_type;
+ 			new_fa->fa_scope = cfg->fc_scope;
+ 			state = fa->fa_state;
+-			new_fa->fa_state &= ~FA_S_ACCESSED;
++			new_fa->fa_state = state & ~FA_S_ACCESSED;
+ 
+ 			list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
+ 			alias_free_mem_rcu(fa);
+@@ -1245,20 +1272,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+ 		 * uses the same scope, type, and nexthop
+ 		 * information.
+ 		 */
+-		fa_orig = fa;
+-		list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
+-			if (fa->fa_tos != tos)
+-				break;
+-			if (fa->fa_info->fib_priority != fi->fib_priority)
+-				break;
+-			if (fa->fa_type == cfg->fc_type &&
+-			    fa->fa_scope == cfg->fc_scope &&
+-			    fa->fa_info == fi) {
+-				goto out;
 -			}
- 		}
+-		}
++		if (fa_match)
++			goto out;
 +
  		if (!(cfg->fc_nlflags & NLM_F_APPEND))
- 			fa = fa_orig;
+-			fa = fa_orig;
++			fa = fa_first;
  	}
-@@ -1279,10 +1281,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+ 	err = -ENOENT;
+ 	if (!(cfg->fc_nlflags & NLM_F_CREATE))
+@@ -1279,10 +1297,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
  	 */
  
  	if (!fa_head) {
@@ -861034,7 +919441,7 @@
  	}
  
  	list_add_tail_rcu(&new_fa->fa_list,
-@@ -1302,40 +1305,41 @@ err:
+@@ -1302,40 +1321,41 @@ err:
  	return err;
  }
  
@@ -861094,7 +919501,7 @@
  {
  	struct trie *t = (struct trie *) tb->tb_data;
  	int plen, ret = 0;
-@@ -1362,10 +1366,13 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1362,10 +1382,13 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  
  	/* Just a leaf? */
  	if (IS_LEAF(n)) {
@@ -861111,7 +919518,7 @@
  	pn = (struct tnode *) n;
  	chopped_off = 0;
  
-@@ -1387,14 +1394,14 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1387,14 +1410,14 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  		}
  
  		if (IS_LEAF(n)) {
@@ -861131,7 +919538,7 @@
  		cn = (struct tnode *)n;
  
  		/*
-@@ -1423,12 +1430,13 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1423,12 +1446,13 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  		 * *are* zero.
  		 */
  
@@ -861148,7 +919555,7 @@
  				goto backtrace;
  		}
  
-@@ -1451,14 +1459,17 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1451,14 +1475,17 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  		 * new tnode's key.
  		 */
  
@@ -861174,7 +919581,7 @@
  		 */
  
  		node_prefix = mask_pfx(cn->key, cn->pos);
-@@ -1466,13 +1477,15 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1466,13 +1493,15 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  		pref_mismatch = key_prefix^node_prefix;
  		mp = 0;
  
@@ -861193,7 +919600,7 @@
  			}
  			key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
  
-@@ -1482,7 +1495,7 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
+@@ -1482,7 +1511,7 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
  			if (current_prefix_length >= cn->pos)
  				current_prefix_length = mp;
  		}
@@ -861202,7 +919609,7 @@
  		pn = (struct tnode *)n; /* Descend */
  		chopped_off = 0;
  		continue;
-@@ -1491,12 +1504,14 @@ backtrace:
+@@ -1491,12 +1520,14 @@ backtrace:
  		chopped_off++;
  
  		/* As zero don't change the child key (cindex) */
@@ -861219,7 +919626,7 @@
  
  		/*
  		 * Either we do the actual chop off according or if we have
-@@ -1528,52 +1543,23 @@ found:
+@@ -1528,52 +1559,23 @@ found:
  	return ret;
  }
  
@@ -861234,7 +919641,8 @@
 -	struct tnode *tp = NULL;
 -	struct node *n = t->trie;
 -	struct leaf *l;
--
++	struct tnode *tp = node_parent((struct node *) l);
+ 
 -	pr_debug("entering trie_leaf_remove(%p)\n", n);
 -
 -	/* Note that in the case skipped bits, those bits are *not* checked!
@@ -861261,8 +919669,7 @@
 -
 -	t->revision++;
 -	t->size--;
-+	struct tnode *tp = node_parent((struct node *) l);
- 
+-
 -	tp = node_parent(n);
 -	tnode_free((struct tnode *) n);
 +	pr_debug("entering trie_leaf_remove(%p)\n", l);
@@ -861280,7 +919687,19 @@
  }
  
  /*
-@@ -1651,7 +1637,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+@@ -1614,9 +1616,8 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+ 	pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
+ 
+ 	fa_to_delete = NULL;
+-	fa_head = fa->fa_list.prev;
+-
+-	list_for_each_entry(fa, fa_head, fa_list) {
++	fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
++	list_for_each_entry_continue(fa, fa_head, fa_list) {
+ 		struct fib_info *fi = fa->fa_info;
+ 
+ 		if (fa->fa_tos != tos)
+@@ -1651,7 +1652,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
  	}
  
  	if (hlist_empty(&l->list))
@@ -861289,7 +919708,7 @@
  
  	if (fa->fa_state & FA_S_ACCESSED)
  		rt_cache_flush(-1);
-@@ -1697,64 +1683,64 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
+@@ -1697,96 +1698,106 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l)
  	return found;
  }
  
@@ -861306,7 +919725,9 @@
 -	struct tnode *p;
 -	int idx;
 -	struct node *trie = rcu_dereference(t->trie);
--
++	do {
++		t_key idx;
+ 
 -	if (c == NULL) {
 -		if (trie == NULL)
 -			return NULL;
@@ -861320,9 +919741,7 @@
 -
 -	while (p) {
 -		int pos, last;
-+	do {
-+		t_key idx;
- 
+-
 -		/*  Find the next child of the parent */
  		if (c)
 -			pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits);
@@ -861369,8 +919788,6 @@
 +		/* Node empty, walk back up to parent */
  		c = (struct node *) p;
 -		p = node_parent(c);
--	}
--	return NULL; /* Ready. Root of trie */
 +	} while ( (p = node_parent_rcu(c)) != NULL);
 +
 +	return NULL; /* Root of trie */
@@ -861398,10 +919815,25 @@
 +		return NULL;	/* trie with just one leaf */
 +
 +	return leaf_walk_rcu(p, c);
++}
++
++static struct leaf *trie_leafindex(struct trie *t, int index)
++{
++	struct leaf *l = trie_firstleaf(t);
++
++	while (index-- > 0) {
++		l = trie_nextleaf(l);
++		if (!l)
++			break;
+ 	}
+-	return NULL; /* Ready. Root of trie */
++	return l;
  }
  
++
  /*
-@@ -1763,30 +1749,27 @@ up:
+  * Caller must hold RTNL.
+  */
  static int fn_trie_flush(struct fib_table *tb)
  {
  	struct trie *t = (struct trie *) tb->tb_data;
@@ -861440,7 +919872,7 @@
  {
  	struct trie *t = (struct trie *) tb->tb_data;
  	int order, last_idx;
-@@ -1831,48 +1814,38 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
+@@ -1831,51 +1842,41 @@ fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib
  			if (next_fi != res->fi)
  				break;
  		} else if (!fib_detect_death(fi, order, &last_resort,
@@ -861502,8 +919934,12 @@
 -
  	__be32 xkey = htonl(key);
  
- 	s_i = cb->args[4];
-@@ -1885,7 +1858,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
+-	s_i = cb->args[4];
++	s_i = cb->args[5];
+ 	i = 0;
+ 
+ 	/* rcu_read_lock is hold by caller */
+@@ -1885,7 +1886,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
  			i++;
  			continue;
  		}
@@ -861511,16 +919947,20 @@
  
  		if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
  				  cb->nlh->nlmsg_seq,
-@@ -1896,7 +1868,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
+@@ -1896,119 +1896,130 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
  				  xkey,
  				  plen,
  				  fa->fa_tos,
 -				  fa->fa_info, 0) < 0) {
+-			cb->args[4] = i;
 +				  fa->fa_info, NLM_F_MULTI) < 0) {
- 			cb->args[4] = i;
++			cb->args[5] = i;
  			return -1;
  		}
-@@ -1906,109 +1878,118 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
+ 		i++;
+ 	}
+-	cb->args[4] = i;
++	cb->args[5] = i;
  	return skb->len;
  }
  
@@ -861537,7 +919977,7 @@
 +	int i, s_i;
  
 -	s_h = cb->args[3];
-+	s_i = cb->args[3];
++	s_i = cb->args[4];
 +	i = 0;
  
 -	for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
@@ -861550,30 +919990,30 @@
 -		if (h > s_h)
 -			memset(&cb->args[4], 0,
 -			       sizeof(cb->args) - 4*sizeof(cb->args[0]));
--
--		fa_head = get_fa_head(l, plen);
 +		}
  
--		if (!fa_head)
--			continue;
+-		fa_head = get_fa_head(l, plen);
 +		if (i > s_i)
-+			cb->args[4] = 0;
++			cb->args[5] = 0;
  
--		if (list_empty(fa_head))
+-		if (!fa_head)
 +		if (list_empty(&li->falh))
  			continue;
  
+-		if (list_empty(fa_head))
+-			continue;
+-
 -		if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
 -			cb->args[3] = h;
 +		if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) {
-+			cb->args[3] = i;
++			cb->args[4] = i;
  			return -1;
  		}
 +		i++;
  	}
 -	cb->args[3] = h;
 +
-+	cb->args[3] = i;
++	cb->args[4] = i;
  	return skb->len;
  }
  
@@ -861587,6 +920027,7 @@
 -
 -	s_m = cb->args[2];
 +	t_key key = cb->args[2];
++	int count = cb->args[3];
  
  	rcu_read_lock();
 -	for (m = 0; m <= 32; m++) {
@@ -861598,17 +920039,15 @@
 +	/* Dump starting at last key.
 +	 * Note: 0.0.0.0/0 (ie default) is first key.
 +	 */
-+	if (!key)
++	if (count == 0)
 +		l = trie_firstleaf(t);
 +	else {
++		/* Normally, continue from last key, but if that is missing
++		 * fallback to using slow rescan
++		 */
 +		l = fib_find_node(t, key);
-+		if (!l) {
-+			/* The table changed during the dump, rather than
-+			 * giving partial data, just make application retry.
-+			 */
-+			rcu_read_unlock();
-+			return -EBUSY;
-+		}
++		if (!l)
++			l = trie_leafindex(t, count);
 +	}
  
 -		if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
@@ -861617,14 +920056,17 @@
 +	while (l) {
 +		cb->args[2] = l->key;
 +		if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
++			cb->args[3] = count;
 +			rcu_read_unlock();
 +			return -1;
  		}
 +
++		++count;
 +		l = trie_nextleaf(l);
-+		memset(&cb->args[3], 0,
-+		       sizeof(cb->args) - 3*sizeof(cb->args[0]));
++		memset(&cb->args[4], 0,
++		       sizeof(cb->args) - 4*sizeof(cb->args[0]));
  	}
++	cb->args[3] = count;
  	rcu_read_unlock();
 -	cb->args[2] = m;
 +
@@ -861696,7 +920138,7 @@
  
  	return tb;
  }
-@@ -2016,6 +1997,8 @@ struct fib_table * __init fib_hash_init(u32 id)
+@@ -2016,6 +2027,8 @@ struct fib_table * __init fib_hash_init(u32 id)
  #ifdef CONFIG_PROC_FS
  /* Depth first Trie walk iterator */
  struct fib_trie_iter {
@@ -861705,7 +920147,7 @@
  	struct tnode *tnode;
  	struct trie *trie;
  	unsigned index;
-@@ -2036,7 +2019,7 @@ static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
+@@ -2036,7 +2049,7 @@ static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
  		 iter->tnode, iter->index, iter->depth);
  rescan:
  	while (cindex < (1<<tn->bits)) {
@@ -861714,7 +920156,7 @@
  
  		if (n) {
  			if (IS_LEAF(n)) {
-@@ -2055,7 +2038,7 @@ rescan:
+@@ -2055,7 +2068,7 @@ rescan:
  	}
  
  	/* Current node exhausted, pop back up */
@@ -861723,7 +920165,7 @@
  	if (p) {
  		cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
  		tn = p;
-@@ -2108,10 +2091,17 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
+@@ -2108,10 +2121,17 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
  	for (n = fib_trie_get_first(&iter, t); n;
  	     n = fib_trie_get_next(&iter)) {
  		if (IS_LEAF(n)) {
@@ -861741,7 +920183,7 @@
  		} else {
  			const struct tnode *tn = (const struct tnode *) n;
  			int i;
-@@ -2140,13 +2130,17 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
+@@ -2140,13 +2160,17 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
  	else
  		avdepth = 0;
  
@@ -861762,7 +920204,7 @@
  	bytes += sizeof(struct tnode) * stat->tnodes;
  
  	max = MAX_STAT_DEPTH;
-@@ -2156,60 +2150,89 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
+@@ -2156,60 +2180,89 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
  	pointers = 0;
  	for (i = 1; i <= max; i++)
  		if (stat->nodesizes[i] != 0) {
@@ -861884,7 +920326,7 @@
  }
  
  static const struct file_operations fib_triestat_fops = {
-@@ -2217,7 +2240,7 @@ static const struct file_operations fib_triestat_fops = {
+@@ -2217,7 +2270,7 @@ static const struct file_operations fib_triestat_fops = {
  	.open	= fib_triestat_seq_open,
  	.read	= seq_read,
  	.llseek	= seq_lseek,
@@ -861893,7 +920335,7 @@
  };
  
  static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
-@@ -2226,13 +2249,13 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
+@@ -2226,13 +2279,13 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
  	loff_t idx = 0;
  	struct node *n;
  
@@ -861909,7 +920351,7 @@
  	     n; ++idx, n = fib_trie_get_next(iter)) {
  		if (pos == idx)
  			return n;
-@@ -2241,11 +2264,25 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
+@@ -2241,11 +2294,25 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
  }
  
  static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
@@ -861936,7 +920378,7 @@
  }
  
  static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-@@ -2263,13 +2300,14 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -2263,13 +2330,14 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  		return v;
  
  	/* continue scan in next trie */
@@ -861953,7 +920395,7 @@
  {
  	rcu_read_unlock();
  }
-@@ -2279,10 +2317,8 @@ static void seq_indent(struct seq_file *seq, int n)
+@@ -2279,10 +2347,8 @@ static void seq_indent(struct seq_file *seq, int n)
  	while (n-- > 0) seq_puts(seq, "   ");
  }
  
@@ -861965,7 +920407,7 @@
  	switch (s) {
  	case RT_SCOPE_UNIVERSE: return "universe";
  	case RT_SCOPE_SITE:	return "site";
-@@ -2290,7 +2326,7 @@ static inline const char *rtn_scope(enum rt_scope_t s)
+@@ -2290,7 +2356,7 @@ static inline const char *rtn_scope(enum rt_scope_t s)
  	case RT_SCOPE_HOST:	return "host";
  	case RT_SCOPE_NOWHERE:	return "nowhere";
  	default:
@@ -861974,7 +920416,7 @@
  		return buf;
  	}
  }
-@@ -2310,13 +2346,11 @@ static const char *rtn_type_names[__RTN_MAX] = {
+@@ -2310,13 +2376,11 @@ static const char *rtn_type_names[__RTN_MAX] = {
  	[RTN_XRESOLVE] = "XRESOLVE",
  };
  
@@ -861990,7 +920432,7 @@
  	return buf;
  }
  
-@@ -2329,8 +2363,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
+@@ -2329,8 +2393,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
  	if (v == SEQ_START_TOKEN)
  		return 0;
  
@@ -862001,7 +920443,7 @@
  			seq_puts(seq, "<local>:\n");
  		else
  			seq_puts(seq, "<main>:\n");
-@@ -2347,25 +2381,29 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
+@@ -2347,25 +2411,29 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
  
  	} else {
  		struct leaf *l = (struct leaf *) n;
@@ -862046,7 +920488,7 @@
  			}
  		}
  	}
-@@ -2382,8 +2420,8 @@ static const struct seq_operations fib_trie_seq_ops = {
+@@ -2382,8 +2450,8 @@ static const struct seq_operations fib_trie_seq_ops = {
  
  static int fib_trie_seq_open(struct inode *inode, struct file *file)
  {
@@ -862057,7 +920499,7 @@
  }
  
  static const struct file_operations fib_trie_fops = {
-@@ -2391,7 +2429,7 @@ static const struct file_operations fib_trie_fops = {
+@@ -2391,7 +2459,7 @@ static const struct file_operations fib_trie_fops = {
  	.open   = fib_trie_seq_open,
  	.read   = seq_read,
  	.llseek = seq_lseek,
@@ -862066,7 +920508,7 @@
  };
  
  static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
-@@ -2419,8 +2457,8 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
+@@ -2419,8 +2487,8 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
  {
  	const struct fib_trie_iter *iter = seq->private;
  	struct leaf *l = v;
@@ -862077,7 +920519,7 @@
  
  	if (v == SEQ_START_TOKEN) {
  		seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
-@@ -2429,25 +2467,23 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
+@@ -2429,25 +2497,23 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
  		return 0;
  	}
  
@@ -862107,7 +920549,7 @@
  
  			if (fa->fa_type == RTN_BROADCAST
  			    || fa->fa_type == RTN_MULTICAST)
-@@ -2461,7 +2497,8 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
+@@ -2461,7 +2527,8 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
  					 fi->fib_nh->nh_gw, flags, 0, 0,
  					 fi->fib_priority,
  					 mask,
@@ -862117,7 +920559,7 @@
  					 fi->fib_window,
  					 fi->fib_rtt >> 3);
  			else
-@@ -2486,8 +2523,8 @@ static const struct seq_operations fib_route_seq_ops = {
+@@ -2486,8 +2553,8 @@ static const struct seq_operations fib_route_seq_ops = {
  
  static int fib_route_seq_open(struct inode *inode, struct file *file)
  {
@@ -862128,7 +920570,7 @@
  }
  
  static const struct file_operations fib_route_fops = {
-@@ -2495,35 +2532,36 @@ static const struct file_operations fib_route_fops = {
+@@ -2495,35 +2562,36 @@ static const struct file_operations fib_route_fops = {
  	.open   = fib_route_seq_open,
  	.read   = seq_read,
  	.llseek = seq_lseek,
@@ -862636,10 +921078,46 @@
  	struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
  	if (likely(state->in_dev != NULL)) {
 diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
-index 8fb6ca2..7801cce 100644
+index 8fb6ca2..de5a41d 100644
 --- a/net/ipv4/inet_connection_sock.c
 +++ b/net/ipv4/inet_connection_sock.c
-@@ -277,18 +277,11 @@ void inet_csk_init_xmit_timers(struct sock *sk,
+@@ -87,6 +87,7 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+ 	struct hlist_node *node;
+ 	struct inet_bind_bucket *tb;
+ 	int ret;
++	struct net *net = sk->sk_net;
+ 
+ 	local_bh_disable();
+ 	if (!snum) {
+@@ -100,7 +101,7 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+ 			head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
+ 			spin_lock(&head->lock);
+ 			inet_bind_bucket_for_each(tb, node, &head->chain)
+-				if (tb->port == rover)
++				if (tb->ib_net == net && tb->port == rover)
+ 					goto next;
+ 			break;
+ 		next:
+@@ -127,7 +128,7 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
+ 		head = &hashinfo->bhash[inet_bhashfn(snum, hashinfo->bhash_size)];
+ 		spin_lock(&head->lock);
+ 		inet_bind_bucket_for_each(tb, node, &head->chain)
+-			if (tb->port == snum)
++			if (tb->ib_net == net && tb->port == snum)
+ 				goto tb_found;
+ 	}
+ 	tb = NULL;
+@@ -147,7 +148,8 @@ tb_found:
+ 	}
+ tb_not_found:
+ 	ret = 1;
+-	if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, head, snum)) == NULL)
++	if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep,
++					net, head, snum)) == NULL)
+ 		goto fail_unlock;
+ 	if (hlist_empty(&tb->owners)) {
+ 		if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
+@@ -277,18 +279,11 @@ void inet_csk_init_xmit_timers(struct sock *sk,
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
  
@@ -862663,7 +921141,7 @@
  	icsk->icsk_pending = icsk->icsk_ack.pending = 0;
  }
  
-@@ -340,7 +333,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
+@@ -340,7 +335,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
  					 .dport = ireq->rmt_port } } };
  
  	security_req_classify_flow(req, &fl);
@@ -862673,10 +921151,56 @@
  		return NULL;
  	}
 diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
-index e468e7a..605ed2c 100644
+index e468e7a..da97695 100644
 --- a/net/ipv4/inet_diag.c
 +++ b/net/ipv4/inet_diag.c
-@@ -935,7 +935,7 @@ out_free_table:
+@@ -259,20 +259,22 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
+ 	const struct inet_diag_handler *handler;
+ 
+ 	handler = inet_diag_lock_handler(nlh->nlmsg_type);
+-	if (!handler)
+-		return -ENOENT;
++	if (IS_ERR(handler)) {
++		err = PTR_ERR(handler);
++		goto unlock;
++	}
+ 
+ 	hashinfo = handler->idiag_hashinfo;
+ 	err = -EINVAL;
+ 
+ 	if (req->idiag_family == AF_INET) {
+-		sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
++		sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0],
+ 				 req->id.idiag_dport, req->id.idiag_src[0],
+ 				 req->id.idiag_sport, req->id.idiag_if);
+ 	}
+ #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ 	else if (req->idiag_family == AF_INET6) {
+-		sk = inet6_lookup(hashinfo,
++		sk = inet6_lookup(&init_net, hashinfo,
+ 				  (struct in6_addr *)req->id.idiag_dst,
+ 				  req->id.idiag_dport,
+ 				  (struct in6_addr *)req->id.idiag_src,
+@@ -708,8 +710,8 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+ 	struct inet_hashinfo *hashinfo;
+ 
+ 	handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);
+-	if (!handler)
+-		goto no_handler;
++	if (IS_ERR(handler))
++		goto unlock;
+ 
+ 	hashinfo = handler->idiag_hashinfo;
+ 
+@@ -838,7 +840,6 @@ done:
+ 	cb->args[2] = num;
+ unlock:
+ 	inet_diag_unlock_handler(handler);
+-no_handler:
+ 	return skb->len;
+ }
+ 
+@@ -935,7 +936,7 @@ out_free_table:
  
  static void __exit inet_diag_exit(void)
  {
@@ -862921,10 +921445,25 @@
  }
  EXPORT_SYMBOL(inet_frag_find);
 diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
-index 67704da..619c63c 100644
+index 67704da..48d4500 100644
 --- a/net/ipv4/inet_hashtables.c
 +++ b/net/ipv4/inet_hashtables.c
-@@ -96,6 +96,7 @@ EXPORT_SYMBOL(inet_put_port);
+@@ -28,12 +28,14 @@
+  * The bindhash mutex for snum's hash chain must be held here.
+  */
+ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
++						 struct net *net,
+ 						 struct inet_bind_hashbucket *head,
+ 						 const unsigned short snum)
+ {
+ 	struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC);
+ 
+ 	if (tb != NULL) {
++		tb->ib_net       = net;
+ 		tb->port      = snum;
+ 		tb->fastreuse = 0;
+ 		INIT_HLIST_HEAD(&tb->owners);
+@@ -96,6 +98,7 @@ EXPORT_SYMBOL(inet_put_port);
   * exclusive lock release). It should be ifdefed really.
   */
  void inet_listen_wlock(struct inet_hashinfo *hashinfo)
@@ -862932,11 +921471,54 @@
  {
  	write_lock(&hashinfo->lhash_lock);
  
-@@ -190,6 +191,44 @@ sherry_cache:
+@@ -124,7 +127,8 @@ EXPORT_SYMBOL(inet_listen_wlock);
+  * remote address for the connection. So always assume those are both
+  * wildcarded during the search since they can never be otherwise.
+  */
+-static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
++static struct sock *inet_lookup_listener_slow(struct net *net,
++					      const struct hlist_head *head,
+ 					      const __be32 daddr,
+ 					      const unsigned short hnum,
+ 					      const int dif)
+@@ -136,7 +140,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
+ 	sk_for_each(sk, node, head) {
+ 		const struct inet_sock *inet = inet_sk(sk);
+ 
+-		if (inet->num == hnum && !ipv6_only_sock(sk)) {
++		if (sk->sk_net == net && inet->num == hnum &&
++				!ipv6_only_sock(sk)) {
+ 			const __be32 rcv_saddr = inet->rcv_saddr;
+ 			int score = sk->sk_family == PF_INET ? 1 : 0;
+ 
+@@ -162,7 +167,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
+ }
+ 
+ /* Optimize the common listener case. */
+-struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
++struct sock *__inet_lookup_listener(struct net *net,
++				    struct inet_hashinfo *hashinfo,
+ 				    const __be32 daddr, const unsigned short hnum,
+ 				    const int dif)
+ {
+@@ -177,9 +183,9 @@ struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
+ 		if (inet->num == hnum && !sk->sk_node.next &&
+ 		    (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
+ 		    (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
+-		    !sk->sk_bound_dev_if)
++		    !sk->sk_bound_dev_if && sk->sk_net == net)
+ 			goto sherry_cache;
+-		sk = inet_lookup_listener_slow(head, daddr, hnum, dif);
++		sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif);
+ 	}
+ 	if (sk) {
+ sherry_cache:
+@@ -190,6 +196,47 @@ sherry_cache:
  }
  EXPORT_SYMBOL_GPL(__inet_lookup_listener);
  
-+struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo,
++struct sock * __inet_lookup_established(struct net *net,
++				  struct inet_hashinfo *hashinfo,
 +				  const __be32 saddr, const __be16 sport,
 +				  const __be32 daddr, const u16 hnum,
 +				  const int dif)
@@ -862955,13 +921537,15 @@
 +	prefetch(head->chain.first);
 +	read_lock(lock);
 +	sk_for_each(sk, node, &head->chain) {
-+		if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
++		if (INET_MATCH(sk, net, hash, acookie,
++					saddr, daddr, ports, dif))
 +			goto hit; /* You sunk my battleship! */
 +	}
 +
 +	/* Must check for a TIME_WAIT'er before going to listener hash. */
 +	sk_for_each(sk, node, &head->twchain) {
-+		if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
++		if (INET_TW_MATCH(sk, net, hash, acookie,
++					saddr, daddr, ports, dif))
 +			goto hit;
 +	}
 +	sk = NULL;
@@ -862977,7 +921561,35 @@
  /* called with local bh disabled */
  static int __inet_check_established(struct inet_timewait_death_row *death_row,
  				    struct sock *sk, __u16 lport,
-@@ -239,7 +278,7 @@ unique:
+@@ -208,6 +255,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
+ 	struct sock *sk2;
+ 	const struct hlist_node *node;
+ 	struct inet_timewait_sock *tw;
++	struct net *net = sk->sk_net;
+ 
+ 	prefetch(head->chain.first);
+ 	write_lock(lock);
+@@ -216,7 +264,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
+ 	sk_for_each(sk2, node, &head->twchain) {
+ 		tw = inet_twsk(sk2);
+ 
+-		if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
++		if (INET_TW_MATCH(sk2, net, hash, acookie,
++					saddr, daddr, ports, dif)) {
+ 			if (twsk_unique(sk, sk2, twp))
+ 				goto unique;
+ 			else
+@@ -227,7 +276,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
+ 
+ 	/* And established part... */
+ 	sk_for_each(sk2, node, &head->chain) {
+-		if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
++		if (INET_MATCH(sk2, net, hash, acookie,
++					saddr, daddr, ports, dif))
+ 			goto not_unique;
+ 	}
+ 
+@@ -239,7 +289,7 @@ unique:
  	sk->sk_hash = hash;
  	BUG_TRAP(sk_unhashed(sk));
  	__sk_add_node(sk, &head->chain);
@@ -862986,10 +921598,15 @@
  	write_unlock(lock);
  
  	if (twp) {
-@@ -267,6 +306,48 @@ static inline u32 inet_sk_port_offset(const struct sock *sk)
+@@ -267,17 +317,60 @@ static inline u32 inet_sk_port_offset(const struct sock *sk)
  					  inet->dport);
  }
  
+-/*
+- * Bind a port for a connect operation and hash it.
+- */
+-int inet_hash_connect(struct inet_timewait_death_row *death_row,
+-		      struct sock *sk)
 +void __inet_hash_nolisten(struct inet_hashinfo *hashinfo, struct sock *sk)
 +{
 +	struct hlist_head *list;
@@ -863032,27 +921649,86 @@
 +}
 +EXPORT_SYMBOL_GPL(__inet_hash);
 +
- /*
-  * Bind a port for a connect operation and hash it.
-  */
-@@ -334,7 +415,7 @@ ok:
++int __inet_hash_connect(struct inet_timewait_death_row *death_row,
++		struct sock *sk,
++		int (*check_established)(struct inet_timewait_death_row *,
++			struct sock *, __u16, struct inet_timewait_sock **),
++		void (*hash)(struct inet_hashinfo *, struct sock *))
+ {
+ 	struct inet_hashinfo *hinfo = death_row->hashinfo;
+ 	const unsigned short snum = inet_sk(sk)->num;
+ 	struct inet_bind_hashbucket *head;
+ 	struct inet_bind_bucket *tb;
+ 	int ret;
++	struct net *net = sk->sk_net;
+ 
+ 	if (!snum) {
+ 		int i, remaining, low, high, port;
+@@ -300,19 +393,19 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
+ 			 * unique enough.
+ 			 */
+ 			inet_bind_bucket_for_each(tb, node, &head->chain) {
+-				if (tb->port == port) {
++				if (tb->ib_net == net && tb->port == port) {
+ 					BUG_TRAP(!hlist_empty(&tb->owners));
+ 					if (tb->fastreuse >= 0)
+ 						goto next_port;
+-					if (!__inet_check_established(death_row,
+-								      sk, port,
+-								      &tw))
++					if (!check_established(death_row, sk,
++								port, &tw))
+ 						goto ok;
+ 					goto next_port;
+ 				}
+ 			}
+ 
+-			tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port);
++			tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
++					net, head, port);
+ 			if (!tb) {
+ 				spin_unlock(&head->lock);
+ 				break;
+@@ -334,7 +427,7 @@ ok:
  		inet_bind_hash(sk, tb, port);
  		if (sk_unhashed(sk)) {
  			inet_sk(sk)->sport = htons(port);
 -			__inet_hash(hinfo, sk, 0);
-+			__inet_hash_nolisten(hinfo, sk);
++			hash(hinfo, sk);
  		}
  		spin_unlock(&head->lock);
  
-@@ -351,7 +432,7 @@ ok:
+@@ -351,17 +444,28 @@ ok:
  	tb  = inet_csk(sk)->icsk_bind_hash;
  	spin_lock_bh(&head->lock);
  	if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
 -		__inet_hash(hinfo, sk, 0);
-+		__inet_hash_nolisten(hinfo, sk);
++		hash(hinfo, sk);
  		spin_unlock_bh(&head->lock);
  		return 0;
  	} else {
+ 		spin_unlock(&head->lock);
+ 		/* No definite answer... Walk to established hash table */
+-		ret = __inet_check_established(death_row, sk, snum, NULL);
++		ret = check_established(death_row, sk, snum, NULL);
+ out:
+ 		local_bh_enable();
+ 		return ret;
+ 	}
+ }
++EXPORT_SYMBOL_GPL(__inet_hash_connect);
++
++/*
++ * Bind a port for a connect operation and hash it.
++ */
++int inet_hash_connect(struct inet_timewait_death_row *death_row,
++		      struct sock *sk)
++{
++	return __inet_hash_connect(death_row, sk,
++			__inet_check_established, __inet_hash_nolisten);
++}
+ 
+ EXPORT_SYMBOL_GPL(inet_hash_connect);
 diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
 index a60b99e..876169f 100644
 --- a/net/ipv4/inet_timewait_sock.c
@@ -863824,7 +922500,7 @@
  						if (skb)
  							timeptr = (__be32*)&optptr[optptr[2]+3];
 diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
-index bc9e575..18070ca 100644
+index bc9e575..341779e 100644
 --- a/net/ipv4/ip_output.c
 +++ b/net/ipv4/ip_output.c
 @@ -91,6 +91,28 @@ __inline__ void ip_send_check(struct iphdr *iph)
@@ -863856,7 +922532,7 @@
  /* dev_loopback_xmit for use with netfilter. */
  static int ip_dev_loopback_xmit(struct sk_buff *newskb)
  {
-@@ -138,20 +160,17 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+@@ -138,20 +160,18 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
  	iph->daddr    = rt->rt_dst;
  	iph->saddr    = rt->rt_src;
  	iph->protocol = sk->sk_protocol;
@@ -863870,6 +922546,7 @@
 -	ip_send_check(iph);
  
  	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
  
  	/* Send it out. */
 -	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
@@ -863878,7 +922555,7 @@
  }
  
  EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
-@@ -251,8 +270,8 @@ int ip_mc_output(struct sk_buff *skb)
+@@ -251,8 +271,8 @@ int ip_mc_output(struct sk_buff *skb)
  		) {
  			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
  			if (newskb)
@@ -863889,7 +922566,7 @@
  					ip_dev_loopback_xmit);
  		}
  
-@@ -267,11 +286,11 @@ int ip_mc_output(struct sk_buff *skb)
+@@ -267,11 +287,11 @@ int ip_mc_output(struct sk_buff *skb)
  	if (rt->rt_flags&RTCF_BROADCAST) {
  		struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
  		if (newskb)
@@ -863903,7 +922580,7 @@
  			    ip_finish_output,
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
-@@ -285,7 +304,7 @@ int ip_output(struct sk_buff *skb)
+@@ -285,7 +305,7 @@ int ip_output(struct sk_buff *skb)
  	skb->dev = dev;
  	skb->protocol = htons(ETH_P_IP);
  
@@ -863912,7 +922589,7 @@
  			    ip_finish_output,
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
-@@ -331,7 +350,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+@@ -331,7 +351,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
  			 * itself out.
  			 */
  			security_sk_classify_flow(sk, &fl);
@@ -863921,7 +922598,7 @@
  				goto no_route;
  		}
  		sk_setup_caps(sk, &rt->u.dst);
-@@ -347,7 +366,6 @@ packet_routed:
+@@ -347,7 +367,6 @@ packet_routed:
  	skb_reset_network_header(skb);
  	iph = ip_hdr(skb);
  	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
@@ -863929,7 +922606,7 @@
  	if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
  		iph->frag_off = htons(IP_DF);
  	else
-@@ -366,13 +384,9 @@ packet_routed:
+@@ -366,13 +385,10 @@ packet_routed:
  	ip_select_ident_more(iph, &rt->u.dst, sk,
  			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
  
@@ -863937,6 +922614,7 @@
 -	ip_send_check(iph);
 -
  	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
  
 -	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
 -		       dst_output);
@@ -863944,7 +922622,32 @@
  
  no_route:
  	IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
-@@ -1262,14 +1276,12 @@ int ip_push_pending_frames(struct sock *sk)
+@@ -462,6 +478,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+ 	if (skb_shinfo(skb)->frag_list) {
+ 		struct sk_buff *frag;
+ 		int first_len = skb_pagelen(skb);
++		int truesizes = 0;
+ 
+ 		if (first_len - hlen > mtu ||
+ 		    ((first_len - hlen) & 7) ||
+@@ -485,7 +502,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+ 				sock_hold(skb->sk);
+ 				frag->sk = skb->sk;
+ 				frag->destructor = sock_wfree;
+-				skb->truesize -= frag->truesize;
++				truesizes += frag->truesize;
+ 			}
+ 		}
+ 
+@@ -496,6 +513,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+ 		frag = skb_shinfo(skb)->frag_list;
+ 		skb_shinfo(skb)->frag_list = NULL;
+ 		skb->data_len = first_len - skb_headlen(skb);
++		skb->truesize -= truesizes;
+ 		skb->len = first_len;
+ 		iph->tot_len = htons(first_len);
+ 		iph->frag_off = htons(IP_MF);
+@@ -1262,16 +1280,15 @@ int ip_push_pending_frames(struct sock *sk)
  		ip_options_build(skb, opt, inet->cork.addr, rt, 0);
  	}
  	iph->tos = inet->tos;
@@ -863958,8 +922661,11 @@
 -	ip_send_check(iph);
  
  	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
  	skb->dst = dst_clone(&rt->u.dst);
-@@ -1279,8 +1291,7 @@ int ip_push_pending_frames(struct sock *sk)
+ 
+ 	if (iph->protocol == IPPROTO_ICMP)
+@@ -1279,8 +1296,7 @@ int ip_push_pending_frames(struct sock *sk)
  			skb_transport_header(skb))->type);
  
  	/* Netfilter gets whole the not fragmented skb. */
@@ -863969,7 +922675,7 @@
  	if (err) {
  		if (err > 0)
  			err = inet->recverr ? net_xmit_errno(err) : 0;
-@@ -1330,8 +1341,6 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
+@@ -1330,8 +1346,6 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
   *
   *	Should run single threaded per socket because it uses the sock
   *     	structure to pass arguments.
@@ -863978,7 +922684,7 @@
   */
  void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
  		   unsigned int len)
-@@ -1370,7 +1379,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
+@@ -1370,7 +1384,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
  						 .dport = tcp_hdr(skb)->source } },
  				    .proto = sk->sk_protocol };
  		security_skb_classify_flow(skb, &fl);
@@ -864001,10 +922707,35 @@
  				mreq.imr_ifindex = dev->ifindex;
  				dev_put(dev);
 diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
-index 2c44a94..f4af99a 100644
+index 2c44a94..ae1f45f 100644
 --- a/net/ipv4/ipcomp.c
 +++ b/net/ipv4/ipcomp.c
-@@ -182,7 +182,6 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
+@@ -74,6 +74,7 @@ out:
+ 
+ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
+ {
++	int nexthdr;
+ 	int err = -ENOMEM;
+ 	struct ip_comp_hdr *ipch;
+ 
+@@ -84,13 +85,15 @@ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
+ 
+ 	/* Remove ipcomp header and decompress original payload */
+ 	ipch = (void *)skb->data;
++	nexthdr = ipch->nexthdr;
++
+ 	skb->transport_header = skb->network_header + sizeof(*ipch);
+ 	__skb_pull(skb, sizeof(*ipch));
+ 	err = ipcomp_decompress(x, skb);
+ 	if (err)
+ 		goto out;
+ 
+-	err = ipch->nexthdr;
++	err = nexthdr;
+ 
+ out:
+ 	return err;
+@@ -182,7 +185,6 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
  static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
  {
  	struct xfrm_state *t;
@@ -864012,7 +922743,7 @@
  
  	t = xfrm_state_alloc();
  	if (t == NULL)
-@@ -193,9 +192,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
+@@ -193,9 +195,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
  	t->id.daddr.a4 = x->id.daddr.a4;
  	memcpy(&t->sel, &x->sel, sizeof(t->sel));
  	t->props.family = AF_INET;
@@ -864023,7 +922754,7 @@
  	t->props.saddr.a4 = x->props.saddr.a4;
  	t->props.flags = x->props.flags;
  
-@@ -389,15 +386,22 @@ static int ipcomp_init_state(struct xfrm_state *x)
+@@ -389,15 +389,22 @@ static int ipcomp_init_state(struct xfrm_state *x)
  	if (x->encap)
  		goto out;
  
@@ -864050,6 +922781,15 @@
  	mutex_lock(&ipcomp_resource_mutex);
  	if (!ipcomp_alloc_scratches())
  		goto error;
+@@ -430,7 +437,7 @@ error:
+ 	goto out;
+ }
+ 
+-static struct xfrm_type ipcomp_type = {
++static const struct xfrm_type ipcomp_type = {
+ 	.description	= "IPCOMP4",
+ 	.owner		= THIS_MODULE,
+ 	.proto	     	= IPPROTO_COMP,
 diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
 index b8f7763..a52b585 100644
 --- a/net/ipv4/ipconfig.c
@@ -865567,10 +924307,10 @@
  obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
  
 diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
-index 2909c92..b4a810c 100644
+index 2909c92..a7591ce 100644
 --- a/net/ipv4/netfilter/arp_tables.c
 +++ b/net/ipv4/netfilter/arp_tables.c
-@@ -19,9 +19,10 @@
+@@ -19,9 +19,11 @@
  #include <linux/proc_fs.h>
  #include <linux/module.h>
  #include <linux/init.h>
@@ -865579,11 +924319,12 @@
  #include <linux/mutex.h>
 +#include <linux/err.h>
 +#include <net/compat.h>
++#include <net/sock.h>
 +#include <asm/uaccess.h>
  
  #include <linux/netfilter/x_tables.h>
  #include <linux/netfilter_arp/arp_tables.h>
-@@ -83,7 +84,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
+@@ -83,7 +85,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
  	__be32 src_ipaddr, tgt_ipaddr;
  	int i, ret;
  
@@ -865592,7 +924333,7 @@
  
  	if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop,
  		  ARPT_INV_ARPOP)) {
-@@ -179,6 +180,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
+@@ -179,6 +181,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
  	}
  
  	return 1;
@@ -865600,7 +924341,7 @@
  }
  
  static inline int arp_checkentry(const struct arpt_arp *arp)
-@@ -435,29 +437,9 @@ static int mark_source_chains(struct xt_table_info *newinfo,
+@@ -435,29 +438,9 @@ static int mark_source_chains(struct xt_table_info *newinfo,
  	return 1;
  }
  
@@ -865631,7 +924372,7 @@
  
  	if (!arp_checkentry(&e->arp)) {
  		duprintf("arp_tables: arp check failed %p %s.\n", e, name);
-@@ -471,35 +453,57 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
+@@ -471,35 +454,57 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
  	if (e->target_offset + t->u.target_size > e->next_offset)
  		return -EINVAL;
  
@@ -865706,7 +924447,7 @@
  	(*i)++;
  	return 0;
  err:
-@@ -633,7 +637,7 @@ static int translate_table(const char *name,
+@@ -633,7 +638,7 @@ static int translate_table(const char *name,
  	/* Finally, each sanity check must pass */
  	i = 0;
  	ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
@@ -865715,7 +924456,7 @@
  
  	if (ret != 0) {
  		ARPT_ENTRY_ITERATE(entry0, newinfo->size,
-@@ -704,16 +708,11 @@ static void get_counters(const struct xt_table_info *t,
+@@ -704,16 +709,11 @@ static void get_counters(const struct xt_table_info *t,
  	}
  }
  
@@ -865734,7 +924475,7 @@
  
  	/* We need atomic snapshot of counters: rest doesn't change
  	 * (other than comefrom, which userspace doesn't care
-@@ -723,13 +722,31 @@ static int copy_entries_to_user(unsigned int total_size,
+@@ -723,13 +723,31 @@ static int copy_entries_to_user(unsigned int total_size,
  	counters = vmalloc_node(countersize, numa_node_id());
  
  	if (counters == NULL)
@@ -865767,7 +924508,7 @@
  	loc_cpu_entry = private->entries[raw_smp_processor_id()];
  	/* ... then copy entire thing ... */
  	if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
-@@ -767,23 +784,159 @@ static int copy_entries_to_user(unsigned int total_size,
+@@ -767,23 +785,160 @@ static int copy_entries_to_user(unsigned int total_size,
  	return ret;
  }
  
@@ -865784,7 +924525,7 @@
 +}
 +
 +static int compat_standard_to_user(void __user *dst, void *src)
- {
++{
 +	compat_int_t cv = *(int *)src;
 +
 +	if (cv > 0)
@@ -865823,7 +924564,7 @@
 +
 +static int compat_table_info(const struct xt_table_info *info,
 +			     struct xt_table_info *newinfo)
-+{
+ {
 +	void *loc_cpu_entry;
 +
 +	if (!newinfo || !info)
@@ -865839,7 +924580,7 @@
 +}
 +#endif
 +
-+static int get_info(void __user *user, int *len, int compat)
++static int get_info(struct net *net, void __user *user, int *len, int compat)
 +{
 +	char name[ARPT_TABLE_MAXNAMELEN];
 +	struct arpt_table *t;
@@ -865859,7 +924600,7 @@
 +	if (compat)
 +		xt_compat_lock(NF_ARP);
 +#endif
-+	t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
++	t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
 +				    "arptable_%s", name);
 +	if (t && !IS_ERR(t)) {
 +		struct arpt_getinfo info;
@@ -865897,7 +924638,8 @@
 +	return ret;
 +}
 +
-+static int get_entries(struct arpt_get_entries __user *uptr, int *len)
++static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
++		       int *len)
 +{
 +	int ret;
 +	struct arpt_get_entries get;
@@ -865916,7 +924658,7 @@
 +		return -EINVAL;
 +	}
 +
-+	t = xt_find_table_lock(NF_ARP, get.name);
++	t = xt_find_table_lock(net, NF_ARP, get.name);
  	if (t && !IS_ERR(t)) {
  		struct xt_table_info *private = t->private;
  		duprintf("t->private->number = %u\n",
@@ -865932,12 +924674,13 @@
  			ret = -EINVAL;
  		}
  		module_put(t->me);
-@@ -794,71 +947,41 @@ static int get_entries(const struct arpt_get_entries *entries,
+@@ -794,71 +949,42 @@ static int get_entries(const struct arpt_get_entries *entries,
  	return ret;
  }
  
 -static int do_replace(void __user *user, unsigned int len)
-+static int __do_replace(const char *name, unsigned int valid_hooks,
++static int __do_replace(struct net *net, const char *name,
++			unsigned int valid_hooks,
 +			struct xt_table_info *newinfo,
 +			unsigned int num_counters,
 +			void __user *counters_ptr)
@@ -865952,8 +924695,7 @@
 -
 -	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 -		return -EFAULT;
-+	void *loc_cpu_old_entry;
- 
+-
 -	/* Hack: Causes ipchains to give correct error msg --RR */
 -	if (len != sizeof(tmp) + tmp.size)
 -		return -ENOPROTOOPT;
@@ -865976,7 +924718,8 @@
 -		ret = -EFAULT;
 -		goto free_newinfo;
 -	}
--
++	void *loc_cpu_old_entry;
+ 
 -	counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
 +	ret = 0;
 +	counters = vmalloc_node(num_counters * sizeof(struct xt_counters),
@@ -865997,7 +924740,7 @@
 -
 -	t = try_then_request_module(xt_find_table_lock(NF_ARP, tmp.name),
 -				    "arptable_%s", tmp.name);
-+	t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
++	t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
 +				    "arptable_%s", name);
  	if (!t || IS_ERR(t)) {
  		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -866019,7 +924762,7 @@
  	if (!oldinfo)
  		goto put_module;
  
-@@ -876,11 +999,12 @@ static int do_replace(void __user *user, unsigned int len)
+@@ -876,11 +1002,12 @@ static int do_replace(void __user *user, unsigned int len)
  	get_counters(oldinfo, counters);
  	/* Decrease module usage counts and free resource */
  	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
@@ -866035,7 +924778,7 @@
  		ret = -EFAULT;
  	vfree(counters);
  	xt_table_unlock(t);
-@@ -890,9 +1014,53 @@ static int do_replace(void __user *user, unsigned int len)
+@@ -890,9 +1017,53 @@ static int do_replace(void __user *user, unsigned int len)
  	module_put(t->me);
  	xt_table_unlock(t);
   free_newinfo_counters_untrans:
@@ -866046,7 +924789,7 @@
 +	return ret;
 +}
 +
-+static int do_replace(void __user *user, unsigned int len)
++static int do_replace(struct net *net, void __user *user, unsigned int len)
 +{
 +	int ret;
 +	struct arpt_replace tmp;
@@ -866080,7 +924823,7 @@
 +
 +	duprintf("arp_tables: Translated table\n");
 +
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, tmp.counters);
 +	if (ret)
 +		goto free_newinfo_untrans;
@@ -866091,12 +924834,13 @@
   free_newinfo:
  	xt_free_table_info(newinfo);
  	return ret;
-@@ -912,31 +1080,59 @@ static inline int add_counter_to_entry(struct arpt_entry *e,
+@@ -912,31 +1083,60 @@ static inline int add_counter_to_entry(struct arpt_entry *e,
  	return 0;
  }
  
 -static int do_add_counters(void __user *user, unsigned int len)
-+static int do_add_counters(void __user *user, unsigned int len, int compat)
++static int do_add_counters(struct net *net, void __user *user, unsigned int len,
++			   int compat)
  {
  	unsigned int i;
 -	struct xt_counters_info tmp, *paddc;
@@ -866154,11 +924898,11 @@
  	}
  
 -	t = xt_find_table_lock(NF_ARP, tmp.name);
-+	t = xt_find_table_lock(NF_ARP, name);
++	t = xt_find_table_lock(net, NF_ARP, name);
  	if (!t || IS_ERR(t)) {
  		ret = t ? PTR_ERR(t) : -ENOENT;
  		goto free;
-@@ -944,7 +1140,7 @@ static int do_add_counters(void __user *user, unsigned int len)
+@@ -944,7 +1144,7 @@ static int do_add_counters(void __user *user, unsigned int len)
  
  	write_lock_bh(&t->lock);
  	private = t->private;
@@ -866167,7 +924911,7 @@
  		ret = -EINVAL;
  		goto unlock_up_free;
  	}
-@@ -955,7 +1151,7 @@ static int do_add_counters(void __user *user, unsigned int len)
+@@ -955,7 +1155,7 @@ static int do_add_counters(void __user *user, unsigned int len)
  	ARPT_ENTRY_ITERATE(loc_cpu_entry,
  			   private->size,
  			   add_counter_to_entry,
@@ -866176,7 +924920,7 @@
  			   &i);
   unlock_up_free:
  	write_unlock_bh(&t->lock);
-@@ -967,7 +1163,329 @@ static int do_add_counters(void __user *user, unsigned int len)
+@@ -967,7 +1167,330 @@ static int do_add_counters(void __user *user, unsigned int len)
  	return ret;
  }
  
@@ -866453,7 +925197,8 @@
 +	struct compat_arpt_entry	entries[0];
 +};
 +
-+static int compat_do_replace(void __user *user, unsigned int len)
++static int compat_do_replace(struct net *net, void __user *user,
++			     unsigned int len)
 +{
 +	int ret;
 +	struct compat_arpt_replace tmp;
@@ -866489,7 +925234,7 @@
 +
 +	duprintf("compat_do_replace: Translated table\n");
 +
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, compat_ptr(tmp.counters));
 +	if (ret)
 +		goto free_newinfo_untrans;
@@ -866507,21 +925252,21 @@
  {
  	int ret;
  
-@@ -976,11 +1494,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
+@@ -976,11 +1499,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
  
  	switch (cmd) {
  	case ARPT_SO_SET_REPLACE:
 -		ret = do_replace(user, len);
-+		ret = compat_do_replace(user, len);
++		ret = compat_do_replace(sk->sk_net, user, len);
  		break;
  
  	case ARPT_SO_SET_ADD_COUNTERS:
 -		ret = do_add_counters(user, len);
-+		ret = do_add_counters(user, len, 1);
++		ret = do_add_counters(sk->sk_net, user, len, 1);
  		break;
  
  	default:
-@@ -991,74 +1509,190 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
+@@ -991,74 +1514,191 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
  	return ret;
  }
  
@@ -866554,10 +925299,7 @@
 +
 +	*dstptr += sizeof(struct compat_arpt_entry);
 +	*size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
- 
--		if (*len != sizeof(struct arpt_getinfo)) {
--			duprintf("length %u != %Zu\n", *len,
--				 sizeof(struct arpt_getinfo));
++
 +	target_offset = e->target_offset - (origsize - *size);
 +
 +	t = arpt_get_target(e);
@@ -866609,8 +925351,12 @@
 +	compat_uint_t size;
 +	struct compat_arpt_entry entrytable[0];
 +};
-+
-+static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
+ 
+-		if (*len != sizeof(struct arpt_getinfo)) {
+-			duprintf("length %u != %Zu\n", *len,
+-				 sizeof(struct arpt_getinfo));
++static int compat_get_entries(struct net *net,
++			      struct compat_arpt_get_entries __user *uptr,
 +			      int *len)
 +{
 +	int ret;
@@ -866630,7 +925376,7 @@
 +	}
 +
 +	xt_compat_lock(NF_ARP);
-+	t = xt_find_table_lock(NF_ARP, get.name);
++	t = xt_find_table_lock(net, NF_ARP, get.name);
 +	if (t && !IS_ERR(t)) {
 +		struct xt_table_info *private = t->private;
 +		struct xt_table_info info;
@@ -866697,10 +925443,10 @@
 +
 +	switch (cmd) {
 +	case ARPT_SO_GET_INFO:
-+		ret = get_info(user, len, 1);
++		ret = get_info(sk->sk_net, user, len, 1);
 +		break;
 +	case ARPT_SO_GET_ENTRIES:
-+		ret = compat_get_entries(user, len);
++		ret = compat_get_entries(sk->sk_net, user, len);
 +		break;
 +	default:
 +		ret = do_arpt_get_ctl(sk, cmd, user, len);
@@ -866709,13 +925455,16 @@
 +	return ret;
 +}
 +#endif
- 
--	case ARPT_SO_GET_ENTRIES: {
--		struct arpt_get_entries get;
++
 +static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 +{
 +	int ret;
  
+-	case ARPT_SO_GET_ENTRIES: {
+-		struct arpt_get_entries get;
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
+ 
 -		if (*len < sizeof(get)) {
 -			duprintf("get_entries: %u < %Zu\n", *len, sizeof(get));
 -			ret = -EINVAL;
@@ -866727,16 +925476,13 @@
 -			ret = -EINVAL;
 -		} else
 -			ret = get_entries(&get, user);
-+	if (!capable(CAP_NET_ADMIN))
-+		return -EPERM;
-+
 +	switch (cmd) {
 +	case ARPT_SO_SET_REPLACE:
-+		ret = do_replace(user, len);
++		ret = do_replace(sk->sk_net, user, len);
 +		break;
 +
 +	case ARPT_SO_SET_ADD_COUNTERS:
-+		ret = do_add_counters(user, len, 0);
++		ret = do_add_counters(sk->sk_net, user, len, 0);
  		break;
 +
 +	default:
@@ -866756,17 +925502,25 @@
 +
 +	switch (cmd) {
 +	case ARPT_SO_GET_INFO:
-+		ret = get_info(user, len, 0);
++		ret = get_info(sk->sk_net, user, len, 0);
 +		break;
 +
 +	case ARPT_SO_GET_ENTRIES:
-+		ret = get_entries(user, len);
++		ret = get_entries(sk->sk_net, user, len);
 +		break;
 +
  	case ARPT_SO_GET_REVISION_TARGET: {
  		struct xt_get_revision rev;
  
-@@ -1090,7 +1724,7 @@ int arpt_register_table(struct arpt_table *table,
+@@ -1085,19 +1725,21 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
+ 	return ret;
+ }
+ 
+-int arpt_register_table(struct arpt_table *table,
+-			const struct arpt_replace *repl)
++struct arpt_table *arpt_register_table(struct net *net,
++				       struct arpt_table *table,
++				       const struct arpt_replace *repl)
  {
  	int ret;
  	struct xt_table_info *newinfo;
@@ -866774,8 +925528,63 @@
 +	struct xt_table_info bootstrap
  		= { 0, 0, 0, { 0 }, { 0 }, { } };
  	void *loc_cpu_entry;
++	struct xt_table *new_table;
+ 
+ 	newinfo = xt_alloc_table_info(repl->size);
+ 	if (!newinfo) {
+ 		ret = -ENOMEM;
+-		return ret;
++		goto out;
+ 	}
+ 
+ 	/* choose the copy on our node/cpu */
+@@ -1111,24 +1753,27 @@ int arpt_register_table(struct arpt_table *table,
+ 			      repl->underflow);
+ 
+ 	duprintf("arpt_register_table: translate table gives %d\n", ret);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
+-	}
++	if (ret != 0)
++		goto out_free;
+ 
+-	ret = xt_register_table(table, &bootstrap, newinfo);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
++	new_table = xt_register_table(net, table, &bootstrap, newinfo);
++	if (IS_ERR(new_table)) {
++		ret = PTR_ERR(new_table);
++		goto out_free;
+ 	}
++	return new_table;
+ 
+-	return 0;
++out_free:
++	xt_free_table_info(newinfo);
++out:
++	return ERR_PTR(ret);
+ }
+ 
+ void arpt_unregister_table(struct arpt_table *table)
+ {
+ 	struct xt_table_info *private;
+ 	void *loc_cpu_entry;
++	struct module *table_owner = table->me;
  
-@@ -1144,6 +1778,11 @@ static struct arpt_target arpt_standard_target __read_mostly = {
+ 	private = xt_unregister_table(table);
+ 
+@@ -1136,6 +1781,8 @@ void arpt_unregister_table(struct arpt_table *table)
+ 	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ 	ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
+ 			   cleanup_entry, NULL);
++	if (private->number > private->initial_entries)
++		module_put(table_owner);
+ 	xt_free_table_info(private);
+ }
+ 
+@@ -1144,6 +1791,11 @@ static struct arpt_target arpt_standard_target __read_mostly = {
  	.name		= ARPT_STANDARD_TARGET,
  	.targetsize	= sizeof(int),
  	.family		= NF_ARP,
@@ -866787,7 +925596,7 @@
  };
  
  static struct arpt_target arpt_error_target __read_mostly = {
-@@ -1158,9 +1797,15 @@ static struct nf_sockopt_ops arpt_sockopts = {
+@@ -1158,17 +1810,38 @@ static struct nf_sockopt_ops arpt_sockopts = {
  	.set_optmin	= ARPT_BASE_CTL,
  	.set_optmax	= ARPT_SO_SET_MAX+1,
  	.set		= do_arpt_set_ctl,
@@ -866803,12 +925612,67 @@
  	.owner		= THIS_MODULE,
  };
  
++static int __net_init arp_tables_net_init(struct net *net)
++{
++	return xt_proto_init(net, NF_ARP);
++}
++
++static void __net_exit arp_tables_net_exit(struct net *net)
++{
++	xt_proto_fini(net, NF_ARP);
++}
++
++static struct pernet_operations arp_tables_net_ops = {
++	.init = arp_tables_net_init,
++	.exit = arp_tables_net_exit,
++};
++
+ static int __init arp_tables_init(void)
+ {
+ 	int ret;
+ 
+-	ret = xt_proto_init(NF_ARP);
++	ret = register_pernet_subsys(&arp_tables_net_ops);
+ 	if (ret < 0)
+ 		goto err1;
+ 
+@@ -1193,7 +1866,7 @@ err4:
+ err3:
+ 	xt_unregister_target(&arpt_standard_target);
+ err2:
+-	xt_proto_fini(NF_ARP);
++	unregister_pernet_subsys(&arp_tables_net_ops);
+ err1:
+ 	return ret;
+ }
+@@ -1203,7 +1876,7 @@ static void __exit arp_tables_fini(void)
+ 	nf_unregister_sockopt(&arpt_sockopts);
+ 	xt_unregister_target(&arpt_error_target);
+ 	xt_unregister_target(&arpt_standard_target);
+-	xt_proto_fini(NF_ARP);
++	unregister_pernet_subsys(&arp_tables_net_ops);
+ }
+ 
+ EXPORT_SYMBOL(arpt_register_table);
 diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
-index 302d3da..7201511 100644
+index 302d3da..4e9c496 100644
 --- a/net/ipv4/netfilter/arptable_filter.c
 +++ b/net/ipv4/netfilter/arptable_filter.c
-@@ -64,7 +64,7 @@ static unsigned int arpt_hook(unsigned int hook,
- 	return arpt_do_table(skb, hook, in, out, &packet_filter);
+@@ -20,7 +20,7 @@ static struct
+ 	struct arpt_replace repl;
+ 	struct arpt_standard entries[3];
+ 	struct arpt_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "filter",
+ 		.valid_hooks = FILTER_VALID_HOOKS,
+@@ -61,10 +61,10 @@ static unsigned int arpt_hook(unsigned int hook,
+ 			      const struct net_device *out,
+ 			      int (*okfn)(struct sk_buff *))
+ {
+-	return arpt_do_table(skb, hook, in, out, &packet_filter);
++	return arpt_do_table(skb, hook, in, out, init_net.ipv4.arptable_filter);
  }
  
 -static struct nf_hook_ops arpt_ops[] = {
@@ -866816,8 +925680,59 @@
  	{
  		.hook		= arpt_hook,
  		.owner		= THIS_MODULE,
+@@ -85,12 +85,31 @@ static struct nf_hook_ops arpt_ops[] = {
+ 	},
+ };
+ 
++static int __net_init arptable_filter_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv4.arptable_filter =
++		arpt_register_table(net, &packet_filter, &initial_table.repl);
++	if (IS_ERR(net->ipv4.arptable_filter))
++		return PTR_ERR(net->ipv4.arptable_filter);
++	return 0;
++}
++
++static void __net_exit arptable_filter_net_exit(struct net *net)
++{
++	arpt_unregister_table(net->ipv4.arptable_filter);
++}
++
++static struct pernet_operations arptable_filter_net_ops = {
++	.init = arptable_filter_net_init,
++	.exit = arptable_filter_net_exit,
++};
++
+ static int __init arptable_filter_init(void)
+ {
+ 	int ret;
+ 
+-	/* Register table */
+-	ret = arpt_register_table(&packet_filter, &initial_table.repl);
++	ret = register_pernet_subsys(&arptable_filter_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -100,14 +119,14 @@ static int __init arptable_filter_init(void)
+ 	return ret;
+ 
+ cleanup_table:
+-	arpt_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&arptable_filter_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit arptable_filter_fini(void)
+ {
+ 	nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
+-	arpt_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&arptable_filter_net_ops);
+ }
+ 
+ module_init(arptable_filter_init);
 diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
-index 14d64a3..5109839 100644
+index 14d64a3..6bda110 100644
 --- a/net/ipv4/netfilter/ip_queue.c
 +++ b/net/ipv4/netfilter/ip_queue.c
 @@ -28,19 +28,15 @@
@@ -867133,9 +926048,19 @@
  }
  
  #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
-@@ -588,26 +526,6 @@ static ctl_table ipq_table[] = {
+@@ -574,6 +512,7 @@ static struct notifier_block ipq_nl_notifier = {
+ 	.notifier_call	= ipq_rcv_nl_event,
+ };
+ 
++#ifdef CONFIG_SYSCTL
+ static struct ctl_table_header *ipq_sysctl_header;
+ 
+ static ctl_table ipq_table[] = {
+@@ -587,27 +526,9 @@ static ctl_table ipq_table[] = {
+ 	},
  	{ .ctl_name = 0 }
  };
++#endif
  
 -static ctl_table ipq_dir_table[] = {
 -	{
@@ -867157,44 +926082,79 @@
 -	{ .ctl_name = 0 }
 -};
 -
++#ifdef CONFIG_PROC_FS
  static int ip_queue_show(struct seq_file *m, void *v)
  {
  	read_lock_bh(&queue_lock);
-@@ -645,7 +563,7 @@ static const struct file_operations ip_queue_proc_fops = {
+@@ -644,8 +565,9 @@ static const struct file_operations ip_queue_proc_fops = {
+ 	.release	= single_release,
  	.owner		= THIS_MODULE,
  };
++#endif
  
 -static struct nf_queue_handler nfqh = {
 +static const struct nf_queue_handler nfqh = {
  	.name	= "ip_queue",
  	.outfn	= &ipq_enqueue_packet,
  };
-@@ -673,7 +591,7 @@ static int __init ip_queue_init(void)
+@@ -653,7 +575,7 @@ static struct nf_queue_handler nfqh = {
+ static int __init ip_queue_init(void)
+ {
+ 	int status = -ENOMEM;
+-	struct proc_dir_entry *proc;
++	struct proc_dir_entry *proc __maybe_unused;
+ 
+ 	netlink_register_notifier(&ipq_nl_notifier);
+ 	ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0,
+@@ -663,6 +585,7 @@ static int __init ip_queue_init(void)
+ 		goto cleanup_netlink_notifier;
  	}
  
++#ifdef CONFIG_PROC_FS
+ 	proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net);
+ 	if (proc) {
+ 		proc->owner = THIS_MODULE;
+@@ -671,10 +594,11 @@ static int __init ip_queue_init(void)
+ 		printk(KERN_ERR "ip_queue: failed to create proc entry\n");
+ 		goto cleanup_ipqnl;
+ 	}
+-
++#endif
  	register_netdevice_notifier(&ipq_dev_notifier);
 -	ipq_sysctl_header = register_sysctl_table(ipq_root_table);
+-
++#ifdef CONFIG_SYSCTL
 +	ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table);
- 
++#endif
  	status = nf_register_queue_handler(PF_INET, &nfqh);
  	if (status < 0) {
-@@ -687,7 +605,7 @@ cleanup_sysctl:
+ 		printk(KERN_ERR "ip_queue: failed to register queue handler\n");
+@@ -683,11 +607,13 @@ static int __init ip_queue_init(void)
+ 	return status;
+ 
+ cleanup_sysctl:
++#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(ipq_sysctl_header);
++#endif
  	unregister_netdevice_notifier(&ipq_dev_notifier);
  	proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
- cleanup_ipqnl:
+-cleanup_ipqnl:
 -	sock_release(ipqnl->sk_socket);
++cleanup_ipqnl: __maybe_unused
 +	netlink_kernel_release(ipqnl);
  	mutex_lock(&ipqnl_mutex);
  	mutex_unlock(&ipqnl_mutex);
  
-@@ -700,13 +618,13 @@ static void __exit ip_queue_fini(void)
+@@ -700,13 +626,15 @@ static void __exit ip_queue_fini(void)
  {
  	nf_unregister_queue_handlers(&nfqh);
  	synchronize_net();
 -	ipq_flush(NF_DROP);
 +	ipq_flush(NULL, 0);
  
++#ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(ipq_sysctl_header);
++#endif
  	unregister_netdevice_notifier(&ipq_dev_notifier);
  	proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
  
@@ -867204,7 +926164,7 @@
  	mutex_unlock(&ipqnl_mutex);
  
 diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
-index b9b189c..982b7f9 100644
+index b9b189c..600737f 100644
 --- a/net/ipv4/netfilter/ip_tables.c
 +++ b/net/ipv4/netfilter/ip_tables.c
 @@ -26,6 +26,7 @@
@@ -867356,6 +926316,15 @@
  static inline int
  get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
  		      char *hookname, char **chainname,
+@@ -284,7 +291,7 @@ static void trace_packet(struct sk_buff *skb,
+ 			 unsigned int hook,
+ 			 const struct net_device *in,
+ 			 const struct net_device *out,
+-			 char *tablename,
++			 const char *tablename,
+ 			 struct xt_table_info *private,
+ 			 struct ipt_entry *e)
+ {
 @@ -465,10 +472,9 @@ mark_source_chains(struct xt_table_info *newinfo,
  
  	/* No recursion; use packet counter to save back ptrs (reset
@@ -867642,7 +926611,7 @@
  	memcpy(dst, &v, sizeof(v));
  }
  
-@@ -1079,64 +1034,61 @@ static int compat_standard_to_user(void __user *dst, void *src)
+@@ -1079,76 +1034,73 @@ static int compat_standard_to_user(void __user *dst, void *src)
  	compat_int_t cv = *(int *)src;
  
  	if (cv > 0)
@@ -867726,7 +926695,11 @@
  }
  #endif
  
-@@ -1147,8 +1099,8 @@ static int get_info(void __user *user, int *len, int compat)
+-static int get_info(void __user *user, int *len, int compat)
++static int get_info(struct net *net, void __user *user, int *len, int compat)
+ {
+ 	char name[IPT_TABLE_MAXNAMELEN];
+ 	struct xt_table *t;
  	int ret;
  
  	if (*len != sizeof(struct ipt_getinfo)) {
@@ -867737,11 +926710,13 @@
  		return -EINVAL;
  	}
  
-@@ -1161,7 +1113,7 @@ static int get_info(void __user *user, int *len, int compat)
+@@ -1160,8 +1112,8 @@ static int get_info(void __user *user, int *len, int compat)
+ 	if (compat)
  		xt_compat_lock(AF_INET);
  #endif
- 	t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+-	t = try_then_request_module(xt_find_table_lock(AF_INET, name),
 -			"iptable_%s", name);
++	t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
 +				    "iptable_%s", name);
  	if (t && !IS_ERR(t)) {
  		struct ipt_getinfo info;
@@ -867766,7 +926741,15 @@
  		info.num_entries = private->number;
  		info.size = private->size;
  		strcpy(info.name, name);
-@@ -1207,31 +1159,27 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
+@@ -1200,38 +1152,34 @@ static int get_info(void __user *user, int *len, int compat)
+ }
+ 
+ static int
+-get_entries(struct ipt_get_entries __user *uptr, int *len)
++get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
+ {
+ 	int ret;
+ 	struct ipt_get_entries get;
  	struct xt_table *t;
  
  	if (*len < sizeof(get)) {
@@ -867786,7 +926769,8 @@
  		return -EINVAL;
  	}
  
- 	t = xt_find_table_lock(AF_INET, get.name);
+-	t = xt_find_table_lock(AF_INET, get.name);
++	t = xt_find_table_lock(net, AF_INET, get.name);
  	if (t && !IS_ERR(t)) {
  		struct xt_table_info *private = t->private;
 -		duprintf("t->private->number = %u\n",
@@ -867803,17 +926787,28 @@
  			ret = -EINVAL;
  		}
  		module_put(t->me);
-@@ -1244,8 +1192,8 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
+@@ -1243,9 +1191,9 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
+ }
  
  static int
- __do_replace(const char *name, unsigned int valid_hooks,
+-__do_replace(const char *name, unsigned int valid_hooks,
 -		struct xt_table_info *newinfo, unsigned int num_counters,
 -		void __user *counters_ptr)
++__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 +	     struct xt_table_info *newinfo, unsigned int num_counters,
 +	     void __user *counters_ptr)
  {
  	int ret;
  	struct xt_table *t;
+@@ -1260,7 +1208,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
+ 		goto out;
+ 	}
+ 
+-	t = try_then_request_module(xt_find_table_lock(AF_INET, name),
++	t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
+ 				    "iptable_%s", name);
+ 	if (!t || IS_ERR(t)) {
+ 		ret = t ? PTR_ERR(t) : -ENOENT;
 @@ -1293,7 +1241,8 @@ __do_replace(const char *name, unsigned int valid_hooks,
  	get_counters(oldinfo, counters);
  	/* Decrease module usage counts and free resource */
@@ -867824,6 +926819,15 @@
  	xt_free_table_info(oldinfo);
  	if (copy_to_user(counters_ptr, counters,
  			 sizeof(struct xt_counters) * num_counters) != 0)
+@@ -1312,7 +1261,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
+ }
+ 
+ static int
+-do_replace(void __user *user, unsigned int len)
++do_replace(struct net *net, void __user *user, unsigned int len)
+ {
+ 	int ret;
+ 	struct ipt_replace tmp;
 @@ -1322,14 +1271,7 @@ do_replace(void __user *user, unsigned int len)
  	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
  		return -EFAULT;
@@ -867855,7 +926859,7 @@
 -	ret = __do_replace(tmp.name, tmp.valid_hooks,
 -			      newinfo, tmp.num_counters,
 -			      tmp.counters);
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, tmp.counters);
  	if (ret)
  		goto free_newinfo_untrans;
@@ -867876,7 +926880,25 @@
  add_counter_to_entry(struct ipt_entry *e,
  		     const struct xt_counters addme[],
  		     unsigned int *i)
-@@ -1479,19 +1420,13 @@ struct compat_ipt_replace {
+@@ -1390,7 +1331,7 @@ add_counter_to_entry(struct ipt_entry *e,
+ }
+ 
+ static int
+-do_add_counters(void __user *user, unsigned int len, int compat)
++do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
+ {
+ 	unsigned int i;
+ 	struct xt_counters_info tmp;
+@@ -1442,7 +1383,7 @@ do_add_counters(void __user *user, unsigned int len, int compat)
+ 		goto free;
+ 	}
+ 
+-	t = xt_find_table_lock(AF_INET, name);
++	t = xt_find_table_lock(net, AF_INET, name);
+ 	if (!t || IS_ERR(t)) {
+ 		ret = t ? PTR_ERR(t) : -ENOENT;
+ 		goto free;
+@@ -1479,22 +1420,16 @@ struct compat_ipt_replace {
  	u32			valid_hooks;
  	u32			num_entries;
  	u32			size;
@@ -867897,7 +926919,11 @@
 -
  static int
  compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
- 			  compat_uint_t *size, struct xt_counters *counters,
+-			  compat_uint_t *size, struct xt_counters *counters,
++			  unsigned int *size, struct xt_counters *counters,
+ 			  unsigned int *i)
+ {
+ 	struct ipt_entry_target *t;
 @@ -1513,7 +1448,9 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
  		goto out;
  
@@ -867923,7 +926949,7 @@
 +		       const char *name,
 +		       const struct ipt_ip *ip,
 +		       unsigned int hookmask,
-+		       int *size, int *i)
++		       int *size, unsigned int *i)
  {
  	struct xt_match *match;
  
@@ -867958,7 +926984,7 @@
  {
  	struct ipt_entry_target *t;
  
-@@ -1577,22 +1514,22 @@ compat_release_entry(struct ipt_entry *e, unsigned int *i)
+@@ -1577,27 +1514,28 @@ compat_release_entry(struct ipt_entry *e, unsigned int *i)
  		return 1;
  
  	/* Cleanup all matches */
@@ -867993,7 +927019,14 @@
  {
  	struct ipt_entry_target *t;
  	struct xt_target *target;
-@@ -1607,32 +1544,33 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
+ 	unsigned int entry_offset;
+-	int ret, off, h, j;
++	unsigned int j;
++	int ret, off, h;
+ 
+ 	duprintf("check_compat_entry_size_and_hooks %p\n", e);
+ 	if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
+@@ -1607,32 +1545,33 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
  	}
  
  	if (e->next_offset < sizeof(struct compat_ipt_entry) +
@@ -868036,7 +927069,7 @@
  		ret = target ? PTR_ERR(target) : -ENOENT;
  		goto release_matches;
  	}
-@@ -1640,12 +1578,12 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
+@@ -1640,12 +1579,12 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
  
  	off += xt_compat_target_offset(target);
  	*size += off;
@@ -868051,7 +927084,7 @@
  		if ((unsigned char *)e - base == hook_entries[h])
  			newinfo->hook_entry[h] = hook_entries[h];
  		if ((unsigned char *)e - base == underflows[h])
-@@ -1653,7 +1591,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
+@@ -1653,7 +1592,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
  	}
  
  	/* Clear counters and comefrom */
@@ -868060,7 +927093,7 @@
  	e->comefrom = 0;
  
  	(*i)++;
-@@ -1666,17 +1604,10 @@ release_matches:
+@@ -1666,17 +1605,10 @@ release_matches:
  	return ret;
  }
  
@@ -868082,7 +927115,7 @@
  {
  	struct ipt_entry_target *t;
  	struct xt_target *target;
-@@ -1688,19 +1619,22 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
+@@ -1688,19 +1620,22 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
  	origsize = *size;
  	de = (struct ipt_entry *)*dstptr;
  	memcpy(de, e, sizeof(struct ipt_entry));
@@ -868110,7 +927143,7 @@
  		if ((unsigned char *)de - base < newinfo->hook_entry[h])
  			newinfo->hook_entry[h] -= origsize - *size;
  		if ((unsigned char *)de - base < newinfo->underflow[h])
-@@ -1709,13 +1643,15 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
+@@ -1709,13 +1644,16 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
  	return ret;
  }
  
@@ -868120,7 +927153,9 @@
 +compat_check_entry(struct ipt_entry *e, const char *name,
 +				     unsigned int *i)
  {
- 	int j, ret;
+-	int j, ret;
++	unsigned int j;
++	int ret;
  
  	j = 0;
 -	ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
@@ -868129,7 +927164,7 @@
  	if (ret)
  		goto cleanup_matches;
  
-@@ -1733,13 +1669,13 @@ static inline int compat_check_entry(struct ipt_entry *e, const char *name,
+@@ -1733,13 +1671,13 @@ static inline int compat_check_entry(struct ipt_entry *e, const char *name,
  
  static int
  translate_compat_table(const char *name,
@@ -868150,7 +927185,7 @@
  {
  	unsigned int i, j;
  	struct xt_table_info *newinfo, *info;
-@@ -1753,7 +1689,7 @@ translate_compat_table(const char *name,
+@@ -1753,7 +1691,7 @@ translate_compat_table(const char *name,
  	info->number = number;
  
  	/* Init all hooks to impossible value. */
@@ -868159,7 +927194,7 @@
  		info->hook_entry[i] = 0xFFFFFFFF;
  		info->underflow[i] = 0xFFFFFFFF;
  	}
-@@ -1762,11 +1698,11 @@ translate_compat_table(const char *name,
+@@ -1762,11 +1700,11 @@ translate_compat_table(const char *name,
  	j = 0;
  	xt_compat_lock(AF_INET);
  	/* Walk through entries, checking offsets. */
@@ -868176,7 +927211,7 @@
  	if (ret != 0)
  		goto out_unlock;
  
-@@ -1778,7 +1714,7 @@ translate_compat_table(const char *name,
+@@ -1778,7 +1716,7 @@ translate_compat_table(const char *name,
  	}
  
  	/* Check hooks all assigned */
@@ -868185,7 +927220,7 @@
  		/* Only hooks which are valid */
  		if (!(valid_hooks & (1 << i)))
  			continue;
-@@ -1800,17 +1736,17 @@ translate_compat_table(const char *name,
+@@ -1800,17 +1738,17 @@ translate_compat_table(const char *name,
  		goto out_unlock;
  
  	newinfo->number = number;
@@ -868209,7 +927244,7 @@
  	xt_compat_unlock(AF_INET);
  	if (ret)
  		goto free_newinfo;
-@@ -1821,11 +1757,11 @@ translate_compat_table(const char *name,
+@@ -1821,11 +1759,11 @@ translate_compat_table(const char *name,
  
  	i = 0;
  	ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
@@ -868224,7 +927259,7 @@
  		IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
  		xt_free_table_info(newinfo);
  		return ret;
-@@ -1844,10 +1780,10 @@ translate_compat_table(const char *name,
+@@ -1844,16 +1782,16 @@ translate_compat_table(const char *name,
  free_newinfo:
  	xt_free_table_info(newinfo);
  out:
@@ -868237,7 +927272,14 @@
  	xt_compat_unlock(AF_INET);
  	goto out;
  }
-@@ -1863,13 +1799,8 @@ compat_do_replace(void __user *user, unsigned int len)
+ 
+ static int
+-compat_do_replace(void __user *user, unsigned int len)
++compat_do_replace(struct net *net, void __user *user, unsigned int len)
+ {
+ 	int ret;
+ 	struct compat_ipt_replace tmp;
+@@ -1863,13 +1801,8 @@ compat_do_replace(void __user *user, unsigned int len)
  	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
  		return -EFAULT;
  
@@ -868252,7 +927294,7 @@
  		return -ENOMEM;
  	if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
  		return -ENOMEM;
-@@ -1878,7 +1809,7 @@ compat_do_replace(void __user *user, unsigned int len)
+@@ -1878,7 +1811,7 @@ compat_do_replace(void __user *user, unsigned int len)
  	if (!newinfo)
  		return -ENOMEM;
  
@@ -868261,7 +927303,7 @@
  	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
  	if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
  			   tmp.size) != 0) {
-@@ -1887,22 +1818,22 @@ compat_do_replace(void __user *user, unsigned int len)
+@@ -1887,22 +1820,22 @@ compat_do_replace(void __user *user, unsigned int len)
  	}
  
  	ret = translate_compat_table(tmp.name, tmp.valid_hooks,
@@ -868278,7 +927320,7 @@
 -	ret = __do_replace(tmp.name, tmp.valid_hooks,
 -			      newinfo, tmp.num_counters,
 -			      compat_ptr(tmp.counters));
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, compat_ptr(tmp.counters));
  	if (ret)
  		goto free_newinfo_untrans;
@@ -868290,7 +927332,7 @@
   free_newinfo:
  	xt_free_table_info(newinfo);
  	return ret;
-@@ -1910,7 +1841,7 @@ compat_do_replace(void __user *user, unsigned int len)
+@@ -1910,7 +1843,7 @@ compat_do_replace(void __user *user, unsigned int len)
  
  static int
  compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
@@ -868299,7 +927341,21 @@
  {
  	int ret;
  
-@@ -1934,15 +1865,15 @@ compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
+@@ -1919,11 +1852,11 @@ compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
+ 
+ 	switch (cmd) {
+ 	case IPT_SO_SET_REPLACE:
+-		ret = compat_do_replace(user, len);
++		ret = compat_do_replace(sk->sk_net, user, len);
+ 		break;
+ 
+ 	case IPT_SO_SET_ADD_COUNTERS:
+-		ret = do_add_counters(user, len, 1);
++		ret = do_add_counters(sk->sk_net, user, len, 1);
+ 		break;
+ 
+ 	default:
+@@ -1934,15 +1867,15 @@ compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
  	return ret;
  }
  
@@ -868319,7 +927375,15 @@
  {
  	struct xt_counters *counters;
  	struct xt_table_info *private = table->private;
-@@ -1978,10 +1909,8 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
+@@ -1972,16 +1905,15 @@ static int compat_copy_entries_to_user(unsigned int total_size,
+ }
+ 
+ static int
+-compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
++compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
++		   int *len)
+ {
+ 	int ret;
  	struct compat_ipt_get_entries get;
  	struct xt_table *t;
  
@@ -868331,7 +927395,7 @@
  		return -EINVAL;
  	}
  
-@@ -1989,9 +1918,8 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
+@@ -1989,30 +1921,27 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
  		return -EFAULT;
  
  	if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
@@ -868343,7 +927407,9 @@
  		return -EINVAL;
  	}
  
-@@ -2000,19 +1928,17 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
+ 	xt_compat_lock(AF_INET);
+-	t = xt_find_table_lock(AF_INET, get.name);
++	t = xt_find_table_lock(net, AF_INET, get.name);
  	if (t && !IS_ERR(t)) {
  		struct xt_table_info *private = t->private;
  		struct xt_table_info info;
@@ -868367,7 +927433,20 @@
  		module_put(t->me);
  		xt_table_unlock(t);
  	} else
-@@ -2047,7 +1973,7 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+@@ -2034,10 +1963,10 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+ 
+ 	switch (cmd) {
+ 	case IPT_SO_GET_INFO:
+-		ret = get_info(user, len, 1);
++		ret = get_info(sk->sk_net, user, len, 1);
+ 		break;
+ 	case IPT_SO_GET_ENTRIES:
+-		ret = compat_get_entries(user, len);
++		ret = compat_get_entries(sk->sk_net, user, len);
+ 		break;
+ 	default:
+ 		ret = do_ipt_get_ctl(sk, cmd, user, len);
+@@ -2047,7 +1976,7 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
  #endif
  
  static int
@@ -868376,7 +927455,41 @@
  {
  	int ret;
  
-@@ -2126,7 +2052,7 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
+@@ -2056,11 +1985,11 @@ do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user, unsigned int len)
+ 
+ 	switch (cmd) {
+ 	case IPT_SO_SET_REPLACE:
+-		ret = do_replace(user, len);
++		ret = do_replace(sk->sk_net, user, len);
+ 		break;
+ 
+ 	case IPT_SO_SET_ADD_COUNTERS:
+-		ret = do_add_counters(user, len, 0);
++		ret = do_add_counters(sk->sk_net, user, len, 0);
+ 		break;
+ 
+ 	default:
+@@ -2081,11 +2010,11 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+ 
+ 	switch (cmd) {
+ 	case IPT_SO_GET_INFO:
+-		ret = get_info(user, len, 0);
++		ret = get_info(sk->sk_net, user, len, 0);
+ 		break;
+ 
+ 	case IPT_SO_GET_ENTRIES:
+-		ret = get_entries(user, len);
++		ret = get_entries(sk->sk_net, user, len);
+ 		break;
+ 
+ 	case IPT_SO_GET_REVISION_MATCH:
+@@ -2122,21 +2051,23 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+ 	return ret;
+ }
+ 
+-int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
++struct xt_table *ipt_register_table(struct net *net, struct xt_table *table,
++				    const struct ipt_replace *repl)
  {
  	int ret;
  	struct xt_table_info *newinfo;
@@ -868384,10 +927497,15 @@
 +	struct xt_table_info bootstrap
  		= { 0, 0, 0, { 0 }, { 0 }, { } };
  	void *loc_cpu_entry;
++	struct xt_table *new_table;
  
-@@ -2134,9 +2060,7 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
- 	if (!newinfo)
- 		return -ENOMEM;
+ 	newinfo = xt_alloc_table_info(repl->size);
+-	if (!newinfo)
+-		return -ENOMEM;
++	if (!newinfo) {
++		ret = -ENOMEM;
++		goto out;
++	}
  
 -	/* choose the copy on our node/cpu
 -	 * but dont care of preemption
@@ -868396,7 +927514,53 @@
  	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
  	memcpy(loc_cpu_entry, repl->entries, repl->size);
  
-@@ -2178,7 +2102,8 @@ icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
+@@ -2145,30 +2076,36 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
+ 			      repl->num_entries,
+ 			      repl->hook_entry,
+ 			      repl->underflow);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
+-	}
++	if (ret != 0)
++		goto out_free;
+ 
+-	ret = xt_register_table(table, &bootstrap, newinfo);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
++	new_table = xt_register_table(net, table, &bootstrap, newinfo);
++	if (IS_ERR(new_table)) {
++		ret = PTR_ERR(new_table);
++		goto out_free;
+ 	}
+ 
+-	return 0;
++	return new_table;
++
++out_free:
++	xt_free_table_info(newinfo);
++out:
++	return ERR_PTR(ret);
+ }
+ 
+ void ipt_unregister_table(struct xt_table *table)
+ {
+ 	struct xt_table_info *private;
+ 	void *loc_cpu_entry;
++	struct module *table_owner = table->me;
+ 
+ 	private = xt_unregister_table(table);
+ 
+ 	/* Decrease module usage counts and free resources */
+ 	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ 	IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
++	if (private->number > private->initial_entries)
++		module_put(table_owner);
+ 	xt_free_table_info(private);
+ }
+ 
+@@ -2178,7 +2115,8 @@ icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
  		     u_int8_t type, u_int8_t code,
  		     bool invert)
  {
@@ -868406,7 +927570,7 @@
  		^ invert;
  }
  
-@@ -2219,7 +2144,7 @@ icmp_match(const struct sk_buff *skb,
+@@ -2219,7 +2157,7 @@ icmp_match(const struct sk_buff *skb,
  /* Called when user tries to insert an entry of this type. */
  static bool
  icmp_checkentry(const char *tablename,
@@ -868415,7 +927579,7 @@
  	   const struct xt_match *match,
  	   void *matchinfo,
  	   unsigned int hook_mask)
-@@ -2270,9 +2195,9 @@ static struct xt_match icmp_matchstruct __read_mostly = {
+@@ -2270,16 +2208,31 @@ static struct xt_match icmp_matchstruct __read_mostly = {
  	.name		= "icmp",
  	.match		= icmp_match,
  	.matchsize	= sizeof(struct ipt_icmp),
@@ -868423,11 +927587,52 @@
  	.proto		= IPPROTO_ICMP,
  	.family		= AF_INET,
 -	.checkentry	= icmp_checkentry,
++};
++
++static int __net_init ip_tables_net_init(struct net *net)
++{
++	return xt_proto_init(net, AF_INET);
++}
++
++static void __net_exit ip_tables_net_exit(struct net *net)
++{
++	xt_proto_fini(net, AF_INET);
++}
++
++static struct pernet_operations ip_tables_net_ops = {
++	.init = ip_tables_net_init,
++	.exit = ip_tables_net_exit,
  };
  
  static int __init ip_tables_init(void)
+ {
+ 	int ret;
+ 
+-	ret = xt_proto_init(AF_INET);
++	ret = register_pernet_subsys(&ip_tables_net_ops);
+ 	if (ret < 0)
+ 		goto err1;
+ 
+@@ -2309,7 +2262,7 @@ err4:
+ err3:
+ 	xt_unregister_target(&ipt_standard_target);
+ err2:
+-	xt_proto_fini(AF_INET);
++	unregister_pernet_subsys(&ip_tables_net_ops);
+ err1:
+ 	return ret;
+ }
+@@ -2322,7 +2275,7 @@ static void __exit ip_tables_fini(void)
+ 	xt_unregister_target(&ipt_error_target);
+ 	xt_unregister_target(&ipt_standard_target);
+ 
+-	xt_proto_fini(AF_INET);
++	unregister_pernet_subsys(&ip_tables_net_ops);
+ }
+ 
+ EXPORT_SYMBOL(ipt_register_table);
 diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
-index 2f544da..1b31f7d 100644
+index 2f544da..c6cf84c 100644
 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
 +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
 @@ -32,7 +32,7 @@
@@ -868439,7 +927644,21 @@
  
  struct clusterip_config {
  	struct list_head list;			/* list of all configs */
-@@ -109,11 +109,9 @@ clusterip_config_entry_put(struct clusterip_config *c)
+@@ -76,13 +76,6 @@ clusterip_config_put(struct clusterip_config *c)
+ 		kfree(c);
+ }
+ 
+-/* increase the count of entries(rules) using/referencing this config */
+-static inline void
+-clusterip_config_entry_get(struct clusterip_config *c)
+-{
+-	atomic_inc(&c->entries);
+-}
+-
+ /* decrease the count of entries using/referencing this config.  If last
+  * entry(rule) is removed, remove the config from lists, but don't free it
+  * yet, since proc-files could still be holding references */
+@@ -109,11 +102,9 @@ clusterip_config_entry_put(struct clusterip_config *c)
  static struct clusterip_config *
  __clusterip_config_find(__be32 clusterip)
  {
@@ -868453,7 +927672,7 @@
  		if (c->clusterip == clusterip)
  			return c;
  	}
-@@ -275,7 +273,7 @@ clusterip_hashfn(const struct sk_buff *skb,
+@@ -275,7 +266,7 @@ clusterip_hashfn(const struct sk_buff *skb,
  	}
  
  	/* node numbers are 1..n, not 0..n */
@@ -868462,7 +927681,7 @@
  }
  
  static inline int
-@@ -289,12 +287,9 @@ clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
+@@ -289,12 +280,9 @@ clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
   ***********************************************************************/
  
  static unsigned int
@@ -868478,7 +927697,7 @@
  {
  	const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
  	struct nf_conn *ct;
-@@ -361,11 +356,9 @@ target(struct sk_buff *skb,
+@@ -361,11 +349,9 @@ target(struct sk_buff *skb,
  }
  
  static bool
@@ -868493,7 +927712,7 @@
  {
  	struct ipt_clusterip_tgt_info *cipinfo = targinfo;
  	const struct ipt_entry *e = e_void;
-@@ -421,7 +414,7 @@ checkentry(const char *tablename,
+@@ -421,7 +407,7 @@ checkentry(const char *tablename,
  
  	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
  		printk(KERN_WARNING "can't load conntrack support for "
@@ -868502,7 +927721,7 @@
  		return false;
  	}
  
-@@ -429,7 +422,7 @@ checkentry(const char *tablename,
+@@ -429,7 +415,7 @@ checkentry(const char *tablename,
  }
  
  /* drop reference count of cluster config when rule is deleted */
@@ -868511,7 +927730,7 @@
  {
  	struct ipt_clusterip_tgt_info *cipinfo = targinfo;
  
-@@ -456,12 +449,12 @@ struct compat_ipt_clusterip_tgt_info
+@@ -456,12 +442,12 @@ struct compat_ipt_clusterip_tgt_info
  };
  #endif /* CONFIG_COMPAT */
  
@@ -868528,7 +927747,7 @@
  	.targetsize	= sizeof(struct ipt_clusterip_tgt_info),
  #ifdef CONFIG_COMPAT
  	.compatsize	= sizeof(struct compat_ipt_clusterip_tgt_info),
-@@ -558,7 +551,7 @@ arp_mangle(unsigned int hook,
+@@ -558,7 +544,7 @@ arp_mangle(unsigned int hook,
  	return NF_ACCEPT;
  }
  
@@ -868537,7 +927756,7 @@
  	.hook = arp_mangle,
  	.pf = NF_ARP,
  	.hooknum = NF_ARP_OUT,
-@@ -714,11 +707,11 @@ static const struct file_operations clusterip_proc_fops = {
+@@ -714,11 +700,11 @@ static const struct file_operations clusterip_proc_fops = {
  
  #endif /* CONFIG_PROC_FS */
  
@@ -868551,7 +927770,7 @@
  	if (ret < 0)
  		return ret;
  
-@@ -744,11 +737,11 @@ cleanup_hook:
+@@ -744,11 +730,11 @@ cleanup_hook:
  	nf_unregister_hook(&cip_arp_ops);
  #endif /* CONFIG_PROC_FS */
  cleanup_target:
@@ -868565,7 +927784,7 @@
  {
  	printk(KERN_NOTICE "ClusterIP Version %s unloading\n",
  		CLUSTERIP_VERSION);
-@@ -756,8 +749,8 @@ static void __exit ipt_clusterip_fini(void)
+@@ -756,8 +742,8 @@ static void __exit ipt_clusterip_fini(void)
  	remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
  #endif
  	nf_unregister_hook(&cip_arp_ops);
@@ -870329,7 +929548,7 @@
 -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 11d39fb..e3154a9 100644
+index 11d39fb..68cbe3c 100644
 --- a/net/ipv4/netfilter/ipt_recent.c
 +++ b/net/ipv4/netfilter/ipt_recent.c
 @@ -30,7 +30,7 @@
@@ -870356,6 +929575,20 @@
  {
  	const struct ipt_recent_info *info = matchinfo;
  	struct recent_table *t;
+@@ -212,11 +212,11 @@ ipt_recent_match(const struct sk_buff *skb,
+ 		recent_entry_remove(t, e);
+ 		ret = !ret;
+ 	} else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) {
+-		unsigned long t = jiffies - info->seconds * HZ;
++		unsigned long time = jiffies - info->seconds * HZ;
+ 		unsigned int i, hits = 0;
+ 
+ 		for (i = 0; i < e->nstamps; i++) {
+-			if (info->seconds && time_after(t, e->stamps[i]))
++			if (info->seconds && time_after(time, e->stamps[i]))
+ 				continue;
+ 			if (++hits >= info->hit_count) {
+ 				ret = !ret;
 @@ -236,9 +236,9 @@ out:
  }
  
@@ -870379,7 +929612,23 @@
  {
  	const struct ipt_recent_info *info = matchinfo;
  	struct recent_table *t;
-@@ -455,17 +454,17 @@ static const struct file_operations recent_fops = {
+@@ -321,6 +320,7 @@ struct recent_iter_state {
+ };
+ 
+ static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(recent_lock)
+ {
+ 	struct recent_iter_state *st = seq->private;
+ 	const struct recent_table *t = st->table;
+@@ -353,6 +353,7 @@ static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ }
+ 
+ static void recent_seq_stop(struct seq_file *s, void *v)
++	__releases(recent_lock)
+ {
+ 	spin_unlock_bh(&recent_lock);
+ }
+@@ -455,17 +456,17 @@ static const struct file_operations recent_fops = {
  };
  #endif /* CONFIG_PROC_FS */
  
@@ -870402,7 +929651,7 @@
  {
  	int err;
  
-@@ -473,27 +472,27 @@ static int __init ipt_recent_init(void)
+@@ -473,27 +474,27 @@ static int __init ipt_recent_init(void)
  		return -EINVAL;
  	ip_list_hash_size = 1 << fls(ip_list_tot);
  
@@ -870553,10 +929802,10 @@
 +module_init(ttl_mt_init);
 +module_exit(ttl_mt_exit);
 diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
-index ba3262c..29bb4f9 100644
+index ba3262c..69f3d7e 100644
 --- a/net/ipv4/netfilter/iptable_filter.c
 +++ b/net/ipv4/netfilter/iptable_filter.c
-@@ -19,7 +19,9 @@ MODULE_LICENSE("GPL");
+@@ -19,28 +19,30 @@ MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Netfilter Core Team <coreteam at netfilter.org>");
  MODULE_DESCRIPTION("iptables filter table");
  
@@ -870567,7 +929816,14 @@
  
  static struct
  {
-@@ -33,14 +35,14 @@ static struct
+ 	struct ipt_replace repl;
+ 	struct ipt_standard entries[3];
+ 	struct ipt_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "filter",
+ 		.valid_hooks = FILTER_VALID_HOOKS,
  		.num_entries = 4,
  		.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
  		.hook_entry = {
@@ -870588,8 +929844,21 @@
  		},
  	},
  	.entries = {
-@@ -89,26 +91,26 @@ ipt_local_out_hook(unsigned int hook,
- 	return ipt_do_table(skb, hook, in, out, &packet_filter);
+@@ -67,7 +69,7 @@ ipt_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ipt_do_table(skb, hook, in, out, &packet_filter);
++	return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter);
+ }
+ 
+ static unsigned int
+@@ -86,29 +88,29 @@ ipt_local_out_hook(unsigned int hook,
+ 		return NF_ACCEPT;
+ 	}
+ 
+-	return ipt_do_table(skb, hook, in, out, &packet_filter);
++	return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter);
  }
  
 -static struct nf_hook_ops ipt_ops[] = {
@@ -870619,8 +929888,62 @@
  		.priority	= NF_IP_PRI_FILTER,
  	},
  };
+@@ -117,6 +119,26 @@ static struct nf_hook_ops ipt_ops[] = {
+ static int forward = NF_ACCEPT;
+ module_param(forward, bool, 0000);
+ 
++static int __net_init iptable_filter_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv4.iptable_filter =
++		ipt_register_table(net, &packet_filter, &initial_table.repl);
++	if (IS_ERR(net->ipv4.iptable_filter))
++		return PTR_ERR(net->ipv4.iptable_filter);
++	return 0;
++}
++
++static void __net_exit iptable_filter_net_exit(struct net *net)
++{
++	ipt_unregister_table(net->ipv4.iptable_filter);
++}
++
++static struct pernet_operations iptable_filter_net_ops = {
++	.init = iptable_filter_net_init,
++	.exit = iptable_filter_net_exit,
++};
++
+ static int __init iptable_filter_init(void)
+ {
+ 	int ret;
+@@ -129,8 +151,7 @@ static int __init iptable_filter_init(void)
+ 	/* Entry 1 is the FORWARD hook */
+ 	initial_table.entries[1].target.verdict = -forward - 1;
+ 
+-	/* Register table */
+-	ret = ipt_register_table(&packet_filter, &initial_table.repl);
++	ret = register_pernet_subsys(&iptable_filter_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -142,14 +163,14 @@ static int __init iptable_filter_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ipt_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&iptable_filter_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit iptable_filter_fini(void)
+ {
+ 	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+-	ipt_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&iptable_filter_net_ops);
+ }
+ 
+ module_init(iptable_filter_init);
 diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
-index b4360a6..5c4be20 100644
+index b4360a6..c55a210 100644
 --- a/net/ipv4/netfilter/iptable_mangle.c
 +++ b/net/ipv4/netfilter/iptable_mangle.c
 @@ -21,11 +21,11 @@ MODULE_LICENSE("GPL");
@@ -870640,7 +929963,15 @@
  
  /* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
  static struct
-@@ -40,18 +40,18 @@ static struct
+@@ -33,25 +33,25 @@ static struct
+ 	struct ipt_replace repl;
+ 	struct ipt_standard entries[5];
+ 	struct ipt_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "mangle",
+ 		.valid_hooks = MANGLE_VALID_HOOKS,
  		.num_entries = 6,
  		.size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
  		.hook_entry = {
@@ -870669,7 +930000,25 @@
  		},
  	},
  	.entries = {
-@@ -128,40 +128,40 @@ ipt_local_hook(unsigned int hook,
+@@ -80,7 +80,7 @@ ipt_route_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ipt_do_table(skb, hook, in, out, &packet_mangler);
++	return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle);
+ }
+ 
+ static unsigned int
+@@ -112,7 +112,7 @@ ipt_local_hook(unsigned int hook,
+ 	daddr = iph->daddr;
+ 	tos = iph->tos;
+ 
+-	ret = ipt_do_table(skb, hook, in, out, &packet_mangler);
++	ret = ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle);
+ 	/* Reroute for ANY change. */
+ 	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
+ 		iph = ip_hdr(skb);
+@@ -128,50 +128,69 @@ ipt_local_hook(unsigned int hook,
  	return ret;
  }
  
@@ -870716,11 +930065,59 @@
  		.priority	= NF_IP_PRI_MANGLE,
  	},
  };
+ 
++static int __net_init iptable_mangle_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv4.iptable_mangle =
++		ipt_register_table(net, &packet_mangler, &initial_table.repl);
++	if (IS_ERR(net->ipv4.iptable_mangle))
++		return PTR_ERR(net->ipv4.iptable_mangle);
++	return 0;
++}
++
++static void __net_exit iptable_mangle_net_exit(struct net *net)
++{
++	ipt_unregister_table(net->ipv4.iptable_mangle);
++}
++
++static struct pernet_operations iptable_mangle_net_ops = {
++	.init = iptable_mangle_net_init,
++	.exit = iptable_mangle_net_exit,
++};
++
+ static int __init iptable_mangle_init(void)
+ {
+ 	int ret;
+ 
+-	/* Register table */
+-	ret = ipt_register_table(&packet_mangler, &initial_table.repl);
++	ret = register_pernet_subsys(&iptable_mangle_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -183,14 +202,14 @@ static int __init iptable_mangle_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ipt_unregister_table(&packet_mangler);
++	unregister_pernet_subsys(&iptable_mangle_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit iptable_mangle_fini(void)
+ {
+ 	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+-	ipt_unregister_table(&packet_mangler);
++	unregister_pernet_subsys(&iptable_mangle_net_ops);
+ }
+ 
+ module_init(iptable_mangle_init);
 diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
-index f867865..dc34aa2 100644
+index f867865..e41fe8c 100644
 --- a/net/ipv4/netfilter/iptable_raw.c
 +++ b/net/ipv4/netfilter/iptable_raw.c
-@@ -7,7 +7,7 @@
+@@ -7,26 +7,26 @@
  #include <linux/netfilter_ipv4/ip_tables.h>
  #include <net/ip.h>
  
@@ -870729,7 +930126,14 @@
  
  static struct
  {
-@@ -21,12 +21,12 @@ static struct
+ 	struct ipt_replace repl;
+ 	struct ipt_standard entries[2];
+ 	struct ipt_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "raw",
+ 		.valid_hooks = RAW_VALID_HOOKS,
  		.num_entries = 3,
  		.size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
  		.hook_entry = {
@@ -870746,7 +930150,21 @@
  		},
  	},
  	.entries = {
-@@ -74,18 +74,18 @@ ipt_local_hook(unsigned int hook,
+@@ -52,7 +52,7 @@ ipt_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ipt_do_table(skb, hook, in, out, &packet_raw);
++	return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw);
+ }
+ 
+ static unsigned int
+@@ -70,33 +70,52 @@ ipt_local_hook(unsigned int hook,
+ 			       "packet.\n");
+ 		return NF_ACCEPT;
+ 	}
+-	return ipt_do_table(skb, hook, in, out, &packet_raw);
++	return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw);
  }
  
  /* 'raw' is the very first table. */
@@ -870768,11 +930186,70 @@
  		.priority = NF_IP_PRI_RAW,
  		.owner = THIS_MODULE,
  	},
+ };
+ 
++static int __net_init iptable_raw_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv4.iptable_raw =
++		ipt_register_table(net, &packet_raw, &initial_table.repl);
++	if (IS_ERR(net->ipv4.iptable_raw))
++		return PTR_ERR(net->ipv4.iptable_raw);
++	return 0;
++}
++
++static void __net_exit iptable_raw_net_exit(struct net *net)
++{
++	ipt_unregister_table(net->ipv4.iptable_raw);
++}
++
++static struct pernet_operations iptable_raw_net_ops = {
++	.init = iptable_raw_net_init,
++	.exit = iptable_raw_net_exit,
++};
++
+ static int __init iptable_raw_init(void)
+ {
+ 	int ret;
+ 
+-	/* Register table */
+-	ret = ipt_register_table(&packet_raw, &initial_table.repl);
++	ret = register_pernet_subsys(&iptable_raw_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -108,14 +127,14 @@ static int __init iptable_raw_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ipt_unregister_table(&packet_raw);
++	unregister_pernet_subsys(&iptable_raw_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit iptable_raw_fini(void)
+ {
+ 	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+-	ipt_unregister_table(&packet_raw);
++	unregister_pernet_subsys(&iptable_raw_net_ops);
+ }
+ 
+ module_init(iptable_raw_init);
 diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
-index 910dae7..ac3d61d 100644
+index 910dae7..a65b845 100644
 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
 +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
-@@ -56,12 +56,6 @@ static int ipv4_print_tuple(struct seq_file *s,
+@@ -27,7 +27,8 @@
+ static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+ 			     struct nf_conntrack_tuple *tuple)
+ {
+-	__be32 _addrs[2], *ap;
++	const __be32 *ap;
++	__be32 _addrs[2];
+ 	ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
+ 				sizeof(u_int32_t) * 2, _addrs);
+ 	if (ap == NULL)
+@@ -56,12 +57,6 @@ static int ipv4_print_tuple(struct seq_file *s,
  			  NIPQUAD(tuple->dst.u3.ip));
  }
  
@@ -870785,7 +930262,28 @@
  /* Returns new sk_buff, or NULL */
  static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
  {
-@@ -150,7 +144,7 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
+@@ -82,7 +77,8 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
+ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ 			    unsigned int *dataoff, u_int8_t *protonum)
+ {
+-	struct iphdr _iph, *iph;
++	const struct iphdr *iph;
++	struct iphdr _iph;
+ 
+ 	iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ 	if (iph == NULL)
+@@ -117,8 +113,8 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
+ {
+ 	struct nf_conn *ct;
+ 	enum ip_conntrack_info ctinfo;
+-	struct nf_conn_help *help;
+-	struct nf_conntrack_helper *helper;
++	const struct nf_conn_help *help;
++	const struct nf_conntrack_helper *helper;
+ 
+ 	/* This is where we call the helper: as the packet goes out. */
+ 	ct = nf_ct_get(skb, &ctinfo);
+@@ -150,7 +146,7 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
  	/* Gather fragments. */
  	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
  		if (nf_ct_ipv4_gather_frags(skb,
@@ -870794,7 +930292,7 @@
  					    IP_DEFRAG_CONNTRACK_IN :
  					    IP_DEFRAG_CONNTRACK_OUT))
  			return NF_STOLEN;
-@@ -185,61 +179,61 @@ static unsigned int ipv4_conntrack_local(unsigned int hooknum,
+@@ -185,61 +181,61 @@ static unsigned int ipv4_conntrack_local(unsigned int hooknum,
  
  /* Connection tracking may drop packets, but never alters them, so
     make it the first hook. */
@@ -870865,7 +930363,18 @@
  		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
  	},
  };
-@@ -363,10 +357,8 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
+@@ -305,8 +301,8 @@ static ctl_table ip_ct_sysctl_table[] = {
+ static int
+ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
+ {
+-	struct inet_sock *inet = inet_sk(sk);
+-	struct nf_conntrack_tuple_hash *h;
++	const struct inet_sock *inet = inet_sk(sk);
++	const struct nf_conntrack_tuple_hash *h;
+ 	struct nf_conntrack_tuple tuple;
+ 
+ 	NF_CT_TUPLE_U_BLANK(&tuple);
+@@ -363,10 +359,8 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
  static int ipv4_tuple_to_nlattr(struct sk_buff *skb,
  				const struct nf_conntrack_tuple *tuple)
  {
@@ -870878,7 +930387,7 @@
  	return 0;
  
  nla_put_failure:
-@@ -384,8 +376,8 @@ static int ipv4_nlattr_to_tuple(struct nlattr *tb[],
+@@ -384,8 +378,8 @@ static int ipv4_nlattr_to_tuple(struct nlattr *tb[],
  	if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST])
  		return -EINVAL;
  
@@ -870889,7 +930398,7 @@
  
  	return 0;
  }
-@@ -405,7 +397,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
+@@ -405,7 +399,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
  	.pkt_to_tuple	 = ipv4_pkt_to_tuple,
  	.invert_tuple	 = ipv4_invert_tuple,
  	.print_tuple	 = ipv4_print_tuple,
@@ -870898,10 +930407,73 @@
  #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  	.tuple_to_nlattr = ipv4_tuple_to_nlattr,
 diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
-index 741f3df..543c02b 100644
+index 741f3df..089252e 100644
 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
 +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
-@@ -121,10 +121,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
+@@ -39,12 +39,14 @@ struct ct_iter_state {
+ static struct hlist_node *ct_get_first(struct seq_file *seq)
+ {
+ 	struct ct_iter_state *st = seq->private;
++	struct hlist_node *n;
+ 
+ 	for (st->bucket = 0;
+ 	     st->bucket < nf_conntrack_htable_size;
+ 	     st->bucket++) {
+-		if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
+-			return nf_conntrack_hash[st->bucket].first;
++		n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
++		if (n)
++			return n;
+ 	}
+ 	return NULL;
+ }
+@@ -54,11 +56,11 @@ static struct hlist_node *ct_get_next(struct seq_file *seq,
+ {
+ 	struct ct_iter_state *st = seq->private;
+ 
+-	head = head->next;
++	head = rcu_dereference(head->next);
+ 	while (head == NULL) {
+ 		if (++st->bucket >= nf_conntrack_htable_size)
+ 			return NULL;
+-		head = nf_conntrack_hash[st->bucket].first;
++		head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+ 	}
+ 	return head;
+ }
+@@ -74,8 +76,9 @@ static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
+ }
+ 
+ static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(RCU)
+ {
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	return ct_get_idx(seq, *pos);
+ }
+ 
+@@ -86,16 +89,17 @@ static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
+ 
+ static void ct_seq_stop(struct seq_file *s, void *v)
++	__releases(RCU)
+ {
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ }
+ 
+ static int ct_seq_show(struct seq_file *s, void *v)
+ {
+ 	const struct nf_conntrack_tuple_hash *hash = v;
+ 	const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
+-	struct nf_conntrack_l3proto *l3proto;
+-	struct nf_conntrack_l4proto *l4proto;
++	const struct nf_conntrack_l3proto *l3proto;
++	const struct nf_conntrack_l4proto *l4proto;
+ 
+ 	NF_CT_ASSERT(ct);
+ 
+@@ -121,10 +125,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
  		      ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
  		return -ENOSPC;
  
@@ -870913,8 +930485,75 @@
  		return -ENOSPC;
  
  	if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+@@ -194,10 +195,12 @@ struct ct_expect_iter_state {
+ static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
+ {
+ 	struct ct_expect_iter_state *st = seq->private;
++	struct hlist_node *n;
+ 
+ 	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
+-		if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
+-			return nf_ct_expect_hash[st->bucket].first;
++		n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
++		if (n)
++			return n;
+ 	}
+ 	return NULL;
+ }
+@@ -207,11 +210,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
+ {
+ 	struct ct_expect_iter_state *st = seq->private;
+ 
+-	head = head->next;
++	head = rcu_dereference(head->next);
+ 	while (head == NULL) {
+ 		if (++st->bucket >= nf_ct_expect_hsize)
+ 			return NULL;
+-		head = nf_ct_expect_hash[st->bucket].first;
++		head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+ 	}
+ 	return head;
+ }
+@@ -227,8 +230,9 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
+ }
+ 
+ static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(RCU)
+ {
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	return ct_expect_get_idx(seq, *pos);
+ }
+ 
+@@ -239,14 +243,15 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ }
+ 
+ static void exp_seq_stop(struct seq_file *seq, void *v)
++	__releases(RCU)
+ {
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ }
+ 
+ static int exp_seq_show(struct seq_file *s, void *v)
+ {
+ 	struct nf_conntrack_expect *exp;
+-	struct hlist_node *n = v;
++	const struct hlist_node *n = v;
+ 
+ 	exp = hlist_entry(n, struct nf_conntrack_expect, hnode);
+ 
+@@ -327,7 +332,7 @@ static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
+ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
+ {
+ 	unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+-	struct ip_conntrack_stat *st = v;
++	const struct ip_conntrack_stat *st = v;
+ 
+ 	if (v == SEQ_START_TOKEN) {
+ 		seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
 diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
-index adcbaf6..4004a04 100644
+index adcbaf6..6873fdd 100644
 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
 +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
 @@ -18,6 +18,7 @@
@@ -870925,7 +930564,17 @@
  
  static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ;
  
-@@ -73,13 +74,6 @@ static int icmp_print_tuple(struct seq_file *s,
+@@ -25,7 +26,8 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
+ 			     unsigned int dataoff,
+ 			     struct nf_conntrack_tuple *tuple)
+ {
+-	struct icmphdr _hdr, *hp;
++	const struct icmphdr *hp;
++	struct icmphdr _hdr;
+ 
+ 	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ 	if (hp == NULL)
+@@ -73,13 +75,6 @@ static int icmp_print_tuple(struct seq_file *s,
  			  ntohs(tuple->src.u.icmp.id));
  }
  
@@ -870939,7 +930588,33 @@
  /* Returns verdict for packet, or -1 for invalid. */
  static int icmp_packet(struct nf_conn *ct,
  		       const struct sk_buff *skb,
-@@ -128,7 +122,6 @@ static int icmp_new(struct nf_conn *conntrack,
+@@ -106,7 +101,7 @@ static int icmp_packet(struct nf_conn *ct,
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int icmp_new(struct nf_conn *conntrack,
++static int icmp_new(struct nf_conn *ct,
+ 		    const struct sk_buff *skb, unsigned int dataoff)
+ {
+ 	static const u_int8_t valid_new[] = {
+@@ -116,19 +111,18 @@ static int icmp_new(struct nf_conn *conntrack,
+ 		[ICMP_ADDRESS] = 1
+ 	};
+ 
+-	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
+-	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
++	if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
++	    || !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) {
+ 		/* Can't create a new ICMP `conn' with this. */
+ 		pr_debug("icmp: can't create new conn with type %u\n",
+-			 conntrack->tuplehash[0].tuple.dst.u.icmp.type);
+-		NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
++			 ct->tuplehash[0].tuple.dst.u.icmp.type);
++		NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple);
+ 		return 0;
+ 	}
+-	atomic_set(&conntrack->proto.icmp.count, 0);
++	atomic_set(&ct->proto.icmp.count, 0);
  	return 1;
  }
  
@@ -870947,7 +930622,28 @@
  /* Returns conntrack if it dealt with ICMP, and filled in skb fields */
  static int
  icmp_error_message(struct sk_buff *skb,
-@@ -195,7 +188,7 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
+@@ -136,8 +130,8 @@ icmp_error_message(struct sk_buff *skb,
+ 		 unsigned int hooknum)
+ {
+ 	struct nf_conntrack_tuple innertuple, origtuple;
+-	struct nf_conntrack_l4proto *innerproto;
+-	struct nf_conntrack_tuple_hash *h;
++	const struct nf_conntrack_l4proto *innerproto;
++	const struct nf_conntrack_tuple_hash *h;
+ 
+ 	NF_CT_ASSERT(skb->nfct == NULL);
+ 
+@@ -183,7 +177,8 @@ static int
+ icmp_error(struct sk_buff *skb, unsigned int dataoff,
+ 	   enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+ {
+-	struct icmphdr _ih, *icmph;
++	const struct icmphdr *icmph;
++	struct icmphdr _ih;
+ 
+ 	/* Not enough header? */
+ 	icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
+@@ -195,7 +190,7 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
  	}
  
  	/* See ip_conntrack_proto_tcp.c */
@@ -870956,7 +930652,7 @@
  	    nf_ip_checksum(skb, hooknum, dataoff, 0)) {
  		if (LOG_INVALID(IPPROTO_ICMP))
  			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-@@ -235,12 +228,9 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
+@@ -235,12 +230,9 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
  static int icmp_tuple_to_nlattr(struct sk_buff *skb,
  				const struct nf_conntrack_tuple *t)
  {
@@ -870972,7 +930668,7 @@
  
  	return 0;
  
-@@ -262,12 +252,9 @@ static int icmp_nlattr_to_tuple(struct nlattr *tb[],
+@@ -262,12 +254,9 @@ static int icmp_nlattr_to_tuple(struct nlattr *tb[],
  	    || !tb[CTA_PROTO_ICMP_ID])
  		return -EINVAL;
  
@@ -870988,7 +930684,7 @@
  
  	if (tuple->dst.u.icmp.type >= sizeof(invmap)
  	    || !invmap[tuple->dst.u.icmp.type])
-@@ -315,7 +302,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
+@@ -315,7 +304,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
  	.pkt_to_tuple		= icmp_pkt_to_tuple,
  	.invert_tuple		= icmp_invert_tuple,
  	.print_tuple		= icmp_print_tuple,
@@ -870997,12 +930693,15 @@
  	.new			= icmp_new,
  	.error			= icmp_error,
 diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
-index 86b465b..e53ae1e 100644
+index 86b465b..dd07362 100644
 --- a/net/ipv4/netfilter/nf_nat_core.c
 +++ b/net/ipv4/netfilter/nf_nat_core.c
-@@ -33,27 +33,28 @@
+@@ -31,29 +31,30 @@
+ #include <net/netfilter/nf_conntrack_l3proto.h>
+ #include <net/netfilter/nf_conntrack_l4proto.h>
  
- static DEFINE_RWLOCK(nf_nat_lock);
+-static DEFINE_RWLOCK(nf_nat_lock);
++static DEFINE_SPINLOCK(nf_nat_lock);
  
 -static struct nf_conntrack_l3proto *l3proto = NULL;
 +static struct nf_conntrack_l3proto *l3proto __read_mostly;
@@ -871070,6 +930769,32 @@
  	int ret = 0;
  
  	/* If we are supposed to map IPs, then we must be in the
+@@ -150,8 +154,8 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
+ 	struct nf_conn *ct;
+ 	struct hlist_node *n;
+ 
+-	read_lock_bh(&nf_nat_lock);
+-	hlist_for_each_entry(nat, n, &bysource[h], bysource) {
++	rcu_read_lock();
++	hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) {
+ 		ct = nat->ct;
+ 		if (same_src(ct, tuple)) {
+ 			/* Copy source part from reply tuple. */
+@@ -160,12 +164,12 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
+ 			result->dst = tuple->dst;
+ 
+ 			if (in_range(result, range)) {
+-				read_unlock_bh(&nf_nat_lock);
++				rcu_read_unlock();
+ 				return 1;
+ 			}
+ 		}
+ 	}
+-	read_unlock_bh(&nf_nat_lock);
++	rcu_read_unlock();
+ 	return 0;
+ }
+ 
 @@ -210,12 +214,13 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
  	maxip = ntohl(range->max_ip);
  	j = jhash_2words((__force u32)tuple->src.u3.ip,
@@ -871124,6 +930849,22 @@
  	BUG_ON(nf_nat_initialized(ct, maniptype));
  
  	/* What we've got will look like inverse of reply. Normally
+@@ -328,12 +330,12 @@ nf_nat_setup_info(struct nf_conn *ct,
+ 		unsigned int srchash;
+ 
+ 		srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+-		write_lock_bh(&nf_nat_lock);
++		spin_lock_bh(&nf_nat_lock);
+ 		/* nf_conntrack_alter_reply might re-allocate exntension aera */
+ 		nat = nfct_nat(ct);
+ 		nat->ct = ct;
+-		hlist_add_head(&nat->bysource, &bysource[srchash]);
+-		write_unlock_bh(&nf_nat_lock);
++		hlist_add_head_rcu(&nat->bysource, &bysource[srchash]);
++		spin_unlock_bh(&nf_nat_lock);
+ 	}
+ 
+ 	/* It's done. */
 @@ -355,7 +357,7 @@ manip_pkt(u_int16_t proto,
  	  enum nf_nat_manip_type maniptype)
  {
@@ -871146,7 +930887,7 @@
  		iph->daddr = target->dst.u3.ip;
  	}
  	return 1;
-@@ -515,7 +517,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
+@@ -515,29 +517,29 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
  EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
  
  /* Protocol registration. */
@@ -871155,15 +930896,33 @@
  {
  	int ret = 0;
  
-@@ -532,7 +534,7 @@ int nf_nat_protocol_register(struct nf_nat_protocol *proto)
+-	write_lock_bh(&nf_nat_lock);
++	spin_lock_bh(&nf_nat_lock);
+ 	if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {
+ 		ret = -EBUSY;
+ 		goto out;
+ 	}
+ 	rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
+  out:
+-	write_unlock_bh(&nf_nat_lock);
++	spin_unlock_bh(&nf_nat_lock);
+ 	return ret;
+ }
  EXPORT_SYMBOL(nf_nat_protocol_register);
  
  /* Noone stores the protocol anywhere; simply delete it. */
 -void nf_nat_protocol_unregister(struct nf_nat_protocol *proto)
 +void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
  {
- 	write_lock_bh(&nf_nat_lock);
+-	write_lock_bh(&nf_nat_lock);
++	spin_lock_bh(&nf_nat_lock);
  	rcu_assign_pointer(nf_nat_protos[proto->protonum],
+ 			   &nf_nat_unknown_protocol);
+-	write_unlock_bh(&nf_nat_lock);
++	spin_unlock_bh(&nf_nat_lock);
+ 	synchronize_rcu();
+ }
+ EXPORT_SYMBOL(nf_nat_protocol_unregister);
 @@ -547,10 +549,8 @@ int
  nf_nat_port_range_to_nlattr(struct sk_buff *skb,
  			    const struct nf_nat_range *range)
@@ -871197,11 +930956,68 @@
  	}
  
  	return ret;
+@@ -596,10 +594,10 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
+ 
+ 	NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);
+ 
+-	write_lock_bh(&nf_nat_lock);
+-	hlist_del(&nat->bysource);
++	spin_lock_bh(&nf_nat_lock);
++	hlist_del_rcu(&nat->bysource);
+ 	nat->ct = NULL;
+-	write_unlock_bh(&nf_nat_lock);
++	spin_unlock_bh(&nf_nat_lock);
+ }
+ 
+ static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
+@@ -611,10 +609,10 @@ static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
+ 	if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
+ 		return;
+ 
+-	write_lock_bh(&nf_nat_lock);
++	spin_lock_bh(&nf_nat_lock);
+ 	hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
+ 	new_nat->ct = ct;
+-	write_unlock_bh(&nf_nat_lock);
++	spin_unlock_bh(&nf_nat_lock);
+ }
+ 
+ static struct nf_ct_ext_type nat_extend __read_mostly = {
+@@ -648,17 +646,13 @@ static int __init nf_nat_init(void)
+ 	}
+ 
+ 	/* Sew in builtin protocols. */
+-	write_lock_bh(&nf_nat_lock);
++	spin_lock_bh(&nf_nat_lock);
+ 	for (i = 0; i < MAX_IP_NAT_PROTO; i++)
+ 		rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
+ 	rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
+ 	rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
+ 	rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
+-	write_unlock_bh(&nf_nat_lock);
+-
+-	for (i = 0; i < nf_nat_htable_size; i++) {
+-		INIT_HLIST_HEAD(&bysource[i]);
+-	}
++	spin_unlock_bh(&nf_nat_lock);
+ 
+ 	/* Initialize fake conntrack so that NAT will skip it */
+ 	nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
 diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
-index 93e18ef..a121989 100644
+index 93e18ef..ee47bf2 100644
 --- a/net/ipv4/netfilter/nf_nat_h323.c
 +++ b/net/ipv4/netfilter/nf_nat_h323.c
-@@ -76,7 +76,7 @@ static int set_addr(struct sk_buff *skb,
+@@ -32,7 +32,8 @@ static int set_addr(struct sk_buff *skb,
+ 		__be32 ip;
+ 		__be16 port;
+ 	} __attribute__ ((__packed__)) buf;
+-	struct tcphdr _tcph, *th;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
+ 
+ 	buf.ip = ip;
+ 	buf.port = port;
+@@ -76,7 +77,7 @@ static int set_addr(struct sk_buff *skb,
  static int set_h225_addr(struct sk_buff *skb,
  			 unsigned char **data, int dataoff,
  			 TransportAddress *taddr,
@@ -871210,7 +931026,7 @@
  {
  	return set_addr(skb, data, dataoff, taddr->ipAddress.ip,
  			addr->ip, port);
-@@ -86,7 +86,7 @@ static int set_h225_addr(struct sk_buff *skb,
+@@ -86,7 +87,7 @@ static int set_h225_addr(struct sk_buff *skb,
  static int set_h245_addr(struct sk_buff *skb,
  			 unsigned char **data, int dataoff,
  			 H245_TransportAddress *taddr,
@@ -871219,7 +931035,12 @@
  {
  	return set_addr(skb, data, dataoff,
  			taddr->unicastAddress.iPAddress.network,
-@@ -103,7 +103,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
+@@ -99,11 +100,11 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
+ 			unsigned char **data,
+ 			TransportAddress *taddr, int count)
+ {
+-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
++	const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
  	int dir = CTINFO2DIR(ctinfo);
  	int i;
  	__be16 port;
@@ -871228,7 +931049,7 @@
  
  	for (i = 0; i < count; i++) {
  		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
-@@ -155,7 +155,7 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
+@@ -155,7 +156,7 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
  	int dir = CTINFO2DIR(ctinfo);
  	int i;
  	__be16 port;
@@ -871237,7 +931058,7 @@
  
  	for (i = 0; i < count; i++) {
  		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
-@@ -389,18 +389,14 @@ static void ip_nat_q931_expect(struct nf_conn *new,
+@@ -389,18 +390,14 @@ static void ip_nat_q931_expect(struct nf_conn *new,
  	/* Change src to where master sends to */
  	range.flags = IP_NAT_RANGE_MAP_IPS;
  	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
@@ -871258,7 +931079,7 @@
  }
  
  /****************************************************************************/
-@@ -412,7 +408,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
+@@ -412,7 +409,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
  	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
  	int dir = CTINFO2DIR(ctinfo);
  	u_int16_t nated_port = ntohs(port);
@@ -871267,7 +931088,7 @@
  
  	/* Set expectations for NAT */
  	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-@@ -479,17 +475,13 @@ static void ip_nat_callforwarding_expect(struct nf_conn *new,
+@@ -479,17 +476,13 @@ static void ip_nat_callforwarding_expect(struct nf_conn *new,
  	/* Change src to where master sends to */
  	range.flags = IP_NAT_RANGE_MAP_IPS;
  	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
@@ -871288,7 +931109,7 @@
  
  /****************************************************************************/
 diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
-index 8718da0..4c02328 100644
+index 8718da0..ca57f47 100644
 --- a/net/ipv4/netfilter/nf_nat_helper.c
 +++ b/net/ipv4/netfilter/nf_nat_helper.c
 @@ -20,6 +20,7 @@
@@ -871299,7 +931120,17 @@
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <net/netfilter/nf_nat.h>
  #include <net/netfilter/nf_nat_protocol.h>
-@@ -180,8 +181,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
+@@ -43,8 +44,7 @@ adjust_tcp_sequence(u32 seq,
+ 	struct nf_nat_seq *this_way, *other_way;
+ 	struct nf_conn_nat *nat = nfct_nat(ct);
+ 
+-	pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
+-		 ntohl(seq), seq);
++	pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", seq, seq);
+ 
+ 	dir = CTINFO2DIR(ctinfo);
+ 
+@@ -180,8 +180,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
  								datalen, 0));
  		}
  	} else
@@ -871310,7 +931141,7 @@
  
  	if (rep_len != match_len) {
  		set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
-@@ -191,6 +192,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
+@@ -191,6 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
  		/* Tell TCP window tracking about seq change */
  		nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
  					ct, CTINFO2DIR(ctinfo));
@@ -871319,7 +931150,7 @@
  	}
  	return 1;
  }
-@@ -270,8 +273,8 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
+@@ -270,8 +272,8 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
  				udph->check = CSUM_MANGLED_0;
  		}
  	} else
@@ -871330,7 +931161,7 @@
  
  	return 1;
  }
-@@ -310,10 +313,10 @@ sack_adjust(struct sk_buff *skb,
+@@ -310,10 +312,10 @@ sack_adjust(struct sk_buff *skb,
  			 ntohl(sack->start_seq), new_start_seq,
  			 ntohl(sack->end_seq), new_end_seq);
  
@@ -871345,7 +931176,7 @@
  		sack->start_seq = new_start_seq;
  		sack->end_seq = new_end_seq;
  		sackoff += sizeof(*sack);
-@@ -397,8 +400,8 @@ nf_nat_seq_adjust(struct sk_buff *skb,
+@@ -397,8 +399,8 @@ nf_nat_seq_adjust(struct sk_buff *skb,
  	else
  		newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
  
@@ -871356,7 +931187,7 @@
  
  	pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
  		 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
-@@ -430,15 +433,13 @@ void nf_nat_follow_master(struct nf_conn *ct,
+@@ -430,15 +432,13 @@ void nf_nat_follow_master(struct nf_conn *ct,
  	range.flags = IP_NAT_RANGE_MAP_IPS;
  	range.min_ip = range.max_ip
  		= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
@@ -871375,9 +931206,24 @@
  }
  EXPORT_SYMBOL(nf_nat_follow_master);
 diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
-index 6817e79..e63b944 100644
+index 6817e79..3a1e6d6 100644
 --- a/net/ipv4/netfilter/nf_nat_pptp.c
 +++ b/net/ipv4/netfilter/nf_nat_pptp.c
+@@ -40,11 +40,11 @@ MODULE_ALIAS("ip_nat_pptp");
+ static void pptp_nat_expected(struct nf_conn *ct,
+ 			      struct nf_conntrack_expect *exp)
+ {
+-	struct nf_conn *master = ct->master;
++	const struct nf_conn *master = ct->master;
+ 	struct nf_conntrack_expect *other_exp;
+ 	struct nf_conntrack_tuple t;
+-	struct nf_ct_pptp_master *ct_pptp_info;
+-	struct nf_nat_pptp *nat_pptp_info;
++	const struct nf_ct_pptp_master *ct_pptp_info;
++	const struct nf_nat_pptp *nat_pptp_info;
+ 	struct nf_nat_range range;
+ 
+ 	ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
 @@ -93,8 +93,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
  		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
  		range.min = range.max = exp->saved_proto;
@@ -871398,10 +931244,78 @@
  }
  
  /* outbound packets == from PNS to PAC */
+@@ -188,7 +186,7 @@ static void
+ pptp_exp_gre(struct nf_conntrack_expect *expect_orig,
+ 	     struct nf_conntrack_expect *expect_reply)
+ {
+-	struct nf_conn *ct = expect_orig->master;
++	const struct nf_conn *ct = expect_orig->master;
+ 	struct nf_ct_pptp_master *ct_pptp_info;
+ 	struct nf_nat_pptp *nat_pptp_info;
+ 
+@@ -219,7 +217,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
+ 		 struct PptpControlHeader *ctlh,
+ 		 union pptp_ctrl_union *pptpReq)
+ {
+-	struct nf_nat_pptp *nat_pptp_info;
++	const struct nf_nat_pptp *nat_pptp_info;
+ 	u_int16_t msg;
+ 	__be16 new_pcid;
+ 	unsigned int pcid_off;
 diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
-index b820f99..9fa272e 100644
+index b820f99..a1e4da1 100644
 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c
 +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
+@@ -59,7 +59,7 @@ static int
+ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
+ 		 const struct nf_nat_range *range,
+ 		 enum nf_nat_manip_type maniptype,
+-		 const struct nf_conn *conntrack)
++		 const struct nf_conn *ct)
+ {
+ 	static u_int16_t key;
+ 	__be16 *keyptr;
+@@ -67,7 +67,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
+ 
+ 	/* If there is no master conntrack we are not PPTP,
+ 	   do not change tuples */
+-	if (!conntrack->master)
++	if (!ct->master)
+ 		return 0;
+ 
+ 	if (maniptype == IP_NAT_MANIP_SRC)
+@@ -76,7 +76,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
+ 		keyptr = &tuple->dst.u.gre.key;
+ 
+ 	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
+-		pr_debug("%p: NATing GRE PPTP\n", conntrack);
++		pr_debug("%p: NATing GRE PPTP\n", ct);
+ 		min = 1;
+ 		range_size = 0xffff;
+ 	} else {
+@@ -88,11 +88,11 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
+ 
+ 	for (i = 0; i < range_size; i++, key++) {
+ 		*keyptr = htons(min + key % range_size);
+-		if (!nf_nat_used_tuple(tuple, conntrack))
++		if (!nf_nat_used_tuple(tuple, ct))
+ 			return 1;
+ 	}
+ 
+-	pr_debug("%p: no NAT mapping\n", conntrack);
++	pr_debug("%p: no NAT mapping\n", ct);
+ 	return 0;
+ }
+ 
+@@ -104,7 +104,7 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
+ {
+ 	struct gre_hdr *greh;
+ 	struct gre_hdr_pptp *pgreh;
+-	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
++	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+ 	unsigned int hdroff = iphdroff + iph->ihl * 4;
+ 
+ 	/* pgreh includes two optional 32bit fields which are not required
 @@ -135,9 +135,10 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
  	return 1;
  }
@@ -871414,10 +931328,34 @@
  	.manip_pkt		= gre_manip_pkt,
  	.in_range		= gre_in_range,
  	.unique_tuple		= gre_unique_tuple,
+@@ -147,12 +148,12 @@ static struct nf_nat_protocol gre __read_mostly = {
+ #endif
+ };
+ 
+-int __init nf_nat_proto_gre_init(void)
++static int __init nf_nat_proto_gre_init(void)
+ {
+ 	return nf_nat_protocol_register(&gre);
+ }
+ 
+-void __exit nf_nat_proto_gre_fini(void)
++static void __exit nf_nat_proto_gre_fini(void)
+ {
+ 	nf_nat_protocol_unregister(&gre);
+ }
 diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
-index b9fc724..a0e44c9 100644
+index b9fc724..03a0296 100644
 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
 +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
+@@ -57,7 +57,7 @@ icmp_manip_pkt(struct sk_buff *skb,
+ 	       const struct nf_conntrack_tuple *tuple,
+ 	       enum nf_nat_manip_type maniptype)
+ {
+-	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
++	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+ 	struct icmphdr *hdr;
+ 	unsigned int hdroff = iphdroff + iph->ihl*4;
+ 
 @@ -65,13 +65,13 @@ icmp_manip_pkt(struct sk_buff *skb,
  		return 0;
  
@@ -871436,9 +931374,18 @@
  	.protonum		= IPPROTO_ICMP,
  	.me			= THIS_MODULE,
 diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
-index 6bab2e1..da23e9f 100644
+index 6bab2e1..ffd5d15 100644
 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
 +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
+@@ -93,7 +93,7 @@ tcp_manip_pkt(struct sk_buff *skb,
+ 	      const struct nf_conntrack_tuple *tuple,
+ 	      enum nf_nat_manip_type maniptype)
+ {
+-	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
++	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+ 	struct tcphdr *hdr;
+ 	unsigned int hdroff = iphdroff + iph->ihl*4;
+ 	__be32 oldip, newip;
 @@ -132,12 +132,12 @@ tcp_manip_pkt(struct sk_buff *skb,
  	if (hdrsize < sizeof(*hdr))
  		return 1;
@@ -871456,9 +931403,18 @@
  	.protonum		= IPPROTO_TCP,
  	.me			= THIS_MODULE,
 diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
-index cbf1a61..10df4db 100644
+index cbf1a61..4b8f499 100644
 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c
 +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
+@@ -91,7 +91,7 @@ udp_manip_pkt(struct sk_buff *skb,
+ 	      const struct nf_conntrack_tuple *tuple,
+ 	      enum nf_nat_manip_type maniptype)
+ {
+-	struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
++	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+ 	struct udphdr *hdr;
+ 	unsigned int hdroff = iphdroff + iph->ihl*4;
+ 	__be32 oldip, newip;
 @@ -117,9 +117,9 @@ udp_manip_pkt(struct sk_buff *skb,
  		portptr = &hdr->dest;
  	}
@@ -871495,7 +931451,7 @@
  	/* .me isn't set: getting a ref to this cannot fail. */
  	.manip_pkt		= unknown_manip_pkt,
 diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
-index 46b25ab..5191822 100644
+index 46b25ab..f8fda57 100644
 --- a/net/ipv4/netfilter/nf_nat_rule.c
 +++ b/net/ipv4/netfilter/nf_nat_rule.c
 @@ -24,7 +24,9 @@
@@ -871530,7 +931486,23 @@
  		},
  	},
  	.entries = {
-@@ -76,7 +78,7 @@ static unsigned int ipt_snat_target(struct sk_buff *skb,
+@@ -56,13 +58,14 @@ static struct
+ 	.term = IPT_ERROR_INIT,			/* ERROR */
+ };
+ 
+-static struct xt_table nat_table = {
++static struct xt_table __nat_table = {
+ 	.name		= "nat",
+ 	.valid_hooks	= NAT_VALID_HOOKS,
+ 	.lock		= RW_LOCK_UNLOCKED,
+ 	.me		= THIS_MODULE,
+ 	.af		= AF_INET,
+ };
++static struct xt_table *nat_table;
+ 
+ /* Source NAT */
+ static unsigned int ipt_snat_target(struct sk_buff *skb,
+@@ -76,7 +79,7 @@ static unsigned int ipt_snat_target(struct sk_buff *skb,
  	enum ip_conntrack_info ctinfo;
  	const struct nf_nat_multi_range_compat *mr = targinfo;
  
@@ -871539,7 +931511,7 @@
  
  	ct = nf_ct_get(skb, &ctinfo);
  
-@@ -85,7 +87,7 @@ static unsigned int ipt_snat_target(struct sk_buff *skb,
+@@ -85,7 +88,7 @@ static unsigned int ipt_snat_target(struct sk_buff *skb,
  			    ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
  	NF_CT_ASSERT(out);
  
@@ -871548,7 +931520,7 @@
  }
  
  /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-@@ -95,7 +97,7 @@ static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
+@@ -95,7 +98,7 @@ static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
  	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
  	struct rtable *rt;
  
@@ -871557,7 +931529,7 @@
  		return;
  
  	if (rt->rt_src != srcip && !warned) {
-@@ -118,20 +120,20 @@ static unsigned int ipt_dnat_target(struct sk_buff *skb,
+@@ -118,20 +121,20 @@ static unsigned int ipt_dnat_target(struct sk_buff *skb,
  	enum ip_conntrack_info ctinfo;
  	const struct nf_nat_multi_range_compat *mr = targinfo;
  
@@ -871582,7 +931554,7 @@
  }
  
  static bool ipt_snat_checkentry(const char *tablename,
-@@ -182,7 +184,7 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+@@ -182,7 +185,7 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
  
  	pr_debug("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
  		 ct, NIPQUAD(ip));
@@ -871591,7 +931563,7 @@
  }
  
  unsigned int
-@@ -201,7 +203,7 @@ alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
+@@ -201,7 +204,7 @@ alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
  
  	pr_debug("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
  		 ct, NIPQUAD(ip));
@@ -871600,7 +931572,16 @@
  }
  
  int nf_nat_rule_find(struct sk_buff *skb,
-@@ -227,7 +229,7 @@ static struct xt_target ipt_snat_reg __read_mostly = {
+@@ -212,7 +215,7 @@ int nf_nat_rule_find(struct sk_buff *skb,
+ {
+ 	int ret;
+ 
+-	ret = ipt_do_table(skb, hooknum, in, out, &nat_table);
++	ret = ipt_do_table(skb, hooknum, in, out, nat_table);
+ 
+ 	if (ret == NF_ACCEPT) {
+ 		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
+@@ -227,7 +230,7 @@ static struct xt_target ipt_snat_reg __read_mostly = {
  	.target		= ipt_snat_target,
  	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
  	.table		= "nat",
@@ -871609,7 +931590,7 @@
  	.checkentry	= ipt_snat_checkentry,
  	.family		= AF_INET,
  };
-@@ -237,7 +239,7 @@ static struct xt_target ipt_dnat_reg __read_mostly = {
+@@ -237,7 +240,7 @@ static struct xt_target ipt_dnat_reg __read_mostly = {
  	.target		= ipt_dnat_target,
  	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
  	.table		= "nat",
@@ -871618,10 +931599,52 @@
  	.checkentry	= ipt_dnat_checkentry,
  	.family		= AF_INET,
  };
+@@ -246,9 +249,10 @@ int __init nf_nat_rule_init(void)
+ {
+ 	int ret;
+ 
+-	ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
+-	if (ret != 0)
+-		return ret;
++	nat_table = ipt_register_table(&init_net, &__nat_table,
++				       &nat_initial_table.repl);
++	if (IS_ERR(nat_table))
++		return PTR_ERR(nat_table);
+ 	ret = xt_register_target(&ipt_snat_reg);
+ 	if (ret != 0)
+ 		goto unregister_table;
+@@ -262,7 +266,7 @@ int __init nf_nat_rule_init(void)
+  unregister_snat:
+ 	xt_unregister_target(&ipt_snat_reg);
+  unregister_table:
+-	ipt_unregister_table(&nat_table);
++	ipt_unregister_table(nat_table);
+ 
+ 	return ret;
+ }
+@@ -271,5 +275,5 @@ void nf_nat_rule_cleanup(void)
+ {
+ 	xt_unregister_target(&ipt_dnat_reg);
+ 	xt_unregister_target(&ipt_snat_reg);
+-	ipt_unregister_table(&nat_table);
++	ipt_unregister_table(nat_table);
+ }
 diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
-index 8996ccb..606a170 100644
+index 8996ccb..b4c8d49 100644
 --- a/net/ipv4/netfilter/nf_nat_sip.c
 +++ b/net/ipv4/netfilter/nf_nat_sip.c
+@@ -35,9 +35,9 @@ struct addr_map {
+ 	} addr[IP_CT_DIR_MAX];
+ };
+ 
+-static void addr_map_init(struct nf_conn *ct, struct addr_map *map)
++static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
+ {
+-	struct nf_conntrack_tuple *t;
++	const struct nf_conntrack_tuple *t;
+ 	enum ip_conntrack_dir dir;
+ 	unsigned int n;
+ 
 @@ -228,15 +228,13 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
  	range.flags = IP_NAT_RANGE_MAP_IPS;
  	range.min_ip = range.max_ip
@@ -871641,7 +931664,7 @@
  
  /* So, this packet has hit the connection tracking matching code.
 diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
-index 03709d6..07f2a49 100644
+index 03709d6..540ce6a 100644
 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
 +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
 @@ -60,7 +60,7 @@ MODULE_ALIAS("ip_nat_snmp_basic");
@@ -871653,6 +931676,15 @@
  
  static int debug;
  static DEFINE_SPINLOCK(snmp_lock);
+@@ -260,7 +260,7 @@ static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
+ {
+ 	unsigned char ch;
+ 
+-	if (eoc == 0) {
++	if (eoc == NULL) {
+ 		if (!asn1_octet_decode(ctx, &ch))
+ 			return 0;
+ 
 diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
 index 7db76ea..99b2c78 100644
 --- a/net/ipv4/netfilter/nf_nat_standalone.c
@@ -871754,6 +931786,19 @@
  	synchronize_net();
  #endif
  	/* Conntrack caches are unregistered in nf_conntrack_cleanup */
+diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
+index 1360a94..b096e81 100644
+--- a/net/ipv4/netfilter/nf_nat_tftp.c
++++ b/net/ipv4/netfilter/nf_nat_tftp.c
+@@ -24,7 +24,7 @@ static unsigned int help(struct sk_buff *skb,
+ 			 enum ip_conntrack_info ctinfo,
+ 			 struct nf_conntrack_expect *exp)
+ {
+-	struct nf_conn *ct = exp->master;
++	const struct nf_conn *ct = exp->master;
+ 
+ 	exp->saved_proto.udp.port
+ 		= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
 diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
 index ce34b28..d63474c 100644
 --- a/net/ipv4/proc.c
@@ -871791,7 +931836,7 @@
  	for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
  		seq_printf(seq, " %lu",
 diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
-index e7050f8..85c0869 100644
+index e7050f8..a3002fe 100644
 --- a/net/ipv4/raw.c
 +++ b/net/ipv4/raw.c
 @@ -80,38 +80,51 @@
@@ -871973,7 +932018,15 @@
  		kfree_skb(skb);
  		return NET_RX_DROP;
  	}
-@@ -320,7 +381,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
+@@ -291,6 +352,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
+ 	skb_reserve(skb, hh_len);
+ 
+ 	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
+ 	skb->dst = dst_clone(&rt->u.dst);
+ 
+ 	skb_reset_network_header(skb);
+@@ -320,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
  		icmp_out_count(((struct icmphdr *)
  			skb_transport_header(skb))->type);
  
@@ -871982,7 +932035,7 @@
  		      dst_output);
  	if (err > 0)
  		err = inet->recverr ? net_xmit_errno(err) : 0;
-@@ -474,7 +535,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -474,7 +536,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  	if (msg->msg_flags & MSG_DONTROUTE)
  		tos |= RTO_ONLINK;
  
@@ -871991,7 +932044,15 @@
  		if (!ipc.oif)
  			ipc.oif = inet->mc_index;
  		if (!saddr)
-@@ -497,7 +558,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -483,6 +545,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ 
+ 	{
+ 		struct flowi fl = { .oif = ipc.oif,
++				    .mark = sk->sk_mark,
+ 				    .nl_u = { .ip4_u =
+ 					      { .daddr = daddr,
+ 						.saddr = saddr,
+@@ -497,7 +560,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  		}
  
  		security_sk_classify_flow(sk, &fl);
@@ -872000,7 +932061,7 @@
  	}
  	if (err)
  		goto done;
-@@ -564,7 +625,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+@@ -564,7 +627,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  
  	if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
  		goto out;
@@ -872009,7 +932070,7 @@
  	ret = -EADDRNOTAVAIL;
  	if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
  	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
-@@ -789,22 +850,18 @@ struct proto raw_prot = {
+@@ -789,22 +852,17 @@ struct proto raw_prot = {
  };
  
  #ifdef CONFIG_PROC_FS
@@ -872032,18 +932093,16 @@
 -		sk_for_each(sk, node, &raw_v4_htable[state->bucket])
 -			if (sk->sk_family == PF_INET)
 +		sk_for_each(sk, node, &state->h->ht[state->bucket])
-+			if (sk->sk_net == state->p.net &&
-+					sk->sk_family == state->family)
++			if (sk->sk_net == state->p.net)
  				goto found;
  	}
  	sk = NULL;
-@@ -820,10 +877,11 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
+@@ -820,10 +878,10 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
  		sk = sk_next(sk);
  try_again:
  		;
 -	} while (sk && sk->sk_family != PF_INET);
-+	} while (sk && sk->sk_net != state->p.net &&
-+			sk->sk_family != state->family);
++	} while (sk && sk->sk_net != state->p.net);
  
 -	if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) {
 -		sk = sk_head(&raw_v4_htable[state->bucket]);
@@ -872072,7 +932131,7 @@
  {
  	struct sock *sk;
  
-@@ -856,11 +917,15 @@ static void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -856,13 +917,17 @@ static void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  	++*pos;
  	return sk;
  }
@@ -872088,72 +932147,77 @@
  }
 +EXPORT_SYMBOL_GPL(raw_seq_stop);
  
- static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
+-static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
++static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
  {
-@@ -871,28 +936,30 @@ static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
+ 	struct inet_sock *inet = inet_sk(sp);
+ 	__be32 dest = inet->daddr,
+@@ -870,31 +935,23 @@ static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
+ 	__u16 destp = 0,
  	      srcp  = inet->num;
  
- 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
 -		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
++	seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
 +		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d",
  		i, src, srcp, dest, destp, sp->sk_state,
  		atomic_read(&sp->sk_wmem_alloc),
  		atomic_read(&sp->sk_rmem_alloc),
  		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
 -		atomic_read(&sp->sk_refcnt), sp);
+-	return tmpbuf;
 +		atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
- 	return tmpbuf;
  }
  
-+#define TMPSZ 128
-+
  static int raw_seq_show(struct seq_file *seq, void *v)
  {
 -	char tmpbuf[129];
-+	char tmpbuf[TMPSZ+1];
- 
+-
  	if (v == SEQ_START_TOKEN)
 -		seq_printf(seq, "%-127s\n",
-+		seq_printf(seq, "%-*s\n", TMPSZ-1,
- 			       "  sl  local_address rem_address   st tx_queue "
- 			       "rx_queue tr tm->when retrnsmt   uid  timeout "
+-			       "  sl  local_address rem_address   st tx_queue "
+-			       "rx_queue tr tm->when retrnsmt   uid  timeout "
 -			       "inode");
-+			       "inode  drops");
- 	else {
- 		struct raw_iter_state *state = raw_seq_private(seq);
- 
+-	else {
+-		struct raw_iter_state *state = raw_seq_private(seq);
+-
 -		seq_printf(seq, "%-127s\n",
-+		seq_printf(seq, "%-*s\n", TMPSZ-1,
- 			   get_raw_sock(v, tmpbuf, state->bucket));
- 	}
+-			   get_raw_sock(v, tmpbuf, state->bucket));
+-	}
++		seq_printf(seq, "  sl  local_address rem_address   st tx_queue "
++				"rx_queue tr tm->when retrnsmt   uid  timeout "
++				"inode  drops\n");
++	else
++		raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket);
  	return 0;
-@@ -905,29 +972,62 @@ static const struct seq_operations raw_seq_ops = {
+ }
+ 
+@@ -905,29 +962,60 @@ static const struct seq_operations raw_seq_ops = {
  	.show  = raw_seq_show,
  };
  
 -static int raw_seq_open(struct inode *inode, struct file *file)
-+int raw_seq_open(struct inode *ino, struct file *file, struct raw_hashinfo *h,
-+		unsigned short family)
- {
--	return seq_open_private(file, &raw_seq_ops,
++int raw_seq_open(struct inode *ino, struct file *file,
++		 struct raw_hashinfo *h, const struct seq_operations *ops)
++{
 +	int err;
 +	struct raw_iter_state *i;
 +
-+	err = seq_open_net(ino, file, &raw_seq_ops,
- 			sizeof(struct raw_iter_state));
++	err = seq_open_net(ino, file, ops, sizeof(struct raw_iter_state));
 +	if (err < 0)
 +		return err;
 +
 +	i = raw_seq_private((struct seq_file *)file->private_data);
 +	i->h = h;
-+	i->family = family;
 +	return 0;
 +}
 +EXPORT_SYMBOL_GPL(raw_seq_open);
 +
 +static int raw_v4_seq_open(struct inode *inode, struct file *file)
-+{
-+	return raw_seq_open(inode, file, &raw_v4_hashinfo, PF_INET);
+ {
+-	return seq_open_private(file, &raw_seq_ops,
+-			sizeof(struct raw_iter_state));
++	return raw_seq_open(inode, file, &raw_v4_hashinfo, &raw_seq_ops);
  }
  
  static const struct file_operations raw_seq_fops = {
@@ -872198,7 +932262,7 @@
  }
  #endif /* CONFIG_PROC_FS */
 diff --git a/net/ipv4/route.c b/net/ipv4/route.c
-index 28484f3..896c768 100644
+index 28484f3..8842ecb 100644
 --- a/net/ipv4/route.c
 +++ b/net/ipv4/route.c
 @@ -92,6 +92,7 @@
@@ -872209,16 +932273,24 @@
  #include <net/net_namespace.h>
  #include <net/protocol.h>
  #include <net/ip.h>
-@@ -132,13 +133,14 @@ static int ip_rt_mtu_expires		= 10 * 60 * HZ;
+@@ -116,8 +117,6 @@
+ 
+ #define RT_GC_TIMEOUT (300*HZ)
+ 
+-static int ip_rt_min_delay		= 2 * HZ;
+-static int ip_rt_max_delay		= 10 * HZ;
+ static int ip_rt_max_size;
+ static int ip_rt_gc_timeout		= RT_GC_TIMEOUT;
+ static int ip_rt_gc_interval		= 60 * HZ;
+@@ -132,13 +131,11 @@ static int ip_rt_mtu_expires		= 10 * 60 * HZ;
  static int ip_rt_min_pmtu		= 512 + 20 + 20;
  static int ip_rt_min_advmss		= 256;
  static int ip_rt_secret_interval	= 10 * 60 * HZ;
-+static int ip_rt_flush_expected;
- static unsigned long rt_deadline;
+-static unsigned long rt_deadline;
  
  #define RTprint(a...)	printk(KERN_DEBUG a)
  
- static struct timer_list rt_flush_timer;
+-static struct timer_list rt_flush_timer;
 -static void rt_check_expire(struct work_struct *work);
 -static DECLARE_DELAYED_WORK(expires_work, rt_check_expire);
 +static void rt_worker_func(struct work_struct *work);
@@ -872226,7 +932298,7 @@
  static struct timer_list rt_secret_timer;
  
  /*
-@@ -152,7 +154,7 @@ static void		 ipv4_dst_ifdown(struct dst_entry *dst,
+@@ -152,7 +149,7 @@ static void		 ipv4_dst_ifdown(struct dst_entry *dst,
  static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
  static void		 ipv4_link_failure(struct sk_buff *skb);
  static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
@@ -872235,15 +932307,17 @@
  
  
  static struct dst_ops ipv4_dst_ops = {
-@@ -165,6 +167,7 @@ static struct dst_ops ipv4_dst_ops = {
+@@ -165,7 +162,9 @@ static struct dst_ops ipv4_dst_ops = {
  	.negative_advice =	ipv4_negative_advice,
  	.link_failure =		ipv4_link_failure,
  	.update_pmtu =		ip_rt_update_pmtu,
 +	.local_out =		ip_local_out,
  	.entry_size =		sizeof(struct rtable),
++	.entries =		ATOMIC_INIT(0),
  };
  
-@@ -232,16 +235,25 @@ struct rt_hash_bucket {
+ #define ECN_OR_COST(class)	TC_PRIO_##class
+@@ -232,34 +231,40 @@ struct rt_hash_bucket {
  
  static spinlock_t	*rt_hash_locks;
  # define rt_hash_lock_addr(slot) &rt_hash_locks[(slot) & (RT_HASH_LOCK_SZ - 1)]
@@ -872277,7 +932351,112 @@
  #endif
  
  static struct rt_hash_bucket 	*rt_hash_table;
-@@ -478,6 +490,83 @@ static const struct file_operations rt_cpu_seq_fops = {
+ static unsigned			rt_hash_mask;
+ static unsigned int		rt_hash_log;
+-static unsigned int		rt_hash_rnd;
++static atomic_t			rt_genid;
+ 
+ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
+ #define RT_CACHE_STAT_INC(field) \
+ 	(__raw_get_cpu_var(rt_cache_stat).field++)
+ 
+-static int rt_intern_hash(unsigned hash, struct rtable *rth,
+-				struct rtable **res);
+-
+ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
+ {
+-	return (jhash_2words(daddr, saddr, rt_hash_rnd)
+-		& rt_hash_mask);
++	return jhash_2words(daddr, saddr, atomic_read(&rt_genid))
++		& rt_hash_mask;
+ }
+ 
+ #define rt_hash(daddr, saddr, idx) \
+@@ -269,27 +274,28 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
+ #ifdef CONFIG_PROC_FS
+ struct rt_cache_iter_state {
+ 	int bucket;
++	int genid;
+ };
+ 
+-static struct rtable *rt_cache_get_first(struct seq_file *seq)
++static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st)
+ {
+ 	struct rtable *r = NULL;
+-	struct rt_cache_iter_state *st = seq->private;
+ 
+ 	for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
+ 		rcu_read_lock_bh();
+-		r = rt_hash_table[st->bucket].chain;
+-		if (r)
+-			break;
++		r = rcu_dereference(rt_hash_table[st->bucket].chain);
++		while (r) {
++			if (r->rt_genid == st->genid)
++				return r;
++			r = rcu_dereference(r->u.dst.rt_next);
++		}
+ 		rcu_read_unlock_bh();
+ 	}
+-	return rcu_dereference(r);
++	return r;
+ }
+ 
+-static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
++static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r)
+ {
+-	struct rt_cache_iter_state *st = seq->private;
+-
+ 	r = r->u.dst.rt_next;
+ 	while (!r) {
+ 		rcu_read_unlock_bh();
+@@ -301,29 +307,38 @@ static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
+ 	return rcu_dereference(r);
+ }
+ 
+-static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos)
++static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos)
+ {
+-	struct rtable *r = rt_cache_get_first(seq);
++	struct rtable *r = rt_cache_get_first(st);
+ 
+ 	if (r)
+-		while (pos && (r = rt_cache_get_next(seq, r)))
++		while (pos && (r = rt_cache_get_next(st, r))) {
++			if (r->rt_genid != st->genid)
++				continue;
+ 			--pos;
++		}
+ 	return pos ? NULL : r;
+ }
+ 
+ static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+-	return *pos ? rt_cache_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
++	struct rt_cache_iter_state *st = seq->private;
++
++	if (*pos)
++		return rt_cache_get_idx(st, *pos - 1);
++	st->genid = atomic_read(&rt_genid);
++	return SEQ_START_TOKEN;
+ }
+ 
+ static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ {
+-	struct rtable *r = NULL;
++	struct rtable *r;
++	struct rt_cache_iter_state *st = seq->private;
+ 
+ 	if (v == SEQ_START_TOKEN)
+-		r = rt_cache_get_first(seq);
++		r = rt_cache_get_first(st);
+ 	else
+-		r = rt_cache_get_next(seq, v);
++		r = rt_cache_get_next(st, v);
+ 	++*pos;
+ 	return r;
+ }
+@@ -478,6 +493,83 @@ static const struct file_operations rt_cpu_seq_fops = {
  	.release = seq_release,
  };
  
@@ -872361,7 +932540,7 @@
  #endif /* CONFIG_PROC_FS */
  
  static __inline__ void rt_free(struct rtable *rt)
-@@ -559,7 +648,41 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
+@@ -559,7 +651,41 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
  		(fl1->iif ^ fl2->iif)) == 0;
  }
  
@@ -872404,39 +932583,43 @@
  {
  	static unsigned int rover;
  	unsigned int i = rover, goal;
-@@ -605,33 +728,33 @@ static void rt_check_expire(struct work_struct *work)
+@@ -585,6 +711,11 @@ static void rt_check_expire(struct work_struct *work)
+ 			continue;
+ 		spin_lock_bh(rt_hash_lock_addr(i));
+ 		while ((rth = *rthp) != NULL) {
++			if (rth->rt_genid != atomic_read(&rt_genid)) {
++				*rthp = rth->u.dst.rt_next;
++				rt_free(rth);
++				continue;
++			}
+ 			if (rth->u.dst.expires) {
+ 				/* Entry is expired even if it is in use */
+ 				if (time_before_eq(jiffies, rth->u.dst.expires)) {
+@@ -605,83 +736,50 @@ static void rt_check_expire(struct work_struct *work)
  		spin_unlock_bh(rt_hash_lock_addr(i));
  	}
  	rover = i;
-+}
-+
-+/*
-+ * rt_worker_func() is run in process context.
-+ * If a whole flush was scheduled, it is done.
-+ * Else, we call rt_check_expire() to scan part of the hash table
-+ */
-+static void rt_worker_func(struct work_struct *work)
-+{
-+	if (ip_rt_flush_expected) {
-+		ip_rt_flush_expected = 0;
-+		rt_do_flush(1);
-+	} else
-+		rt_check_expire();
- 	schedule_delayed_work(&expires_work, ip_rt_gc_interval);
+-	schedule_delayed_work(&expires_work, ip_rt_gc_interval);
  }
  
- /* This can run from both BH and non-BH contexts, the latter
-  * in the case of a forced flush event.
+-/* This can run from both BH and non-BH contexts, the latter
+- * in the case of a forced flush event.
++/*
++ * rt_worker_func() is run in process context.
++ * we call rt_check_expire() to scan part of the hash table
   */
 -static void rt_run_flush(unsigned long dummy)
-+static void rt_run_flush(unsigned long process_context)
++static void rt_worker_func(struct work_struct *work)
  {
 -	int i;
 -	struct rtable *rth, *next;
 -
- 	rt_deadline = 0;
- 
- 	get_random_bytes(&rt_hash_rnd, 4);
+-	rt_deadline = 0;
+-
+-	get_random_bytes(&rt_hash_rnd, 4);
++	rt_check_expire();
++	schedule_delayed_work(&expires_work, ip_rt_gc_interval);
++}
  
 -	for (i = rt_hash_mask; i >= 0; i--) {
 -		spin_lock_bh(rt_hash_lock_addr(i));
@@ -872444,32 +932627,76 @@
 -		if (rth)
 -			rt_hash_table[i].chain = NULL;
 -		spin_unlock_bh(rt_hash_lock_addr(i));
--
++/*
++ * Pertubation of rt_genid by a small quantity [1..256]
++ * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
++ * many times (2^24) without giving recent rt_genid.
++ * Jenkins hash is strong enough that litle changes of rt_genid are OK.
++ */
++static void rt_cache_invalidate(void)
++{
++	unsigned char shuffle;
+ 
 -		for (; rth; rth = next) {
 -			next = rth->u.dst.rt_next;
 -			rt_free(rth);
 -		}
 -	}
-+	rt_do_flush(process_context);
++	get_random_bytes(&shuffle, sizeof(shuffle));
++	atomic_add(shuffle + 1U, &rt_genid);
  }
  
- static DEFINE_SPINLOCK(rt_flush_lock);
-@@ -665,7 +788,7 @@ void rt_cache_flush(int delay)
- 
- 	if (delay <= 0) {
- 		spin_unlock_bh(&rt_flush_lock);
+-static DEFINE_SPINLOCK(rt_flush_lock);
+-
++/*
++ * delay < 0  : invalidate cache (fast : entries will be deleted later)
++ * delay >= 0 : invalidate & flush cache (can be long)
++ */
+ void rt_cache_flush(int delay)
+ {
+-	unsigned long now = jiffies;
+-	int user_mode = !in_softirq();
+-
+-	if (delay < 0)
+-		delay = ip_rt_min_delay;
+-
+-	spin_lock_bh(&rt_flush_lock);
+-
+-	if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
+-		long tmo = (long)(rt_deadline - now);
+-
+-		/* If flush timer is already running
+-		   and flush request is not immediate (delay > 0):
+-
+-		   if deadline is not achieved, prolongate timer to "delay",
+-		   otherwise fire it at deadline time.
+-		 */
+-
+-		if (user_mode && tmo < ip_rt_max_delay-ip_rt_min_delay)
+-			tmo = 0;
+-
+-		if (delay > tmo)
+-			delay = tmo;
+-	}
+-
+-	if (delay <= 0) {
+-		spin_unlock_bh(&rt_flush_lock);
 -		rt_run_flush(0);
-+		rt_run_flush(user_mode);
- 		return;
- 	}
- 
-@@ -676,12 +799,17 @@ void rt_cache_flush(int delay)
- 	spin_unlock_bh(&rt_flush_lock);
+-		return;
+-	}
+-
+-	if (rt_deadline == 0)
+-		rt_deadline = now + ip_rt_max_delay;
+-
+-	mod_timer(&rt_flush_timer, now+delay);
+-	spin_unlock_bh(&rt_flush_lock);
++	rt_cache_invalidate();
++	if (delay >= 0)
++		rt_do_flush(!in_softirq());
  }
  
 +/*
-+ * We change rt_hash_rnd and ask next rt_worker_func() invocation
-+ * to perform a flush in process context
++ * We change rt_genid and let gc do the cleanup
 + */
  static void rt_secret_rebuild(unsigned long dummy)
  {
@@ -872477,15 +932704,12 @@
 -
 -	rt_cache_flush(0);
 -	mod_timer(&rt_secret_timer, now + ip_rt_secret_interval);
-+	get_random_bytes(&rt_hash_rnd, 4);
-+	ip_rt_flush_expected = 1;
-+	cancel_delayed_work(&expires_work);
-+	schedule_delayed_work(&expires_work, HZ/10);
++	rt_cache_invalidate();
 +	mod_timer(&rt_secret_timer, jiffies + ip_rt_secret_interval);
  }
  
  /*
-@@ -697,7 +825,7 @@ static void rt_secret_rebuild(unsigned long dummy)
+@@ -697,7 +795,7 @@ static void rt_secret_rebuild(unsigned long dummy)
     and when load increases it reduces to limit cache size.
   */
  
@@ -872494,7 +932718,7 @@
  {
  	static unsigned long expire = RT_GC_TIMEOUT;
  	static unsigned long last_gc;
-@@ -728,14 +856,14 @@ static int rt_garbage_collect(void)
+@@ -728,14 +826,14 @@ static int rt_garbage_collect(void)
  			equilibrium = ipv4_dst_ops.gc_thresh;
  		goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
  		if (goal > 0) {
@@ -872511,16 +932735,31 @@
  		equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;
  	}
  
-@@ -838,7 +966,7 @@ restart:
+@@ -757,7 +855,8 @@ static int rt_garbage_collect(void)
+ 			rthp = &rt_hash_table[k].chain;
+ 			spin_lock_bh(rt_hash_lock_addr(k));
+ 			while ((rth = *rthp) != NULL) {
+-				if (!rt_may_expire(rth, tmo, expire)) {
++				if (rth->rt_genid == atomic_read(&rt_genid) &&
++					!rt_may_expire(rth, tmo, expire)) {
+ 					tmo >>= 1;
+ 					rthp = &rth->u.dst.rt_next;
+ 					continue;
+@@ -838,7 +937,12 @@ restart:
  
  	spin_lock_bh(rt_hash_lock_addr(hash));
  	while ((rth = *rthp) != NULL) {
 -		if (compare_keys(&rth->fl, &rt->fl)) {
++		if (rth->rt_genid != atomic_read(&rt_genid)) {
++			*rthp = rth->u.dst.rt_next;
++			rt_free(rth);
++			continue;
++		}
 +		if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt)) {
  			/* Put it first */
  			*rthp = rth->u.dst.rt_next;
  			/*
-@@ -912,7 +1040,7 @@ restart:
+@@ -912,7 +1016,7 @@ restart:
  				int saved_int = ip_rt_gc_min_interval;
  				ip_rt_gc_elasticity	= 1;
  				ip_rt_gc_min_interval	= 0;
@@ -872529,7 +932768,34 @@
  				ip_rt_gc_min_interval	= saved_int;
  				ip_rt_gc_elasticity	= saved_elasticity;
  				goto restart;
-@@ -1031,7 +1159,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+@@ -1003,17 +1107,19 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
+ 
+ static void rt_del(unsigned hash, struct rtable *rt)
+ {
+-	struct rtable **rthp;
++	struct rtable **rthp, *aux;
+ 
++	rthp = &rt_hash_table[hash].chain;
+ 	spin_lock_bh(rt_hash_lock_addr(hash));
+ 	ip_rt_put(rt);
+-	for (rthp = &rt_hash_table[hash].chain; *rthp;
+-	     rthp = &(*rthp)->u.dst.rt_next)
+-		if (*rthp == rt) {
+-			*rthp = rt->u.dst.rt_next;
+-			rt_free(rt);
+-			break;
++	while ((aux = *rthp) != NULL) {
++		if (aux == rt || (aux->rt_genid != atomic_read(&rt_genid))) {
++			*rthp = aux->u.dst.rt_next;
++			rt_free(aux);
++			continue;
+ 		}
++		rthp = &aux->u.dst.rt_next;
++	}
+ 	spin_unlock_bh(rt_hash_lock_addr(hash));
+ }
+ 
+@@ -1031,7 +1137,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
  		return;
  
  	if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev)
@@ -872539,7 +932805,7 @@
  		goto reject_redirect;
  
  	if (!IN_DEV_SHARED_MEDIA(in_dev)) {
-@@ -1040,7 +1169,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+@@ -1040,7 +1147,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
  		if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
  			goto reject_redirect;
  	} else {
@@ -872548,7 +932814,26 @@
  			goto reject_redirect;
  	}
  
-@@ -1291,7 +1420,8 @@ static __inline__ unsigned short guess_mtu(unsigned short old_mtu)
+@@ -1057,7 +1164,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+ 				if (rth->fl.fl4_dst != daddr ||
+ 				    rth->fl.fl4_src != skeys[i] ||
+ 				    rth->fl.oif != ikeys[k] ||
+-				    rth->fl.iif != 0) {
++				    rth->fl.iif != 0 ||
++				    rth->rt_genid != atomic_read(&rt_genid)) {
+ 					rthp = &rth->u.dst.rt_next;
+ 					continue;
+ 				}
+@@ -1095,7 +1203,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+ 				rt->u.dst.neighbour	= NULL;
+ 				rt->u.dst.hh		= NULL;
+ 				rt->u.dst.xfrm		= NULL;
+-
++				rt->rt_genid		= atomic_read(&rt_genid);
+ 				rt->rt_flags		|= RTCF_REDIRECTED;
+ 
+ 				/* Gateway is different ... */
+@@ -1291,7 +1399,8 @@ static __inline__ unsigned short guess_mtu(unsigned short old_mtu)
  	return 68;
  }
  
@@ -872558,17 +932843,18 @@
  {
  	int i;
  	unsigned short old_mtu = ntohs(iph->tot_len);
-@@ -1314,7 +1444,8 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
+@@ -1314,7 +1423,9 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
  			    rth->rt_dst  == daddr &&
  			    rth->rt_src  == iph->saddr &&
  			    rth->fl.iif == 0 &&
 -			    !(dst_metric_locked(&rth->u.dst, RTAX_MTU))) {
 +			    !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
-+			    rth->u.dst.dev->nd_net == net) {
++			    rth->u.dst.dev->nd_net == net &&
++			    rth->rt_genid == atomic_read(&rt_genid)) {
  				unsigned short mtu = new_mtu;
  
  				if (new_mtu < 68 || new_mtu >= old_mtu) {
-@@ -1389,8 +1520,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+@@ -1389,8 +1500,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  {
  	struct rtable *rt = (struct rtable *) dst;
  	struct in_device *idev = rt->idev;
@@ -872580,7 +932866,7 @@
  		if (loopback_idev) {
  			rt->idev = loopback_idev;
  			in_dev_put(idev);
-@@ -1434,7 +1566,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
+@@ -1434,7 +1546,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
  
  	if (rt->fl.iif == 0)
  		src = rt->rt_src;
@@ -872589,7 +932875,7 @@
  		src = FIB_RES_PREFSRC(res);
  		fib_res_put(&res);
  	} else
-@@ -1509,12 +1641,12 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1509,12 +1621,12 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	if (in_dev == NULL)
  		return -EINVAL;
  
@@ -872606,7 +932892,17 @@
  			goto e_inval;
  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
  	} else if (fib_validate_source(saddr, 0, tos, 0,
-@@ -1556,7 +1688,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1548,15 +1660,16 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ 	rth->fl.oif	= 0;
+ 	rth->rt_gateway	= daddr;
+ 	rth->rt_spec_dst= spec_dst;
+-	rth->rt_type	= RTN_MULTICAST;
++	rth->rt_genid	= atomic_read(&rt_genid);
+ 	rth->rt_flags	= RTCF_MULTICAST;
++	rth->rt_type	= RTN_MULTICAST;
+ 	if (our) {
+ 		rth->u.dst.input= ip_local_deliver;
+ 		rth->rt_flags |= RTCF_LOCAL;
  	}
  
  #ifdef CONFIG_IP_MROUTE
@@ -872615,7 +932911,7 @@
  		rth->u.dst.input = ip_mr_input;
  #endif
  	RT_CACHE_STAT_INC(in_slow_mc);
-@@ -1643,7 +1775,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
+@@ -1643,7 +1756,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
  	if (err)
  		flags |= RTCF_DIRECTSRC;
  
@@ -872624,7 +932920,7 @@
  	    (IN_DEV_SHARED_MEDIA(out_dev) ||
  	     inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
  		flags |= RTCF_DOREDIRECT;
-@@ -1652,7 +1784,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
+@@ -1652,7 +1765,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
  		/* Not IP (i.e. ARP). Do not create route, if it is
  		 * invalid for proxy arp. DNAT routes are always valid.
  		 */
@@ -872633,7 +932929,15 @@
  			err = -EINVAL;
  			goto cleanup;
  		}
-@@ -1756,6 +1888,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1688,6 +1801,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
+ 
+ 	rth->u.dst.input = ip_forward;
+ 	rth->u.dst.output = ip_output;
++	rth->rt_genid = atomic_read(&rt_genid);
+ 
+ 	rt_set_nexthop(rth, res, itag);
+ 
+@@ -1756,6 +1870,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	__be32		spec_dst;
  	int		err = -EINVAL;
  	int		free_res = 0;
@@ -872641,7 +932945,7 @@
  
  	/* IP on this device is disabled. */
  
-@@ -1766,7 +1899,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1766,7 +1881,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	   by fib_lookup.
  	 */
  
@@ -872651,7 +932955,7 @@
  		goto martian_source;
  
  	if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
-@@ -1775,16 +1909,17 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1775,16 +1891,17 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	/* Accept zero addresses only to limited broadcast;
  	 * I even do not know to fix it or not. Waiting for complains :-)
  	 */
@@ -872672,7 +932976,7 @@
  		if (!IN_DEV_FORWARD(in_dev))
  			goto e_hostunreach;
  		goto no_route;
-@@ -1799,7 +1934,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1799,7 +1916,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	if (res.type == RTN_LOCAL) {
  		int result;
  		result = fib_validate_source(saddr, daddr, tos,
@@ -872681,7 +932985,7 @@
  					     dev, &spec_dst, &itag);
  		if (result < 0)
  			goto martian_source;
-@@ -1825,7 +1960,7 @@ brd_input:
+@@ -1825,7 +1942,7 @@ brd_input:
  	if (skb->protocol != htons(ETH_P_IP))
  		goto e_inval;
  
@@ -872690,7 +932994,15 @@
  		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
  	else {
  		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
-@@ -1861,7 +1996,7 @@ local_input:
+@@ -1845,6 +1962,7 @@ local_input:
+ 		goto e_nobufs;
+ 
+ 	rth->u.dst.output= ip_rt_bug;
++	rth->rt_genid = atomic_read(&rt_genid);
+ 
+ 	atomic_set(&rth->u.dst.__refcnt, 1);
+ 	rth->u.dst.flags= DST_HOST;
+@@ -1861,7 +1979,7 @@ local_input:
  #endif
  	rth->rt_iif	=
  	rth->fl.iif	= dev->ifindex;
@@ -872699,7 +933011,7 @@
  	dev_hold(rth->u.dst.dev);
  	rth->idev	= in_dev_get(rth->u.dst.dev);
  	rth->rt_gateway	= daddr;
-@@ -1921,7 +2056,9 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1921,7 +2039,9 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	struct rtable * rth;
  	unsigned	hash;
  	int iif = dev->ifindex;
@@ -872709,17 +933021,18 @@
  	tos &= IPTOS_RT_MASK;
  	hash = rt_hash(daddr, saddr, iif);
  
-@@ -1933,7 +2070,8 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1933,7 +2053,9 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  		    rth->fl.iif == iif &&
  		    rth->fl.oif == 0 &&
  		    rth->fl.mark == skb->mark &&
 -		    rth->fl.fl4_tos == tos) {
 +		    rth->fl.fl4_tos == tos &&
-+		    rth->u.dst.dev->nd_net == net) {
++		    rth->u.dst.dev->nd_net == net &&
++		    rth->rt_genid == atomic_read(&rt_genid)) {
  			dst_use(&rth->u.dst, jiffies);
  			RT_CACHE_STAT_INC(in_hit);
  			rcu_read_unlock();
-@@ -1955,7 +2093,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1955,7 +2077,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  	   Note, that multicast routers are not affected, because
  	   route cache entry is created eventually.
  	 */
@@ -872728,7 +933041,7 @@
  		struct in_device *in_dev;
  
  		rcu_read_lock();
-@@ -1964,7 +2102,8 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+@@ -1964,7 +2086,8 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
  				ip_hdr(skb)->protocol);
  			if (our
  #ifdef CONFIG_IP_MROUTE
@@ -872738,7 +933051,7 @@
  #endif
  			    ) {
  				rcu_read_unlock();
-@@ -1990,14 +2129,14 @@ static inline int __mkroute_output(struct rtable **result,
+@@ -1990,14 +2113,14 @@ static inline int __mkroute_output(struct rtable **result,
  	u32 tos = RT_FL_TOS(oldflp);
  	int err = 0;
  
@@ -872756,7 +933069,15 @@
  		return -EINVAL;
  
  	if (dev_out->flags & IFF_LOOPBACK)
-@@ -2077,7 +2216,7 @@ static inline int __mkroute_output(struct rtable **result,
+@@ -2060,6 +2183,7 @@ static inline int __mkroute_output(struct rtable **result,
+ 	rth->rt_spec_dst= fl->fl4_src;
+ 
+ 	rth->u.dst.output=ip_output;
++	rth->rt_genid = atomic_read(&rt_genid);
+ 
+ 	RT_CACHE_STAT_INC(out_slow_tot);
+ 
+@@ -2077,7 +2201,7 @@ static inline int __mkroute_output(struct rtable **result,
  #ifdef CONFIG_IP_MROUTE
  		if (res->type == RTN_MULTICAST) {
  			if (IN_DEV_MFORWARD(in_dev) &&
@@ -872765,7 +933086,7 @@
  				rth->u.dst.input = ip_mr_input;
  				rth->u.dst.output = ip_mc_output;
  			}
-@@ -2119,7 +2258,8 @@ static inline int ip_mkroute_output(struct rtable **rp,
+@@ -2119,7 +2243,8 @@ static inline int ip_mkroute_output(struct rtable **rp,
   * Major route resolver routine.
   */
  
@@ -872775,7 +933096,7 @@
  {
  	u32 tos	= RT_FL_TOS(oldflp);
  	struct flowi fl = { .nl_u = { .ip4_u =
-@@ -2131,7 +2271,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2131,7 +2256,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  						  RT_SCOPE_UNIVERSE),
  				      } },
  			    .mark = oldflp->mark,
@@ -872784,7 +933105,7 @@
  			    .oif = oldflp->oif };
  	struct fib_result res;
  	unsigned flags = 0;
-@@ -2147,26 +2287,27 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2147,26 +2272,27 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  
  	if (oldflp->fl4_src) {
  		err = -EINVAL;
@@ -872819,7 +933140,7 @@
  			/* Special hack: user can direct multicasts
  			   and limited broadcast via necessary interface
  			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
-@@ -2192,7 +2333,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2192,7 +2318,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  
  
  	if (oldflp->oif) {
@@ -872828,7 +933149,7 @@
  		err = -ENODEV;
  		if (dev_out == NULL)
  			goto out;
-@@ -2203,14 +2344,15 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2203,14 +2329,15 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  			goto out;	/* Wrong error code */
  		}
  
@@ -872846,7 +933167,7 @@
  				fl.fl4_src = inet_select_addr(dev_out, 0,
  							      fl.fl4_scope);
  			else if (!oldflp->fl4_dst)
-@@ -2225,15 +2367,15 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2225,15 +2352,15 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  			fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
  		if (dev_out)
  			dev_put(dev_out);
@@ -872865,7 +933186,7 @@
  		res.fi = NULL;
  		if (oldflp->oif) {
  			/* Apparently, routing tables are wrong. Assume,
-@@ -2272,7 +2414,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2272,7 +2399,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  			fl.fl4_src = fl.fl4_dst;
  		if (dev_out)
  			dev_put(dev_out);
@@ -872874,7 +933195,7 @@
  		dev_hold(dev_out);
  		fl.oif = dev_out->ifindex;
  		if (res.fi)
-@@ -2288,7 +2430,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
+@@ -2288,7 +2415,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
  	else
  #endif
  	if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
@@ -872883,7 +933204,7 @@
  
  	if (!fl.fl4_src)
  		fl.fl4_src = FIB_RES_PREFSRC(res);
-@@ -2311,7 +2453,8 @@ make_route:
+@@ -2311,7 +2438,8 @@ make_route:
  out:	return err;
  }
  
@@ -872893,17 +933214,18 @@
  {
  	unsigned hash;
  	struct rtable *rth;
-@@ -2327,7 +2470,8 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
+@@ -2327,7 +2455,9 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
  		    rth->fl.oif == flp->oif &&
  		    rth->fl.mark == flp->mark &&
  		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
 -			    (IPTOS_RT_MASK | RTO_ONLINK))) {
 +			    (IPTOS_RT_MASK | RTO_ONLINK)) &&
-+		    rth->u.dst.dev->nd_net == net) {
++		    rth->u.dst.dev->nd_net == net &&
++		    rth->rt_genid == atomic_read(&rt_genid)) {
  			dst_use(&rth->u.dst, jiffies);
  			RT_CACHE_STAT_INC(out_hit);
  			rcu_read_unlock_bh();
-@@ -2338,7 +2482,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
+@@ -2338,7 +2468,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
  	}
  	rcu_read_unlock_bh();
  
@@ -872912,7 +933234,11 @@
  }
  
  EXPORT_SYMBOL_GPL(__ip_route_output_key);
-@@ -2357,12 +2501,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
+@@ -2354,15 +2484,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
+ 	.check			=	ipv4_dst_check,
+ 	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
+ 	.entry_size		=	sizeof(struct rtable),
++	.entries		=	ATOMIC_INIT(0),
  };
  
  
@@ -872925,7 +933251,7 @@
  static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk)
  {
  	struct rtable *ort = *rp;
-@@ -2374,8 +2512,8 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
+@@ -2374,8 +2499,8 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
  
  		atomic_set(&new->__refcnt, 1);
  		new->__use = 1;
@@ -872936,7 +933262,15 @@
  		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
  
  		new->dev = ort->u.dst.dev;
-@@ -2406,11 +2544,12 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
+@@ -2387,6 +2512,7 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
+ 		rt->idev = ort->idev;
+ 		if (rt->idev)
+ 			in_dev_hold(rt->idev);
++		rt->rt_genid = atomic_read(&rt_genid);
+ 		rt->rt_flags = ort->rt_flags;
+ 		rt->rt_type = ort->rt_type;
+ 		rt->rt_dst = ort->rt_dst;
+@@ -2406,11 +2532,12 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
  	return (rt ? 0 : -ENOMEM);
  }
  
@@ -872951,7 +933285,7 @@
  		return err;
  
  	if (flp->proto) {
-@@ -2418,7 +2557,8 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
+@@ -2418,7 +2545,8 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
  			flp->fl4_src = (*rp)->rt_src;
  		if (!flp->fl4_dst)
  			flp->fl4_dst = (*rp)->rt_dst;
@@ -872961,7 +933295,7 @@
  		if (err == -EREMOTE)
  			err = ipv4_dst_blackhole(rp, flp, sk);
  
-@@ -2430,9 +2570,9 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
+@@ -2430,9 +2558,9 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk,
  
  EXPORT_SYMBOL_GPL(ip_route_output_flow);
  
@@ -872973,7 +933307,7 @@
  }
  
  static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
-@@ -2499,8 +2639,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+@@ -2499,8 +2627,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
  #ifdef CONFIG_IP_MROUTE
  		__be32 dst = rt->rt_dst;
  
@@ -872984,7 +933318,7 @@
  			int err = ipmr_get_route(skb, r, nowait);
  			if (err <= 0) {
  				if (!nowait) {
-@@ -2531,6 +2671,7 @@ nla_put_failure:
+@@ -2531,6 +2659,7 @@ nla_put_failure:
  
  static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
  {
@@ -872992,7 +933326,7 @@
  	struct rtmsg *rtm;
  	struct nlattr *tb[RTA_MAX+1];
  	struct rtable *rt = NULL;
-@@ -2540,6 +2681,9 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
+@@ -2540,6 +2669,9 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
  	int err;
  	struct sk_buff *skb;
  
@@ -873002,7 +933336,7 @@
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
  	if (err < 0)
  		goto errout;
-@@ -2595,7 +2739,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
+@@ -2595,7 +2727,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
  			},
  			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
  		};
@@ -873011,7 +933345,7 @@
  	}
  
  	if (err)
-@@ -2610,7 +2754,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
+@@ -2610,7 +2742,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
  	if (err <= 0)
  		goto errout_free;
  
@@ -873020,7 +933354,41 @@
  errout:
  	return err;
  
-@@ -2862,51 +3006,7 @@ ctl_table ipv4_route_table[] = {
+@@ -2635,6 +2767,8 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
+ 		     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
+ 			if (idx < s_idx)
+ 				continue;
++			if (rt->rt_genid != atomic_read(&rt_genid))
++				continue;
+ 			skb->dst = dst_clone(&rt->u.dst);
+ 			if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
+ 					 cb->nlh->nlmsg_seq, RTM_NEWROUTE,
+@@ -2704,24 +2838,6 @@ ctl_table ipv4_route_table[] = {
+ 		.strategy	= &ipv4_sysctl_rtcache_flush_strategy,
+ 	},
+ 	{
+-		.ctl_name	= NET_IPV4_ROUTE_MIN_DELAY,
+-		.procname	= "min_delay",
+-		.data		= &ip_rt_min_delay,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec_jiffies,
+-		.strategy	= &sysctl_jiffies,
+-	},
+-	{
+-		.ctl_name	= NET_IPV4_ROUTE_MAX_DELAY,
+-		.procname	= "max_delay",
+-		.data		= &ip_rt_max_delay,
+-		.maxlen		= sizeof(int),
+-		.mode		= 0644,
+-		.proc_handler	= &proc_dointvec_jiffies,
+-		.strategy	= &sysctl_jiffies,
+-	},
+-	{
+ 		.ctl_name	= NET_IPV4_ROUTE_GC_THRESH,
+ 		.procname	= "gc_thresh",
+ 		.data		= &ipv4_dst_ops.gc_thresh,
+@@ -2862,51 +2978,7 @@ ctl_table ipv4_route_table[] = {
  #endif
  
  #ifdef CONFIG_NET_CLS_ROUTE
@@ -873073,8 +933441,14 @@
  #endif /* CONFIG_NET_CLS_ROUTE */
  
  static __initdata unsigned long rhash_entries;
-@@ -2927,16 +3027,9 @@ int __init ip_rt_init(void)
- 			     (jiffies ^ (jiffies >> 7)));
+@@ -2923,20 +2995,13 @@ int __init ip_rt_init(void)
+ {
+ 	int rc = 0;
+ 
+-	rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^
+-			     (jiffies ^ (jiffies >> 7)));
++	atomic_set(&rt_genid, (int) ((num_physpages ^ (num_physpages>>8)) ^
++			     (jiffies ^ (jiffies >> 7))));
  
  #ifdef CONFIG_NET_CLS_ROUTE
 -	{
@@ -873091,7 +933465,7 @@
  #endif
  
  	ipv4_dst_ops.kmem_cachep =
-@@ -2964,10 +3057,8 @@ int __init ip_rt_init(void)
+@@ -2964,10 +3029,7 @@ int __init ip_rt_init(void)
  	devinet_init();
  	ip_fib_init();
  
@@ -873099,12 +933473,11 @@
 -	rt_flush_timer.function = rt_run_flush;
 -	init_timer(&rt_secret_timer);
 -	rt_secret_timer.function = rt_secret_rebuild;
-+	setup_timer(&rt_flush_timer, rt_run_flush, 0);
 +	setup_timer(&rt_secret_timer, rt_secret_rebuild, 0);
  
  	/* All the timers, started at system startup tend
  	   to synchronize. Perturb it a bit.
-@@ -2979,20 +3070,8 @@ int __init ip_rt_init(void)
+@@ -2979,20 +3041,8 @@ int __init ip_rt_init(void)
  		ip_rt_secret_interval;
  	add_timer(&rt_secret_timer);
  
@@ -873141,7 +933514,7 @@
  			goto out;
  		}
 diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
-index bec6fe8..82cdf23 100644
+index bec6fe8..88286f3 100644
 --- a/net/ipv4/sysctl_net_ipv4.c
 +++ b/net/ipv4/sysctl_net_ipv4.c
 @@ -13,83 +13,20 @@
@@ -873230,6 +933603,15 @@
  
  extern seqlock_t sysctl_port_range_lock;
  extern int sysctl_local_port_range[2];
+@@ -248,7 +185,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
+ 
+ 	tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
+ 	ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
+-	if (ret == 0 && newval && newlen)
++	if (ret == 1 && newval && newlen)
+ 		ret = tcp_set_allowed_congestion_control(tbl.data);
+ 	kfree(tbl.data);
+ 
 @@ -256,7 +193,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
  
  }
@@ -873873,7 +934255,7 @@
  	struct tcp_sock *tp = tcp_sk(sk);
  	struct illinois *ca = inet_csk_ca(sk);
 diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
-index b39f0d8..fa2c85c 100644
+index b39f0d8..19c449f 100644
 --- a/net/ipv4/tcp_input.c
 +++ b/net/ipv4/tcp_input.c
 @@ -105,6 +105,7 @@ int sysctl_tcp_abc __read_mostly;
@@ -874948,7 +935330,7 @@
 -		cnt += tcp_skb_pcount(skb);
 -		if (cnt > packets || after(TCP_SKB_CB(skb)->end_seq, tp->high_seq))
 +
-+		if (tcp_is_fack(tp) ||
++		if (tcp_is_fack(tp) || tcp_is_reno(tp) ||
 +		    (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
 +			cnt += tcp_skb_pcount(skb);
 +
@@ -876259,7 +936641,7 @@
  
  				if (tp->rx_opt.tstamp_ok)
 diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
-index 652c323..9aea88b 100644
+index 652c323..77c1939 100644
 --- a/net/ipv4/tcp_ipv4.c
 +++ b/net/ipv4/tcp_ipv4.c
 @@ -99,7 +99,7 @@ static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
@@ -876271,6 +936653,17 @@
  #endif
  
  struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
+@@ -369,8 +369,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
+ 		return;
+ 	}
+ 
+-	sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr,
+-			 th->source, inet_iif(skb));
++	sk = inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->daddr, th->dest,
++			iph->saddr, th->source, inet_iif(skb));
+ 	if (!sk) {
+ 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+ 		return;
 @@ -1020,7 +1020,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
  static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
  				   __be32 saddr, __be32 daddr,
@@ -876298,6 +936691,38 @@
  	__inet_inherit_port(&tcp_hashinfo, sk, newsk);
  
  	return newsk;
+@@ -1503,8 +1503,8 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
+ 	if (req)
+ 		return tcp_check_req(sk, skb, req, prev);
+ 
+-	nsk = inet_lookup_established(&tcp_hashinfo, iph->saddr, th->source,
+-				      iph->daddr, th->dest, inet_iif(skb));
++	nsk = inet_lookup_established(sk->sk_net, &tcp_hashinfo, iph->saddr,
++			th->source, iph->daddr, th->dest, inet_iif(skb));
+ 
+ 	if (nsk) {
+ 		if (nsk->sk_state != TCP_TIME_WAIT) {
+@@ -1661,8 +1661,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
+ 	TCP_SKB_CB(skb)->flags	 = iph->tos;
+ 	TCP_SKB_CB(skb)->sacked	 = 0;
+ 
+-	sk = __inet_lookup(&tcp_hashinfo, iph->saddr, th->source,
+-			   iph->daddr, th->dest, inet_iif(skb));
++	sk = __inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->saddr,
++			th->source, iph->daddr, th->dest, inet_iif(skb));
+ 	if (!sk)
+ 		goto no_tcp_socket;
+ 
+@@ -1735,7 +1735,8 @@ do_time_wait:
+ 	}
+ 	switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
+ 	case TCP_TW_SYN: {
+-		struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
++		struct sock *sk2 = inet_lookup_listener(skb->dev->nd_net,
++							&tcp_hashinfo,
+ 							iph->daddr, th->dest,
+ 							inet_iif(skb));
+ 		if (sk2) {
 diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
 index e7f5ef9..ce3c41f 100644
 --- a/net/ipv4/tcp_lp.c
@@ -876318,7 +936743,7 @@
  
  /**
 diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
-index f4c1eef..89f0188 100644
+index f4c1eef..ed750f9 100644
 --- a/net/ipv4/tcp_output.c
 +++ b/net/ipv4/tcp_output.c
 @@ -61,27 +61,24 @@ int sysctl_tcp_base_mss __read_mostly = 512;
@@ -877631,6 +938056,12 @@
  }
  
  /* A window probe timeout has occurred.  If window is not closed send
+@@ -2595,5 +2564,4 @@ EXPORT_SYMBOL(tcp_connect);
+ EXPORT_SYMBOL(tcp_make_synack);
+ EXPORT_SYMBOL(tcp_simple_retransmit);
+ EXPORT_SYMBOL(tcp_sync_mss);
+-EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
+ EXPORT_SYMBOL(tcp_mtup_init);
 diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
 index be27a33..2747ec7 100644
 --- a/net/ipv4/tcp_scalable.c
@@ -877814,7 +938245,7 @@
  	struct tcp_sock *tp = tcp_sk(sk);
  	struct yeah *yeah = inet_csk_ca(sk);
 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
-index 03c400c..2fb8d73 100644
+index 03c400c..7ea1b67 100644
 --- a/net/ipv4/udp.c
 +++ b/net/ipv4/udp.c
 @@ -82,6 +82,7 @@
@@ -877825,7 +938256,7 @@
  #include <linux/types.h>
  #include <linux/fcntl.h>
  #include <linux/module.h>
-@@ -110,10 +111,25 @@
+@@ -110,18 +111,33 @@
   */
  
  DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly;
@@ -877837,6 +938268,7 @@
  struct hlist_head udp_hash[UDP_HTABLE_SIZE];
  DEFINE_RWLOCK(udp_hash_lock);
  
+-static inline int __udp_lib_lport_inuse(__u16 num,
 +int sysctl_udp_mem[3] __read_mostly;
 +int sysctl_udp_rmem_min __read_mostly;
 +int sysctl_udp_wmem_min __read_mostly;
@@ -877848,10 +938280,44 @@
 +atomic_t udp_memory_allocated;
 +EXPORT_SYMBOL(udp_memory_allocated);
 +
- static inline int __udp_lib_lport_inuse(__u16 num,
++static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
  					const struct hlist_head udptable[])
  {
-@@ -214,7 +230,7 @@ gotit:
+ 	struct sock *sk;
+ 	struct hlist_node *node;
+ 
+ 	sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
+-		if (sk->sk_hash == num)
++		if (sk->sk_net == net && sk->sk_hash == num)
+ 			return 1;
+ 	return 0;
+ }
+@@ -143,6 +159,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
+ 	struct hlist_head *head;
+ 	struct sock *sk2;
+ 	int    error = 1;
++	struct net *net = sk->sk_net;
+ 
+ 	write_lock_bh(&udp_hash_lock);
+ 
+@@ -182,7 +199,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
+ 		/* 2nd pass: find hole in shortest hash chain */
+ 		rover = best;
+ 		for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
+-			if (! __udp_lib_lport_inuse(rover, udptable))
++			if (! __udp_lib_lport_inuse(net, rover, udptable))
+ 				goto gotit;
+ 			rover += UDP_HTABLE_SIZE;
+ 			if (rover > high)
+@@ -202,6 +219,7 @@ gotit:
+ 		sk_for_each(sk2, node, head)
+ 			if (sk2->sk_hash == snum                             &&
+ 			    sk2 != sk                                        &&
++			    sk2->sk_net == net				     &&
+ 			    (!sk2->sk_reuse        || !sk->sk_reuse)         &&
+ 			    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
+ 			     || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+@@ -214,7 +232,7 @@ gotit:
  	if (sk_unhashed(sk)) {
  		head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
  		sk_add_node(sk, head);
@@ -877860,7 +938326,41 @@
  	}
  	error = 0;
  fail:
-@@ -402,7 +418,7 @@ out:
+@@ -245,9 +263,9 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
+ /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
+  * harder than this. -DaveM
+  */
+-static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
+-				      __be32 daddr, __be16 dport,
+-				      int dif, struct hlist_head udptable[])
++static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
++		__be16 sport, __be32 daddr, __be16 dport,
++		int dif, struct hlist_head udptable[])
+ {
+ 	struct sock *sk, *result = NULL;
+ 	struct hlist_node *node;
+@@ -258,7 +276,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
+ 	sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
+ 		struct inet_sock *inet = inet_sk(sk);
+ 
+-		if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
++		if (sk->sk_net == net && sk->sk_hash == hnum &&
++				!ipv6_only_sock(sk)) {
+ 			int score = (sk->sk_family == PF_INET ? 1 : 0);
+ 			if (inet->rcv_saddr) {
+ 				if (inet->rcv_saddr != daddr)
+@@ -345,8 +364,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[])
+ 	int harderr;
+ 	int err;
+ 
+-	sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source,
+-			       skb->dev->ifindex, udptable		    );
++	sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest,
++			iph->saddr, uh->source, skb->dev->ifindex, udptable);
+ 	if (sk == NULL) {
+ 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+ 		return;	/* No socket for error */
+@@ -402,7 +421,7 @@ out:
  
  void udp_err(struct sk_buff *skb, u32 info)
  {
@@ -877869,7 +938369,7 @@
  }
  
  /*
-@@ -471,6 +487,7 @@ static int udp_push_pending_frames(struct sock *sk)
+@@ -471,6 +490,7 @@ static int udp_push_pending_frames(struct sock *sk)
  	struct sk_buff *skb;
  	struct udphdr *uh;
  	int err = 0;
@@ -877877,7 +938377,7 @@
  	__wsum csum = 0;
  
  	/* Grab the skbuff where UDP header space exists. */
-@@ -486,7 +503,7 @@ static int udp_push_pending_frames(struct sock *sk)
+@@ -486,7 +506,7 @@ static int udp_push_pending_frames(struct sock *sk)
  	uh->len = htons(up->len);
  	uh->check = 0;
  
@@ -877886,7 +938386,7 @@
  		csum  = udplite_csum_outgoing(sk, skb);
  
  	else if (sk->sk_no_check == UDP_CSUM_NOXMIT) {   /* UDP csum disabled */
-@@ -514,7 +531,7 @@ out:
+@@ -514,7 +534,7 @@ out:
  	up->len = 0;
  	up->pending = 0;
  	if (!err)
@@ -877895,7 +938395,7 @@
  	return err;
  }
  
-@@ -531,7 +548,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -531,7 +551,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  	__be32 daddr, faddr, saddr;
  	__be16 dport;
  	u8  tos;
@@ -877904,7 +938404,7 @@
  	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
  	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
  
-@@ -621,7 +638,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -621,7 +641,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  		connected = 0;
  	}
  
@@ -877913,7 +938413,7 @@
  		if (!ipc.oif)
  			ipc.oif = inet->mc_index;
  		if (!saddr)
-@@ -643,7 +660,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -643,7 +663,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  					       { .sport = inet->sport,
  						 .dport = dport } } };
  		security_sk_classify_flow(sk, &fl);
@@ -877922,7 +938422,7 @@
  		if (err) {
  			if (err == -ENETUNREACH)
  				IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
-@@ -825,6 +842,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -825,6 +845,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
  	struct sk_buff *skb;
  	unsigned int ulen, copied;
@@ -877930,7 +938430,7 @@
  	int err;
  	int is_udplite = IS_UDPLITE(sk);
  
-@@ -838,7 +856,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+@@ -838,7 +859,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  		return ip_recv_error(sk, msg, len);
  
  try_again:
@@ -877940,7 +938440,7 @@
  	if (!skb)
  		goto out;
  
-@@ -873,6 +892,9 @@ try_again:
+@@ -873,6 +895,9 @@ try_again:
  	if (err)
  		goto out_free;
  
@@ -877950,7 +938450,7 @@
  	sock_recv_timestamp(msg, sk, skb);
  
  	/* Copy the address. */
-@@ -891,14 +913,17 @@ try_again:
+@@ -891,14 +916,17 @@ try_again:
  		err = ulen;
  
  out_free:
@@ -877971,7 +938471,7 @@
  
  	if (noblock)
  		return -EAGAIN;
-@@ -940,6 +965,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -940,6 +968,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  {
  	struct udp_sock *up = udp_sk(sk);
  	int rc;
@@ -877979,7 +938479,7 @@
  
  	/*
  	 *	Charge it to the socket, dropping if the queue is full.
-@@ -967,7 +993,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -967,7 +996,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  
  			ret = (*up->encap_rcv)(sk, skb);
  			if (ret <= 0) {
@@ -877989,7 +938489,7 @@
  				return -ret;
  			}
  		}
-@@ -978,7 +1005,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -978,7 +1008,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  	/*
  	 * 	UDP-Lite specific tests, ignored on UDP sockets
  	 */
@@ -877998,7 +938498,7 @@
  
  		/*
  		 * MIB statistics other than incrementing the error count are
-@@ -1019,15 +1046,14 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -1019,15 +1049,14 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
  		/* Note that an ENOMEM error is charged twice */
  		if (rc == -ENOMEM)
@@ -878016,7 +938516,7 @@
  	kfree_skb(skb);
  	return -1;
  }
-@@ -1062,7 +1088,15 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
+@@ -1062,7 +1091,15 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
  				skb1 = skb_clone(skb, GFP_ATOMIC);
  
  			if (skb1) {
@@ -878033,8 +938533,14 @@
  				if (ret > 0)
  					/* we should probably re-process instead
  					 * of dropping packets here. */
-@@ -1155,7 +1189,13 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
- 			       inet_iif(skb), udptable);
+@@ -1151,11 +1188,17 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
+ 	if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
+ 		return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
+ 
+-	sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
+-			       inet_iif(skb), udptable);
++	sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr,
++			uh->dest, inet_iif(skb), udptable);
  
  	if (sk != NULL) {
 -		int ret = udp_queue_rcv_skb(sk, skb);
@@ -878048,7 +938554,7 @@
  		sock_put(sk);
  
  		/* a return value > 0 means to resubmit the input, but
-@@ -1236,6 +1276,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+@@ -1236,6 +1279,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
  	struct udp_sock *up = udp_sk(sk);
  	int val;
  	int err = 0;
@@ -878056,7 +938562,7 @@
  
  	if (optlen<sizeof(int))
  		return -EINVAL;
-@@ -1277,7 +1318,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+@@ -1277,7 +1321,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
  	/* The sender sets actual checksum coverage length via this option.
  	 * The case coverage > packet length is handled by send module. */
  	case UDPLITE_SEND_CSCOV:
@@ -878065,7 +938571,7 @@
  			return -ENOPROTOOPT;
  		if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
  			val = 8;
-@@ -1289,7 +1330,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+@@ -1289,7 +1333,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
  	 * sense, this should be set to at least 8 (as done below). If zero is
  	 * used, this again means full checksum coverage.                     */
  	case UDPLITE_RECV_CSCOV:
@@ -878074,7 +938580,7 @@
  			return -ENOPROTOOPT;
  		if (val != 0 && val < 8) /* Avoid silly minimal values.       */
  			val = 8;
-@@ -1449,6 +1490,10 @@ struct proto udp_prot = {
+@@ -1449,6 +1493,10 @@ struct proto udp_prot = {
  	.hash		   = udp_lib_hash,
  	.unhash		   = udp_lib_unhash,
  	.get_port	   = udp_v4_get_port,
@@ -878085,7 +938591,7 @@
  	.obj_size	   = sizeof(struct udp_sock),
  #ifdef CONFIG_COMPAT
  	.compat_setsockopt = compat_udp_setsockopt,
-@@ -1505,6 +1550,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
+@@ -1505,6 +1553,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
  }
  
  static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
@@ -878093,7 +938599,7 @@
  {
  	read_lock(&udp_hash_lock);
  	return *pos ? udp_get_idx(seq, *pos-1) : (void *)1;
-@@ -1524,6 +1570,7 @@ static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1524,6 +1573,7 @@ static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void udp_seq_stop(struct seq_file *seq, void *v)
@@ -878101,7 +938607,7 @@
  {
  	read_unlock(&udp_hash_lock);
  }
-@@ -1644,6 +1691,25 @@ void udp4_proc_exit(void)
+@@ -1644,6 +1694,25 @@ void udp4_proc_exit(void)
  }
  #endif /* CONFIG_PROC_FS */
  
@@ -878748,7 +939254,7 @@
  			    !(IPCB(skb)->flags & IPSKB_REROUTED));
  }
 diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
-index cc86fb1..3783e3e 100644
+index cc86fb1..10ed704 100644
 --- a/net/ipv4/xfrm4_policy.c
 +++ b/net/ipv4/xfrm4_policy.c
 @@ -8,36 +8,54 @@
@@ -879031,15 +939537,18 @@
  		BUG_ON(!loopback_idev);
  
  		do {
-@@ -318,6 +244,7 @@ static struct dst_ops xfrm4_dst_ops = {
+@@ -318,8 +244,10 @@ static struct dst_ops xfrm4_dst_ops = {
  	.update_pmtu =		xfrm4_update_pmtu,
  	.destroy =		xfrm4_dst_destroy,
  	.ifdown =		xfrm4_dst_ifdown,
 +	.local_out =		__ip_local_out,
  	.gc_thresh =		1024,
  	.entry_size =		sizeof(struct xfrm_dst),
++	.entries =		ATOMIC_INIT(0),
  };
-@@ -328,8 +255,10 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
+ 
+ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
+@@ -328,8 +256,10 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
  	.dst_lookup =		xfrm4_dst_lookup,
  	.get_saddr =		xfrm4_get_saddr,
  	.find_bundle = 		__xfrm4_find_bundle,
@@ -879095,6 +939604,40 @@
  };
  
  void __init xfrm4_state_init(void)
+diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
+index 3268451..41f5982 100644
+--- a/net/ipv4/xfrm4_tunnel.c
++++ b/net/ipv4/xfrm4_tunnel.c
+@@ -38,7 +38,7 @@ static void ipip_destroy(struct xfrm_state *x)
+ {
+ }
+ 
+-static struct xfrm_type ipip_type = {
++static const struct xfrm_type ipip_type = {
+ 	.description	= "IPIP",
+ 	.owner		= THIS_MODULE,
+ 	.proto	     	= IPPROTO_IPIP,
+@@ -50,7 +50,7 @@ static struct xfrm_type ipip_type = {
+ 
+ static int xfrm_tunnel_rcv(struct sk_buff *skb)
+ {
+-	return xfrm4_rcv_spi(skb, IPPROTO_IP, ip_hdr(skb)->saddr);
++	return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr);
+ }
+ 
+ static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
+diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
+index eb0b808..3ffb032 100644
+--- a/net/ipv6/Kconfig
++++ b/net/ipv6/Kconfig
+@@ -85,6 +85,7 @@ config INET6_ESP
+ 	depends on IPV6
+ 	select XFRM
+ 	select CRYPTO
++	select CRYPTO_AEAD
+ 	select CRYPTO_HMAC
+ 	select CRYPTO_MD5
+ 	select CRYPTO_CBC
 diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
 index 87c23a7..24f3aa0 100644
 --- a/net/ipv6/Makefile
@@ -881139,7 +941682,7 @@
  	proto_unregister(&rawv6_prot);
  	proto_unregister(&udplitev6_prot);
 diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
-index 4eaf550..fb0d07a 100644
+index 4eaf550..379c8e0 100644
 --- a/net/ipv6/ah6.c
 +++ b/net/ipv6/ah6.c
 @@ -370,6 +370,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
@@ -881173,6 +941716,15 @@
  
  	skb->network_header += ah_hlen;
  	memcpy(skb_network_header(skb), tmp_hdr, hdr_len);
+@@ -513,7 +515,7 @@ static void ah6_destroy(struct xfrm_state *x)
+ 	kfree(ahp);
+ }
+ 
+-static struct xfrm_type ah6_type =
++static const struct xfrm_type ah6_type =
+ {
+ 	.description	= "AH6",
+ 	.owner		= THIS_MODULE,
 diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
 index f915c4d..9c7f83f 100644
 --- a/net/ipv6/anycast.c
@@ -881226,90 +941778,674 @@
  					dev_put(dev);
  				err = -EINVAL;
 diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
-index 4440532..5bd5292 100644
+index 4440532..8e0f142 100644
 --- a/net/ipv6/esp6.c
 +++ b/net/ipv6/esp6.c
-@@ -165,31 +165,32 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
- 		goto out;
- 	}
+@@ -24,33 +24,124 @@
+  * 	This file is derived from net/ipv4/esp.c
+  */
  
-+	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
-+		ret = -EINVAL;
-+		goto out;
++#include <crypto/aead.h>
++#include <crypto/authenc.h>
+ #include <linux/err.h>
+ #include <linux/module.h>
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+ #include <net/esp.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+ #include <linux/kernel.h>
+ #include <linux/pfkeyv2.h>
+ #include <linux/random.h>
++#include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <net/icmp.h>
+ #include <net/ipv6.h>
+ #include <net/protocol.h>
+ #include <linux/icmpv6.h>
+ 
++struct esp_skb_cb {
++	struct xfrm_skb_cb xfrm;
++	void *tmp;
++};
++
++#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
++
++/*
++ * Allocate an AEAD request structure with extra space for SG and IV.
++ *
++ * For alignment considerations the IV is placed at the front, followed
++ * by the request and finally the SG list.
++ *
++ * TODO: Use spare space in skb for this where possible.
++ */
++static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
++{
++	unsigned int len;
++
++	len = crypto_aead_ivsize(aead);
++	if (len) {
++		len += crypto_aead_alignmask(aead) &
++		       ~(crypto_tfm_ctx_alignment() - 1);
++		len = ALIGN(len, crypto_tfm_ctx_alignment());
 +	}
 +
-+	skb->ip_summed = CHECKSUM_NONE;
++	len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
++	len = ALIGN(len, __alignof__(struct scatterlist));
 +
-+	spin_lock(&x->lock);
++	len += sizeof(struct scatterlist) * nfrags;
++
++	return kmalloc(len, GFP_ATOMIC);
++}
++
++static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
++{
++	return crypto_aead_ivsize(aead) ?
++	       PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
++}
++
++static inline struct aead_givcrypt_request *esp_tmp_givreq(
++	struct crypto_aead *aead, u8 *iv)
++{
++	struct aead_givcrypt_request *req;
++
++	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
++				crypto_tfm_ctx_alignment());
++	aead_givcrypt_set_tfm(req, aead);
++	return req;
++}
++
++static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
++{
++	struct aead_request *req;
++
++	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
++				crypto_tfm_ctx_alignment());
++	aead_request_set_tfm(req, aead);
++	return req;
++}
++
++static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
++					     struct aead_request *req)
++{
++	return (void *)ALIGN((unsigned long)(req + 1) +
++			     crypto_aead_reqsize(aead),
++			     __alignof__(struct scatterlist));
++}
++
++static inline struct scatterlist *esp_givreq_sg(
++	struct crypto_aead *aead, struct aead_givcrypt_request *req)
++{
++	return (void *)ALIGN((unsigned long)(req + 1) +
++			     crypto_aead_reqsize(aead),
++			     __alignof__(struct scatterlist));
++}
++
++static void esp_output_done(struct crypto_async_request *base, int err)
++{
++	struct sk_buff *skb = base->data;
 +
- 	/* If integrity check is required, do this. */
- 	if (esp->auth.icv_full_len) {
- 		u8 sum[alen];
++	kfree(ESP_SKB_CB(skb)->tmp);
++	xfrm_output_resume(skb, err);
++}
++
+ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
+ {
+ 	int err;
+ 	struct ip_esp_hdr *esph;
+-	struct crypto_blkcipher *tfm;
+-	struct blkcipher_desc desc;
++	struct crypto_aead *aead;
++	struct aead_givcrypt_request *req;
++	struct scatterlist *sg;
++	struct scatterlist *asg;
+ 	struct sk_buff *trailer;
++	void *tmp;
+ 	int blksize;
+ 	int clen;
+ 	int alen;
+ 	int nfrags;
++	u8 *iv;
+ 	u8 *tail;
+ 	struct esp_data *esp = x->data;
  
- 		ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
- 		if (ret)
--			goto out;
-+			goto unlock;
+@@ -60,18 +151,26 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
+ 	/* Round to block size */
+ 	clen = skb->len;
+ 
+-	alen = esp->auth.icv_trunc_len;
+-	tfm = esp->conf.tfm;
+-	desc.tfm = tfm;
+-	desc.flags = 0;
+-	blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
++	aead = esp->aead;
++	alen = crypto_aead_authsize(aead);
++
++	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
+ 	clen = ALIGN(clen + 2, blksize);
+-	if (esp->conf.padlen)
+-		clen = ALIGN(clen, esp->conf.padlen);
++	if (esp->padlen)
++		clen = ALIGN(clen, esp->padlen);
  
- 		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
- 			BUG();
+-	if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) {
++	if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
+ 		goto error;
+-	}
++	nfrags = err;
++
++	tmp = esp_alloc_tmp(aead, nfrags + 1);
++	if (!tmp)
++		goto error;
++
++	iv = esp_tmp_iv(aead, tmp);
++	req = esp_tmp_givreq(aead, iv);
++	asg = esp_givreq_sg(aead, req);
++	sg = asg + 1;
+ 
+ 	/* Fill padding... */
+ 	tail = skb_tail_pointer(trailer);
+@@ -81,167 +180,154 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
+ 			tail[i] = i + 1;
+ 	} while (0);
+ 	tail[clen-skb->len - 2] = (clen - skb->len) - 2;
+-	pskb_put(skb, trailer, clen - skb->len);
++	tail[clen - skb->len - 1] = *skb_mac_header(skb);
++	pskb_put(skb, trailer, clen - skb->len + alen);
+ 
+ 	skb_push(skb, -skb_network_offset(skb));
+ 	esph = ip_esp_hdr(skb);
+-	*(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
+ 	*skb_mac_header(skb) = IPPROTO_ESP;
+ 
+ 	esph->spi = x->id.spi;
+ 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
+ 
+-	spin_lock_bh(&x->lock);
++	sg_init_table(sg, nfrags);
++	skb_to_sgvec(skb, sg,
++		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
++		     clen + alen);
++	sg_init_one(asg, esph, sizeof(*esph));
+ 
+-	if (esp->conf.ivlen) {
+-		if (unlikely(!esp->conf.ivinitted)) {
+-			get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
+-			esp->conf.ivinitted = 1;
+-		}
+-		crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+-	}
++	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
++	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
++	aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
++	aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
+ 
+-	do {
+-		struct scatterlist *sg = &esp->sgbuf[0];
++	ESP_SKB_CB(skb)->tmp = tmp;
++	err = crypto_aead_givencrypt(req);
++	if (err == -EINPROGRESS)
++		goto error;
+ 
+-		if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
+-			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+-			if (!sg)
+-				goto unlock;
+-		}
+-		sg_init_table(sg, nfrags);
+-		skb_to_sgvec(skb, sg,
+-			     esph->enc_data +
+-			     esp->conf.ivlen -
+-			     skb->data, clen);
+-		err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
+-		if (unlikely(sg != &esp->sgbuf[0]))
+-			kfree(sg);
+-	} while (0);
++	if (err == -EBUSY)
++		err = NET_XMIT_DROP;
++
++	kfree(tmp);
++
++error:
++	return err;
++}
++
++static int esp_input_done2(struct sk_buff *skb, int err)
++{
++	struct xfrm_state *x = xfrm_input_state(skb);
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead = esp->aead;
++	int alen = crypto_aead_authsize(aead);
++	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
++	int elen = skb->len - hlen;
++	int hdr_len = skb_network_header_len(skb);
++	int padlen;
++	u8 nexthdr[2];
++
++	kfree(ESP_SKB_CB(skb)->tmp);
+ 
+ 	if (unlikely(err))
+-		goto unlock;
++		goto out;
+ 
+-	if (esp->conf.ivlen) {
+-		memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
+-		crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
+-	}
++	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
++		BUG();
+ 
+-	if (esp->auth.icv_full_len) {
+-		err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
+-				     sizeof(*esph) + esp->conf.ivlen + clen);
+-		memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
++	err = -EINVAL;
++	padlen = nexthdr[0];
++	if (padlen + 2 + alen >= elen) {
++		LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
++			       "padlen=%d, elen=%d\n", padlen + 2, elen - alen);
++		goto out;
+ 	}
+ 
+-unlock:
+-	spin_unlock_bh(&x->lock);
++	/* ... check padding bits here. Silly. :-) */
+ 
+-error:
++	pskb_trim(skb, skb->len - alen - padlen - 2);
++	__skb_pull(skb, hlen);
++	skb_set_transport_header(skb, -hdr_len);
++
++	err = nexthdr[1];
++
++	/* RFC4303: Drop dummy packets without any error */
++	if (err == IPPROTO_NONE)
++		err = -EINVAL;
++
++out:
+ 	return err;
+ }
+ 
++static void esp_input_done(struct crypto_async_request *base, int err)
++{
++	struct sk_buff *skb = base->data;
++
++	xfrm_input_resume(skb, esp_input_done2(skb, err));
++}
++
+ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
+ {
+-	struct ipv6hdr *iph;
+ 	struct ip_esp_hdr *esph;
+ 	struct esp_data *esp = x->data;
+-	struct crypto_blkcipher *tfm = esp->conf.tfm;
+-	struct blkcipher_desc desc = { .tfm = tfm };
++	struct crypto_aead *aead = esp->aead;
++	struct aead_request *req;
+ 	struct sk_buff *trailer;
+-	int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+-	int alen = esp->auth.icv_trunc_len;
+-	int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
+-	int hdr_len = skb_network_header_len(skb);
++	int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
+ 	int nfrags;
+ 	int ret = 0;
++	void *tmp;
++	u8 *iv;
++	struct scatterlist *sg;
++	struct scatterlist *asg;
+ 
+ 	if (!pskb_may_pull(skb, sizeof(*esph))) {
+ 		ret = -EINVAL;
+ 		goto out;
+ 	}
+ 
+-	if (elen <= 0 || (elen & (blksize-1))) {
++	if (elen <= 0) {
+ 		ret = -EINVAL;
+ 		goto out;
+ 	}
  
- 		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
+-	/* If integrity check is required, do this. */
+-	if (esp->auth.icv_full_len) {
+-		u8 sum[alen];
+-
+-		ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
+-		if (ret)
+-			goto out;
+-
+-		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
+-			BUG();
+-
+-		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
 -			x->stats.integrity_failed++;
 -			ret = -EINVAL;
 -			goto out;
-+			ret = -EBADMSG;
-+			goto unlock;
- 		}
- 	}
- 
--	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
--		ret = -EINVAL;
--		goto out;
+-		}
 -	}
 -
--	skb->ip_summed = CHECKSUM_NONE;
--
- 	esph = (struct ip_esp_hdr *)skb->data;
- 	iph = ipv6_hdr(skb);
+ 	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
+ 		ret = -EINVAL;
+ 		goto out;
+ 	}
+ 
++	ret = -ENOMEM;
++	tmp = esp_alloc_tmp(aead, nfrags + 1);
++	if (!tmp)
++		goto out;
++
++	ESP_SKB_CB(skb)->tmp = tmp;
++	iv = esp_tmp_iv(aead, tmp);
++	req = esp_tmp_req(aead, iv);
++	asg = esp_req_sg(aead, req);
++	sg = asg + 1;
++
+ 	skb->ip_summed = CHECKSUM_NONE;
  
-@@ -198,15 +199,13 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
- 		crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
+ 	esph = (struct ip_esp_hdr *)skb->data;
+-	iph = ipv6_hdr(skb);
  
- 	{
+ 	/* Get ivec. This can be wrong, check against another impls. */
+-	if (esp->conf.ivlen)
+-		crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
+-
+-	{
 -		u8 nexthdr[2];
- 		struct scatterlist *sg = &esp->sgbuf[0];
+-		struct scatterlist *sg = &esp->sgbuf[0];
 -		u8 padlen;
- 
- 		if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
- 			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
- 			if (!sg) {
- 				ret = -ENOMEM;
+-
+-		if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
+-			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+-			if (!sg) {
+-				ret = -ENOMEM;
 -				goto out;
-+				goto unlock;
- 			}
- 		}
- 		sg_init_table(sg, nfrags);
-@@ -216,8 +215,17 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
- 		ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
- 		if (unlikely(sg != &esp->sgbuf[0]))
- 			kfree(sg);
+-			}
+-		}
+-		sg_init_table(sg, nfrags);
+-		skb_to_sgvec(skb, sg,
+-			     sizeof(*esph) + esp->conf.ivlen,
+-			     elen);
+-		ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
+-		if (unlikely(sg != &esp->sgbuf[0]))
+-			kfree(sg);
 -		if (unlikely(ret))
 -			goto out;
-+	}
-+
-+unlock:
-+	spin_unlock(&x->lock);
+-
+-		if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
+-			BUG();
+-
+-		padlen = nexthdr[0];
+-		if (padlen+2 >= elen) {
+-			LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen);
+-			ret = -EINVAL;
+-			goto out;
+-		}
+-		/* ... check padding bits here. Silly. :-) */
++	iv = esph->enc_data;
+ 
+-		/* RFC4303: Drop dummy packets without any error */
+-		if (nexthdr[1] == IPPROTO_NONE) {
+-			ret = -EINVAL;
+-			goto out;
+-		}
++	sg_init_table(sg, nfrags);
++	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
++	sg_init_one(asg, esph, sizeof(*esph));
+ 
+-		pskb_trim(skb, skb->len - alen - padlen - 2);
+-		ret = nexthdr[1];
+-	}
++	aead_request_set_callback(req, 0, esp_input_done, skb);
++	aead_request_set_crypt(req, sg, sg, elen, iv);
++	aead_request_set_assoc(req, asg, sizeof(*esph));
 +
-+	if (unlikely(ret))
++	ret = crypto_aead_decrypt(req);
++	if (ret == -EINPROGRESS)
 +		goto out;
 +
-+	{
-+		u8 nexthdr[2];
-+		u8 padlen;
++	ret = esp_input_done2(skb, ret);
  
- 		if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
- 			BUG();
+-	__skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
+-	skb_set_transport_header(skb, -hdr_len);
+ out:
+ 	return ret;
+ }
+@@ -249,11 +335,11 @@ out:
+ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
+ {
+ 	struct esp_data *esp = x->data;
+-	u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+-	u32 align = max_t(u32, blksize, esp->conf.padlen);
++	u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
++	u32 align = max_t(u32, blksize, esp->padlen);
+ 	u32 rem;
+ 
+-	mtu -= x->props.header_len + esp->auth.icv_trunc_len;
++	mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
+ 	rem = mtu & (align - 1);
+ 	mtu &= ~(align - 1);
+ 
+@@ -292,81 +378,146 @@ static void esp6_destroy(struct xfrm_state *x)
+ 	if (!esp)
+ 		return;
+ 
+-	crypto_free_blkcipher(esp->conf.tfm);
+-	esp->conf.tfm = NULL;
+-	kfree(esp->conf.ivec);
+-	esp->conf.ivec = NULL;
+-	crypto_free_hash(esp->auth.tfm);
+-	esp->auth.tfm = NULL;
+-	kfree(esp->auth.work_icv);
+-	esp->auth.work_icv = NULL;
++	crypto_free_aead(esp->aead);
+ 	kfree(esp);
+ }
+ 
+-static int esp6_init_state(struct xfrm_state *x)
++static int esp_init_aead(struct xfrm_state *x)
+ {
+-	struct esp_data *esp = NULL;
+-	struct crypto_blkcipher *tfm;
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead;
++	int err;
++
++	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
++	err = PTR_ERR(aead);
++	if (IS_ERR(aead))
++		goto error;
++
++	esp->aead = aead;
+ 
++	err = crypto_aead_setkey(aead, x->aead->alg_key,
++				 (x->aead->alg_key_len + 7) / 8);
++	if (err)
++		goto error;
++
++	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
++	if (err)
++		goto error;
++
++error:
++	return err;
++}
++
++static int esp_init_authenc(struct xfrm_state *x)
++{
++	struct esp_data *esp = x->data;
++	struct crypto_aead *aead;
++	struct crypto_authenc_key_param *param;
++	struct rtattr *rta;
++	char *key;
++	char *p;
++	char authenc_name[CRYPTO_MAX_ALG_NAME];
++	unsigned int keylen;
++	int err;
++
++	err = -EINVAL;
+ 	if (x->ealg == NULL)
+ 		goto error;
+ 
+-	if (x->encap)
++	err = -ENAMETOOLONG;
++	if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
++		     x->aalg ? x->aalg->alg_name : "digest_null",
++		     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+ 		goto error;
+ 
+-	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+-	if (esp == NULL)
+-		return -ENOMEM;
++	aead = crypto_alloc_aead(authenc_name, 0, 0);
++	err = PTR_ERR(aead);
++	if (IS_ERR(aead))
++		goto error;
++
++	esp->aead = aead;
++
++	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
++		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
++	err = -ENOMEM;
++	key = kmalloc(keylen, GFP_KERNEL);
++	if (!key)
++		goto error;
++
++	p = key;
++	rta = (void *)p;
++	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
++	rta->rta_len = RTA_LENGTH(sizeof(*param));
++	param = RTA_DATA(rta);
++	p += RTA_SPACE(sizeof(*param));
+ 
+ 	if (x->aalg) {
+ 		struct xfrm_algo_desc *aalg_desc;
+-		struct crypto_hash *hash;
+-
+-		hash = crypto_alloc_hash(x->aalg->alg_name, 0,
+-					 CRYPTO_ALG_ASYNC);
+-		if (IS_ERR(hash))
+-			goto error;
+ 
+-		esp->auth.tfm = hash;
+-		if (crypto_hash_setkey(hash, x->aalg->alg_key,
+-				       (x->aalg->alg_key_len + 7) / 8))
+-			goto error;
++		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
++		p += (x->aalg->alg_key_len + 7) / 8;
+ 
+ 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
+ 		BUG_ON(!aalg_desc);
+ 
++		err = -EINVAL;
+ 		if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
+-		    crypto_hash_digestsize(hash)) {
++		    crypto_aead_authsize(aead)) {
+ 			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
+ 				 x->aalg->alg_name,
+-				 crypto_hash_digestsize(hash),
++				 crypto_aead_authsize(aead),
+ 				 aalg_desc->uinfo.auth.icv_fullbits/8);
+-			goto error;
++			goto free_key;
+ 		}
+ 
+-		esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
+-		esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
+-
+-		esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
+-		if (!esp->auth.work_icv)
+-			goto error;
+-	}
+-	tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
+-	if (IS_ERR(tfm))
+-		goto error;
+-	esp->conf.tfm = tfm;
+-	esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
+-	esp->conf.padlen = 0;
+-	if (esp->conf.ivlen) {
+-		esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
+-		if (unlikely(esp->conf.ivec == NULL))
+-			goto error;
+-		esp->conf.ivinitted = 0;
++		err = crypto_aead_setauthsize(
++			aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
++		if (err)
++			goto free_key;
+ 	}
+-	if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
+-				    (x->ealg->alg_key_len + 7) / 8))
++
++	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
++	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
++
++	err = crypto_aead_setkey(aead, key, keylen);
++
++free_key:
++	kfree(key);
++
++error:
++	return err;
++}
++
++static int esp6_init_state(struct xfrm_state *x)
++{
++	struct esp_data *esp;
++	struct crypto_aead *aead;
++	u32 align;
++	int err;
++
++	if (x->encap)
++		return -EINVAL;
++
++	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
++	if (esp == NULL)
++		return -ENOMEM;
++
++	x->data = esp;
++
++	if (x->aead)
++		err = esp_init_aead(x);
++	else
++		err = esp_init_authenc(x);
++
++	if (err)
+ 		goto error;
+-	x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
++
++	aead = esp->aead;
++
++	esp->padlen = 0;
++
++	x->props.header_len = sizeof(struct ip_esp_hdr) +
++			      crypto_aead_ivsize(aead);
+ 	switch (x->props.mode) {
+ 	case XFRM_MODE_BEET:
+ 	case XFRM_MODE_TRANSPORT:
+@@ -377,17 +528,17 @@ static int esp6_init_state(struct xfrm_state *x)
+ 	default:
+ 		goto error;
+ 	}
+-	x->data = esp;
+-	return 0;
++
++	align = ALIGN(crypto_aead_blocksize(aead), 4);
++	if (esp->padlen)
++		align = max_t(u32, align, esp->padlen);
++	x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
+ 
+ error:
+-	x->data = esp;
+-	esp6_destroy(x);
+-	x->data = NULL;
+-	return -EINVAL;
++	return err;
+ }
+ 
+-static struct xfrm_type esp6_type =
++static const struct xfrm_type esp6_type =
+ {
+ 	.description	= "ESP6",
+ 	.owner	     	= THIS_MODULE,
 diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
 index 1e89efd..3cd1c99 100644
 --- a/net/ipv6/exthdrs.c
@@ -881684,7 +942820,7 @@
  #endif
  
 diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
-index 0765d8b..a66a7d8 100644
+index 0765d8b..d325a99 100644
 --- a/net/ipv6/inet6_hashtables.c
 +++ b/net/ipv6/inet6_hashtables.c
 @@ -43,7 +43,7 @@ void __inet6_hash(struct inet_hashinfo *hashinfo,
@@ -881696,7 +942832,117 @@
  	write_unlock(lock);
  }
  EXPORT_SYMBOL(__inet6_hash);
-@@ -216,7 +216,7 @@ unique:
+@@ -54,7 +54,8 @@ EXPORT_SYMBOL(__inet6_hash);
+  *
+  * The sockhash lock must be held as a reader here.
+  */
+-struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
++struct sock *__inet6_lookup_established(struct net *net,
++					struct inet_hashinfo *hashinfo,
+ 					   const struct in6_addr *saddr,
+ 					   const __be16 sport,
+ 					   const struct in6_addr *daddr,
+@@ -75,22 +76,13 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
+ 	read_lock(lock);
+ 	sk_for_each(sk, node, &head->chain) {
+ 		/* For IPV6 do the cheaper port and family tests first. */
+-		if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif))
++		if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif))
+ 			goto hit; /* You sunk my battleship! */
+ 	}
+ 	/* Must check for a TIME_WAIT'er before going to listener hash. */
+ 	sk_for_each(sk, node, &head->twchain) {
+-		const struct inet_timewait_sock *tw = inet_twsk(sk);
+-
+-		if(*((__portpair *)&(tw->tw_dport))	== ports	&&
+-		   sk->sk_family		== PF_INET6) {
+-			const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
+-
+-			if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)	&&
+-			    ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr)	&&
+-			    (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
+-				goto hit;
+-		}
++		if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif))
++			goto hit;
+ 	}
+ 	read_unlock(lock);
+ 	return NULL;
+@@ -102,9 +94,9 @@ hit:
+ }
+ EXPORT_SYMBOL(__inet6_lookup_established);
+ 
+-struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+-				   const struct in6_addr *daddr,
+-				   const unsigned short hnum, const int dif)
++struct sock *inet6_lookup_listener(struct net *net,
++		struct inet_hashinfo *hashinfo, const struct in6_addr *daddr,
++		const unsigned short hnum, const int dif)
+ {
+ 	struct sock *sk;
+ 	const struct hlist_node *node;
+@@ -113,7 +105,8 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+ 
+ 	read_lock(&hashinfo->lhash_lock);
+ 	sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
+-		if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) {
++		if (sk->sk_net == net && inet_sk(sk)->num == hnum &&
++				sk->sk_family == PF_INET6) {
+ 			const struct ipv6_pinfo *np = inet6_sk(sk);
+ 
+ 			score = 1;
+@@ -145,7 +138,7 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+ 
+ EXPORT_SYMBOL_GPL(inet6_lookup_listener);
+ 
+-struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
++struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
+ 			  const struct in6_addr *saddr, const __be16 sport,
+ 			  const struct in6_addr *daddr, const __be16 dport,
+ 			  const int dif)
+@@ -153,7 +146,7 @@ struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
+ 	struct sock *sk;
+ 
+ 	local_bh_disable();
+-	sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
++	sk = __inet6_lookup(net, hashinfo, saddr, sport, daddr, ntohs(dport), dif);
+ 	local_bh_enable();
+ 
+ 	return sk;
+@@ -179,21 +172,16 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
+ 	struct sock *sk2;
+ 	const struct hlist_node *node;
+ 	struct inet_timewait_sock *tw;
++	struct net *net = sk->sk_net;
+ 
+ 	prefetch(head->chain.first);
+ 	write_lock(lock);
+ 
+ 	/* Check TIME-WAIT sockets first. */
+ 	sk_for_each(sk2, node, &head->twchain) {
+-		const struct inet6_timewait_sock *tw6 = inet6_twsk(sk2);
+-
+ 		tw = inet_twsk(sk2);
+ 
+-		if(*((__portpair *)&(tw->tw_dport)) == ports		 &&
+-		   sk2->sk_family	       == PF_INET6	 &&
+-		   ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)	 &&
+-		   ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
+-		   (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) {
++		if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) {
+ 			if (twsk_unique(sk, sk2, twp))
+ 				goto unique;
+ 			else
+@@ -204,7 +192,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
+ 
+ 	/* And established part... */
+ 	sk_for_each(sk2, node, &head->chain) {
+-		if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
++		if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif))
+ 			goto not_unique;
+ 	}
+ 
+@@ -216,7 +204,7 @@ unique:
  	BUG_TRAP(sk_unhashed(sk));
  	__sk_add_node(sk, &head->chain);
  	sk->sk_hash = hash;
@@ -881705,6 +942951,106 @@
  	write_unlock(lock);
  
  	if (twp != NULL) {
+@@ -248,97 +236,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
+ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
+ 		       struct sock *sk)
+ {
+-	struct inet_hashinfo *hinfo = death_row->hashinfo;
+-	const unsigned short snum = inet_sk(sk)->num;
+-	struct inet_bind_hashbucket *head;
+-	struct inet_bind_bucket *tb;
+-	int ret;
+-
+-	if (snum == 0) {
+-		int i, port, low, high, remaining;
+-		static u32 hint;
+-		const u32 offset = hint + inet6_sk_port_offset(sk);
+-		struct hlist_node *node;
+-		struct inet_timewait_sock *tw = NULL;
+-
+-		inet_get_local_port_range(&low, &high);
+-		remaining = (high - low) + 1;
+-
+-		local_bh_disable();
+-		for (i = 1; i <= remaining; i++) {
+-			port = low + (i + offset) % remaining;
+-			head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
+-			spin_lock(&head->lock);
+-
+-			/* Does not bother with rcv_saddr checks,
+-			 * because the established check is already
+-			 * unique enough.
+-			 */
+-			inet_bind_bucket_for_each(tb, node, &head->chain) {
+-				if (tb->port == port) {
+-					BUG_TRAP(!hlist_empty(&tb->owners));
+-					if (tb->fastreuse >= 0)
+-						goto next_port;
+-					if (!__inet6_check_established(death_row,
+-								       sk, port,
+-								       &tw))
+-						goto ok;
+-					goto next_port;
+-				}
+-			}
+-
+-			tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
+-						     head, port);
+-			if (!tb) {
+-				spin_unlock(&head->lock);
+-				break;
+-			}
+-			tb->fastreuse = -1;
+-			goto ok;
+-
+-		next_port:
+-			spin_unlock(&head->lock);
+-		}
+-		local_bh_enable();
+-
+-		return -EADDRNOTAVAIL;
+-
+-ok:
+-		hint += i;
+-
+-		/* Head lock still held and bh's disabled */
+-		inet_bind_hash(sk, tb, port);
+-		if (sk_unhashed(sk)) {
+-			inet_sk(sk)->sport = htons(port);
+-			__inet6_hash(hinfo, sk);
+-		}
+-		spin_unlock(&head->lock);
+-
+-		if (tw) {
+-			inet_twsk_deschedule(tw, death_row);
+-			inet_twsk_put(tw);
+-		}
+-
+-		ret = 0;
+-		goto out;
+-	}
+-
+-	head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
+-	tb   = inet_csk(sk)->icsk_bind_hash;
+-	spin_lock_bh(&head->lock);
+-
+-	if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
+-		__inet6_hash(hinfo, sk);
+-		spin_unlock_bh(&head->lock);
+-		return 0;
+-	} else {
+-		spin_unlock(&head->lock);
+-		/* No definite answer... Walk to established hash table */
+-		ret = __inet6_check_established(death_row, sk, snum, NULL);
+-out:
+-		local_bh_enable();
+-		return ret;
+-	}
++	return __inet_hash_connect(death_row, sk,
++			__inet6_check_established, __inet6_hash);
+ }
+ 
+ EXPORT_SYMBOL_GPL(inet6_hash_connect);
 diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
 index 946cf38..f93407c 100644
 --- a/net/ipv6/ip6_fib.c
@@ -881954,7 +943300,7 @@
  
  int ip6_mc_input(struct sk_buff *skb)
 diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
-index 3bef30e..15c4f6c 100644
+index 3bef30e..9ac6ca2 100644
 --- a/net/ipv6/ip6_output.c
 +++ b/net/ipv6/ip6_output.c
 @@ -29,7 +29,7 @@
@@ -882019,7 +943365,13 @@
  }
  
  static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
-@@ -236,7 +262,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+@@ -231,12 +257,13 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+ 	ipv6_addr_copy(&hdr->daddr, first_hop);
+ 
+ 	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
+ 
+ 	mtu = dst_mtu(dst);
  	if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
  		IP6_INC_STATS(ip6_dst_idev(skb->dst),
  			      IPSTATS_MIB_OUTREQUESTS);
@@ -882028,7 +943380,7 @@
  				dst_output);
  	}
  
-@@ -423,7 +449,7 @@ int ip6_forward(struct sk_buff *skb)
+@@ -423,7 +450,7 @@ int ip6_forward(struct sk_buff *skb)
  
  	/* XXX: idev->cnf.proxy_ndp? */
  	if (ipv6_devconf.proxy_ndp &&
@@ -882037,7 +943389,7 @@
  		int proxied = ip6_forward_proxy_check(skb);
  		if (proxied > 0)
  			return ip6_input(skb);
-@@ -500,7 +526,8 @@ int ip6_forward(struct sk_buff *skb)
+@@ -500,7 +527,8 @@ int ip6_forward(struct sk_buff *skb)
  	hdr->hop_limit--;
  
  	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
@@ -882047,7 +943399,32 @@
  
  error:
  	IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
-@@ -909,7 +936,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
+@@ -609,6 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+ 
+ 	if (skb_shinfo(skb)->frag_list) {
+ 		int first_len = skb_pagelen(skb);
++		int truesizes = 0;
+ 
+ 		if (first_len - hlen > mtu ||
+ 		    ((first_len - hlen) & 7) ||
+@@ -631,7 +660,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+ 				sock_hold(skb->sk);
+ 				frag->sk = skb->sk;
+ 				frag->destructor = sock_wfree;
+-				skb->truesize -= frag->truesize;
++				truesizes += frag->truesize;
+ 			}
+ 		}
+ 
+@@ -662,6 +691,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
+ 
+ 		first_len = skb_pagelen(skb);
+ 		skb->data_len = first_len - skb_headlen(skb);
++		skb->truesize -= truesizes;
+ 		skb->len = first_len;
+ 		ipv6_hdr(skb)->payload_len = htons(first_len -
+ 						   sizeof(struct ipv6hdr));
+@@ -909,7 +939,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
  			struct flowi fl_gw;
  			int redirect;
  
@@ -882057,7 +943434,7 @@
  
  			redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
  			if (ifp)
-@@ -1098,7 +1126,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+@@ -1098,7 +1129,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
  		inet->cork.length = 0;
  		sk->sk_sndmsg_page = NULL;
  		sk->sk_sndmsg_off = 0;
@@ -882067,7 +943444,7 @@
  		length += exthdrlen;
  		transhdrlen += exthdrlen;
  	} else {
-@@ -1113,7 +1142,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
+@@ -1113,7 +1145,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
  
  	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
  
@@ -882077,7 +943454,7 @@
  	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
  
  	if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
-@@ -1401,10 +1431,6 @@ int ip6_push_pending_frames(struct sock *sk)
+@@ -1401,16 +1434,13 @@ int ip6_push_pending_frames(struct sock *sk)
  	*(__be32*)hdr = fl->fl6_flowlabel |
  		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
  
@@ -882088,7 +943465,14 @@
  	hdr->hop_limit = np->cork.hop_limit;
  	hdr->nexthdr = proto;
  	ipv6_addr_copy(&hdr->saddr, &fl->fl6_src);
-@@ -1421,7 +1447,7 @@ int ip6_push_pending_frames(struct sock *sk)
+ 	ipv6_addr_copy(&hdr->daddr, final_dst);
+ 
+ 	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
+ 
+ 	skb->dst = dst_clone(&rt->u.dst);
+ 	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
+@@ -1421,7 +1451,7 @@ int ip6_push_pending_frames(struct sock *sk)
  		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
  	}
  
@@ -882172,10 +943556,36 @@
  	if (net_xmit_eval(err) == 0) {
  		stats->tx_bytes += pkt_len;
 diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
-index 0cd4056..b276d04 100644
+index 0cd4056..b900395 100644
 --- a/net/ipv6/ipcomp6.c
 +++ b/net/ipv6/ipcomp6.c
-@@ -190,7 +190,6 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+@@ -64,6 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
+ 
+ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
+ {
++	int nexthdr;
+ 	int err = -ENOMEM;
+ 	struct ip_comp_hdr *ipch;
+ 	int plen, dlen;
+@@ -79,6 +80,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
+ 
+ 	/* Remove ipcomp header and decompress original payload */
+ 	ipch = (void *)skb->data;
++	nexthdr = ipch->nexthdr;
++
+ 	skb->transport_header = skb->network_header + sizeof(*ipch);
+ 	__skb_pull(skb, sizeof(*ipch));
+ 
+@@ -108,7 +111,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
+ 	skb->truesize += dlen - plen;
+ 	__skb_put(skb, dlen - plen);
+ 	skb_copy_to_linear_data(skb, scratch, dlen);
+-	err = ipch->nexthdr;
++	err = nexthdr;
+ 
+ out_put_cpu:
+ 	put_cpu();
+@@ -190,7 +193,6 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
  static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
  {
  	struct xfrm_state *t = NULL;
@@ -882183,7 +943593,7 @@
  
  	t = xfrm_state_alloc();
  	if (!t)
-@@ -204,9 +203,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
+@@ -204,9 +206,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
  	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;
@@ -882194,7 +943604,7 @@
  	memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
  
  	if (xfrm_init_state(t))
-@@ -405,22 +402,22 @@ static int ipcomp6_init_state(struct xfrm_state *x)
+@@ -405,22 +405,22 @@ static int ipcomp6_init_state(struct xfrm_state *x)
  	if (x->encap)
  		goto out;
  
@@ -882224,6 +943634,15 @@
  	mutex_lock(&ipcomp6_resource_mutex);
  	if (!ipcomp6_alloc_scratches())
  		goto error;
+@@ -453,7 +453,7 @@ error:
+ 	goto out;
+ }
+ 
+-static struct xfrm_type ipcomp6_type =
++static const struct xfrm_type ipcomp6_type =
+ {
+ 	.description	= "IPCOMP6",
+ 	.owner		= THIS_MODULE,
 diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
 index 8c5f80f..bf2a686 100644
 --- a/net/ipv6/ipv6_sockglue.c
@@ -882356,7 +943775,7 @@
  	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
  	if (likely(state->im != NULL)) {
 diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
-index 7fd841d..49d3966 100644
+index 7fd841d..cd8a5bd 100644
 --- a/net/ipv6/mip6.c
 +++ b/net/ipv6/mip6.c
 @@ -34,11 +34,6 @@
@@ -882389,7 +943808,13 @@
  }
  
  /* Destination Option Header is inserted.
-@@ -337,25 +335,27 @@ static struct xfrm_type mip6_destopt_type =
+@@ -332,30 +330,32 @@ static void mip6_destopt_destroy(struct xfrm_state *x)
+ {
+ }
+ 
+-static struct xfrm_type mip6_destopt_type =
++static const struct xfrm_type mip6_destopt_type =
+ {
  	.description	= "MIP6DESTOPT",
  	.owner		= THIS_MODULE,
  	.proto	     	= IPPROTO_DSTOPTS,
@@ -882421,7 +943846,13 @@
  }
  
  /* Routing Header type 2 is inserted.
-@@ -467,13 +467,12 @@ static struct xfrm_type mip6_rthdr_type =
+@@ -462,18 +462,17 @@ static void mip6_rthdr_destroy(struct xfrm_state *x)
+ {
+ }
+ 
+-static struct xfrm_type mip6_rthdr_type =
++static const struct xfrm_type mip6_rthdr_type =
+ {
  	.description	= "MIP6RT",
  	.owner		= THIS_MODULE,
  	.proto	     	= IPPROTO_ROUTING,
@@ -882863,7 +944294,7 @@
  
  # targets
 diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
-index e273605..56b4ea6 100644
+index e273605..e869916 100644
 --- a/net/ipv6/netfilter/ip6_queue.c
 +++ b/net/ipv6/netfilter/ip6_queue.c
 @@ -29,6 +29,7 @@
@@ -883185,9 +944616,19 @@
  }
  
  #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
-@@ -577,26 +529,6 @@ static ctl_table ipq_table[] = {
+@@ -563,6 +515,7 @@ static struct notifier_block ipq_nl_notifier = {
+ 	.notifier_call	= ipq_rcv_nl_event,
+ };
+ 
++#ifdef CONFIG_SYSCTL
+ static struct ctl_table_header *ipq_sysctl_header;
+ 
+ static ctl_table ipq_table[] = {
+@@ -576,27 +529,9 @@ static ctl_table ipq_table[] = {
+ 	},
  	{ .ctl_name = 0 }
  };
++#endif
  
 -static ctl_table ipq_dir_table[] = {
 -	{
@@ -883209,44 +944650,80 @@
 -	{ .ctl_name = 0 }
 -};
 -
++#ifdef CONFIG_PROC_FS
  static int ip6_queue_show(struct seq_file *m, void *v)
  {
  	read_lock_bh(&queue_lock);
-@@ -634,7 +566,7 @@ static const struct file_operations ip6_queue_proc_fops = {
+@@ -633,8 +568,9 @@ static const struct file_operations ip6_queue_proc_fops = {
+ 	.release	= single_release,
  	.owner		= THIS_MODULE,
  };
++#endif
  
 -static struct nf_queue_handler nfqh = {
 +static const struct nf_queue_handler nfqh = {
  	.name	= "ip6_queue",
  	.outfn	= &ipq_enqueue_packet,
  };
-@@ -662,7 +594,7 @@ static int __init ip6_queue_init(void)
+@@ -642,7 +578,7 @@ static struct nf_queue_handler nfqh = {
+ static int __init ip6_queue_init(void)
+ {
+ 	int status = -ENOMEM;
+-	struct proc_dir_entry *proc;
++	struct proc_dir_entry *proc __maybe_unused;
+ 
+ 	netlink_register_notifier(&ipq_nl_notifier);
+ 	ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0,
+@@ -652,6 +588,7 @@ static int __init ip6_queue_init(void)
+ 		goto cleanup_netlink_notifier;
  	}
  
++#ifdef CONFIG_PROC_FS
+ 	proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net);
+ 	if (proc) {
+ 		proc->owner = THIS_MODULE;
+@@ -660,10 +597,11 @@ static int __init ip6_queue_init(void)
+ 		printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
+ 		goto cleanup_ipqnl;
+ 	}
+-
++#endif
  	register_netdevice_notifier(&ipq_dev_notifier);
 -	ipq_sysctl_header = register_sysctl_table(ipq_root_table);
+-
++#ifdef CONFIG_SYSCTL
 +	ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table);
- 
++#endif
  	status = nf_register_queue_handler(PF_INET6, &nfqh);
  	if (status < 0) {
-@@ -677,7 +609,7 @@ cleanup_sysctl:
+ 		printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
+@@ -672,12 +610,14 @@ static int __init ip6_queue_init(void)
+ 	return status;
+ 
+ cleanup_sysctl:
++#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(ipq_sysctl_header);
++#endif
+ 	unregister_netdevice_notifier(&ipq_dev_notifier);
  	proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
  
- cleanup_ipqnl:
+-cleanup_ipqnl:
 -	sock_release(ipqnl->sk_socket);
++cleanup_ipqnl: __maybe_unused
 +	netlink_kernel_release(ipqnl);
  	mutex_lock(&ipqnl_mutex);
  	mutex_unlock(&ipqnl_mutex);
  
-@@ -690,13 +622,13 @@ static void __exit ip6_queue_fini(void)
+@@ -690,13 +630,15 @@ static void __exit ip6_queue_fini(void)
  {
  	nf_unregister_queue_handlers(&nfqh);
  	synchronize_net();
 -	ipq_flush(NF_DROP);
 +	ipq_flush(NULL, 0);
  
++#ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(ipq_sysctl_header);
++#endif
  	unregister_netdevice_notifier(&ipq_dev_notifier);
  	proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
  
@@ -883256,7 +944733,7 @@
  	mutex_unlock(&ipqnl_mutex);
  
 diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
-index acaba15..dd7860f 100644
+index acaba15..bf9bb6e 100644
 --- a/net/ipv6/netfilter/ip6_tables.c
 +++ b/net/ipv6/netfilter/ip6_tables.c
 @@ -19,21 +19,21 @@
@@ -883379,6 +944856,15 @@
  static inline int
  get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
  		      char *hookname, char **chainname,
+@@ -322,7 +320,7 @@ static void trace_packet(struct sk_buff *skb,
+ 			 unsigned int hook,
+ 			 const struct net_device *in,
+ 			 const struct net_device *out,
+-			 char *tablename,
++			 const char *tablename,
+ 			 struct xt_table_info *private,
+ 			 struct ip6t_entry *e)
+ {
 @@ -378,8 +376,8 @@ ip6t_do_table(struct sk_buff *skb,
  	 * match it. */
  
@@ -883842,7 +945328,7 @@
 +}
 +#endif
 +
-+static int get_info(void __user *user, int *len, int compat)
++static int get_info(struct net *net, void __user *user, int *len, int compat)
 +{
 +	char name[IP6T_TABLE_MAXNAMELEN];
 +	struct xt_table *t;
@@ -883862,7 +945348,7 @@
 +	if (compat)
 +		xt_compat_lock(AF_INET6);
 +#endif
-+	t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
++	t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
 +				    "ip6table_%s", name);
 +	if (t && !IS_ERR(t)) {
 +		struct ip6t_getinfo info;
@@ -883904,7 +945390,7 @@
  static int
 -get_entries(const struct ip6t_get_entries *entries,
 -	    struct ip6t_get_entries __user *uptr)
-+get_entries(struct ip6t_get_entries __user *uptr, int *len)
++get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
  {
  	int ret;
 +	struct ip6t_get_entries get;
@@ -883923,7 +945409,7 @@
 +		return -EINVAL;
 +	}
 +
-+	t = xt_find_table_lock(AF_INET6, get.name);
++	t = xt_find_table_lock(net, AF_INET6, get.name);
  	if (t && !IS_ERR(t)) {
  		struct xt_table_info *private = t->private;
  		duprintf("t->private->number = %u\n", private->number);
@@ -883943,7 +945429,7 @@
  
  static int
 -do_replace(void __user *user, unsigned int len)
-+__do_replace(const char *name, unsigned int valid_hooks,
++__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 +	     struct xt_table_info *newinfo, unsigned int num_counters,
 +	     void __user *counters_ptr)
  {
@@ -883954,11 +945440,11 @@
 +	struct xt_table_info *oldinfo;
  	struct xt_counters *counters;
 -	void *loc_cpu_entry, *loc_cpu_old_entry;
-+	void *loc_cpu_old_entry;
- 
+-
 -	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 -		return -EFAULT;
--
++	void *loc_cpu_old_entry;
+ 
 -	/* overflow check */
 -	if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
 -			SMP_CACHE_BYTES)
@@ -883998,7 +945484,7 @@
 -
 -	t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
 -				    "ip6table_%s", tmp.name);
-+	t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
++	t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
 +				    "ip6table_%s", name);
  	if (!t || IS_ERR(t)) {
  		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -884047,7 +945533,7 @@
 +}
 +
 +static int
-+do_replace(void __user *user, unsigned int len)
++do_replace(struct net *net, void __user *user, unsigned int len)
 +{
 +	int ret;
 +	struct ip6t_replace tmp;
@@ -884081,7 +945567,7 @@
 +
 +	duprintf("ip_tables: Translated table\n");
 +
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, tmp.counters);
 +	if (ret)
 +		goto free_newinfo_untrans;
@@ -884092,12 +945578,13 @@
   free_newinfo:
  	xt_free_table_info(newinfo);
  	return ret;
-@@ -1151,31 +1358,59 @@ add_counter_to_entry(struct ip6t_entry *e,
+@@ -1151,31 +1358,60 @@ add_counter_to_entry(struct ip6t_entry *e,
  }
  
  static int
 -do_add_counters(void __user *user, unsigned int len)
-+do_add_counters(void __user *user, unsigned int len, int compat)
++do_add_counters(struct net *net, void __user *user, unsigned int len,
++		int compat)
  {
  	unsigned int i;
 -	struct xt_counters_info tmp, *paddc;
@@ -884156,11 +945643,11 @@
  	}
  
 -	t = xt_find_table_lock(AF_INET6, tmp.name);
-+	t = xt_find_table_lock(AF_INET6, name);
++	t = xt_find_table_lock(net, AF_INET6, name);
  	if (!t || IS_ERR(t)) {
  		ret = t ? PTR_ERR(t) : -ENOENT;
  		goto free;
-@@ -1183,18 +1418,18 @@ do_add_counters(void __user *user, unsigned int len)
+@@ -1183,18 +1419,18 @@ do_add_counters(void __user *user, unsigned int len)
  
  	write_lock_bh(&t->lock);
  	private = t->private;
@@ -884182,7 +945669,7 @@
  			  &i);
   unlock_up_free:
  	write_unlock_bh(&t->lock);
-@@ -1206,8 +1441,433 @@ do_add_counters(void __user *user, unsigned int len)
+@@ -1206,8 +1442,435 @@ do_add_counters(void __user *user, unsigned int len)
  	return ret;
  }
  
@@ -884202,7 +945689,7 @@
  static int
 -do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 +compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
-+			  compat_uint_t *size, struct xt_counters *counters,
++			  unsigned int *size, struct xt_counters *counters,
 +			  unsigned int *i)
 +{
 +	struct ip6t_entry_target *t;
@@ -884249,7 +945736,7 @@
 +		       const char *name,
 +		       const struct ip6t_ip6 *ipv6,
 +		       unsigned int hookmask,
-+		       int *size, int *i)
++		       int *size, unsigned int *i)
 +{
 +	struct xt_match *match;
 +
@@ -884307,7 +945794,8 @@
 +	struct ip6t_entry_target *t;
 +	struct xt_target *target;
 +	unsigned int entry_offset;
-+	int ret, off, h, j;
++	unsigned int j;
++	int ret, off, h;
 +
 +	duprintf("check_compat_entry_size_and_hooks %p\n", e);
 +	if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
@@ -884419,7 +945907,8 @@
 +static int compat_check_entry(struct ip6t_entry *e, const char *name,
 +				     unsigned int *i)
 +{
-+	int j, ret;
++	unsigned int j;
++	int ret;
 +
 +	j = 0;
 +	ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6,
@@ -884561,7 +946050,7 @@
 +}
 +
 +static int
-+compat_do_replace(void __user *user, unsigned int len)
++compat_do_replace(struct net *net, void __user *user, unsigned int len)
 +{
 +	int ret;
 +	struct compat_ip6t_replace tmp;
@@ -884598,7 +946087,7 @@
 +
 +	duprintf("compat_do_replace: Translated table\n");
 +
-+	ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
++	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
 +			   tmp.num_counters, compat_ptr(tmp.counters));
 +	if (ret)
 +		goto free_newinfo_untrans;
@@ -884617,21 +946106,21 @@
  {
  	int ret;
  
-@@ -1216,11 +1876,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
+@@ -1216,11 +1879,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
  
  	switch (cmd) {
  	case IP6T_SO_SET_REPLACE:
 -		ret = do_replace(user, len);
-+		ret = compat_do_replace(user, len);
++		ret = compat_do_replace(sk->sk_net, user, len);
  		break;
  
  	case IP6T_SO_SET_ADD_COUNTERS:
 -		ret = do_add_counters(user, len);
-+		ret = do_add_counters(user, len, 1);
++		ret = do_add_counters(sk->sk_net, user, len, 1);
  		break;
  
  	default:
-@@ -1231,75 +1891,155 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
+@@ -1231,75 +1894,156 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
  	return ret;
  }
  
@@ -884674,7 +946163,8 @@
 +}
 +
 +static int
-+compat_get_entries(struct compat_ip6t_get_entries __user *uptr, int *len)
++compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
++		   int *len)
  {
  	int ret;
 +	struct compat_ip6t_get_entries get;
@@ -884704,7 +946194,7 @@
 +	}
 +
 +	xt_compat_lock(AF_INET6);
-+	t = xt_find_table_lock(AF_INET6, get.name);
++	t = xt_find_table_lock(net, AF_INET6, get.name);
 +	if (t && !IS_ERR(t)) {
 +		struct xt_table_info *private = t->private;
 +		struct xt_table_info info;
@@ -884770,10 +946260,10 @@
 +
 +	switch (cmd) {
 +	case IP6T_SO_GET_INFO:
-+		ret = get_info(user, len, 1);
++		ret = get_info(sk->sk_net, user, len, 1);
 +		break;
 +	case IP6T_SO_GET_ENTRIES:
-+		ret = compat_get_entries(user, len);
++		ret = compat_get_entries(sk->sk_net, user, len);
 +		break;
 +	default:
 +		ret = do_ip6t_get_ctl(sk, cmd, user, len);
@@ -884806,12 +946296,12 @@
 +
 +	switch (cmd) {
 +	case IP6T_SO_SET_REPLACE:
-+		ret = do_replace(user, len);
- 		break;
++		ret = do_replace(sk->sk_net, user, len);
++		break;
 +
 +	case IP6T_SO_SET_ADD_COUNTERS:
-+		ret = do_add_counters(user, len, 0);
-+		break;
++		ret = do_add_counters(sk->sk_net, user, len, 0);
+ 		break;
 +
 +	default:
 +		duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
@@ -884831,23 +946321,24 @@
 +
 +	switch (cmd) {
 +	case IP6T_SO_GET_INFO:
-+		ret = get_info(user, len, 0);
++		ret = get_info(sk->sk_net, user, len, 0);
 +		break;
 +
 +	case IP6T_SO_GET_ENTRIES:
-+		ret = get_entries(user, len);
++		ret = get_entries(sk->sk_net, user, len);
 +		break;
 +
  	case IP6T_SO_GET_REVISION_MATCH:
  	case IP6T_SO_GET_REVISION_TARGET: {
  		struct ip6t_get_revision rev;
-@@ -1334,12 +2074,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+@@ -1334,20 +2078,23 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
  	return ret;
  }
  
 -int ip6t_register_table(struct xt_table *table,
 -			const struct ip6t_replace *repl)
-+int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl)
++struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table,
++				     const struct ip6t_replace *repl)
  {
  	int ret;
  	struct xt_table_info *newinfo;
@@ -884855,17 +946346,67 @@
 +	struct xt_table_info bootstrap
  		= { 0, 0, 0, { 0 }, { 0 }, { } };
  	void *loc_cpu_entry;
++	struct xt_table *new_table;
  
-@@ -1347,7 +2086,7 @@ int ip6t_register_table(struct xt_table *table,
- 	if (!newinfo)
- 		return -ENOMEM;
+ 	newinfo = xt_alloc_table_info(repl->size);
+-	if (!newinfo)
+-		return -ENOMEM;
++	if (!newinfo) {
++		ret = -ENOMEM;
++		goto out;
++	}
  
 -	/* choose the copy on our node/cpu */
 +	/* choose the copy on our node/cpu, but dont care about preemption */
  	loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
  	memcpy(loc_cpu_entry, repl->entries, repl->size);
  
-@@ -1403,17 +2142,18 @@ icmp6_match(const struct sk_buff *skb,
+@@ -1356,30 +2103,35 @@ int ip6t_register_table(struct xt_table *table,
+ 			      repl->num_entries,
+ 			      repl->hook_entry,
+ 			      repl->underflow);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
+-	}
++	if (ret != 0)
++		goto out_free;
+ 
+-	ret = xt_register_table(table, &bootstrap, newinfo);
+-	if (ret != 0) {
+-		xt_free_table_info(newinfo);
+-		return ret;
++	new_table = xt_register_table(net, table, &bootstrap, newinfo);
++	if (IS_ERR(new_table)) {
++		ret = PTR_ERR(new_table);
++		goto out_free;
+ 	}
++	return new_table;
+ 
+-	return 0;
++out_free:
++	xt_free_table_info(newinfo);
++out:
++	return ERR_PTR(ret);
+ }
+ 
+ void ip6t_unregister_table(struct xt_table *table)
+ {
+ 	struct xt_table_info *private;
+ 	void *loc_cpu_entry;
++	struct module *table_owner = table->me;
+ 
+ 	private = xt_unregister_table(table);
+ 
+ 	/* Decrease module usage counts and free resources */
+ 	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ 	IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
++	if (private->number > private->initial_entries)
++		module_put(table_owner);
+ 	xt_free_table_info(private);
+ }
+ 
+@@ -1403,17 +2155,18 @@ icmp6_match(const struct sk_buff *skb,
  	   unsigned int protoff,
  	   bool *hotdrop)
  {
@@ -884887,7 +946428,7 @@
  		duprintf("Dropping evil ICMP tinygram.\n");
  		*hotdrop = true;
  		return false;
-@@ -1445,6 +2185,11 @@ static struct xt_target ip6t_standard_target __read_mostly = {
+@@ -1445,6 +2198,11 @@ static struct xt_target ip6t_standard_target __read_mostly = {
  	.name		= IP6T_STANDARD_TARGET,
  	.targetsize	= sizeof(int),
  	.family		= AF_INET6,
@@ -884899,7 +946440,7 @@
  };
  
  static struct xt_target ip6t_error_target __read_mostly = {
-@@ -1459,15 +2204,21 @@ static struct nf_sockopt_ops ip6t_sockopts = {
+@@ -1459,26 +2217,47 @@ static struct nf_sockopt_ops ip6t_sockopts = {
  	.set_optmin	= IP6T_BASE_CTL,
  	.set_optmax	= IP6T_SO_SET_MAX+1,
  	.set		= do_ip6t_set_ctl,
@@ -884922,7 +946463,43 @@
  	.matchsize	= sizeof(struct ip6t_icmp),
  	.checkentry	= icmp6_checkentry,
  	.proto		= IPPROTO_ICMPV6,
-@@ -1516,6 +2267,7 @@ err1:
+ 	.family		= AF_INET6,
+ };
+ 
++static int __net_init ip6_tables_net_init(struct net *net)
++{
++	return xt_proto_init(net, AF_INET6);
++}
++
++static void __net_exit ip6_tables_net_exit(struct net *net)
++{
++	xt_proto_fini(net, AF_INET6);
++}
++
++static struct pernet_operations ip6_tables_net_ops = {
++	.init = ip6_tables_net_init,
++	.exit = ip6_tables_net_exit,
++};
++
+ static int __init ip6_tables_init(void)
+ {
+ 	int ret;
+ 
+-	ret = xt_proto_init(AF_INET6);
++	ret = register_pernet_subsys(&ip6_tables_net_ops);
+ 	if (ret < 0)
+ 		goto err1;
+ 
+@@ -1508,7 +2287,7 @@ err4:
+ err3:
+ 	xt_unregister_target(&ip6t_standard_target);
+ err2:
+-	xt_proto_fini(AF_INET6);
++	unregister_pernet_subsys(&ip6_tables_net_ops);
+ err1:
+ 	return ret;
+ }
+@@ -1516,10 +2295,12 @@ err1:
  static void __exit ip6_tables_fini(void)
  {
  	nf_unregister_sockopt(&ip6t_sockopts);
@@ -884930,6 +946507,12 @@
  	xt_unregister_match(&icmp6_matchstruct);
  	xt_unregister_target(&ip6t_error_target);
  	xt_unregister_target(&ip6t_standard_target);
+-	xt_proto_fini(AF_INET6);
++
++	unregister_pernet_subsys(&ip6_tables_net_ops);
+ }
+ 
+ /*
 diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
 index 9afc836..d5f8fd5 100644
 --- a/net/ipv6/netfilter/ip6t_HL.c
@@ -885935,10 +947518,10 @@
 +module_init(rt_mt6_init);
 +module_exit(rt_mt6_exit);
 diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
-index 1d26b20..87d38d0 100644
+index 1d26b20..2d9cd09 100644
 --- a/net/ipv6/netfilter/ip6table_filter.c
 +++ b/net/ipv6/netfilter/ip6table_filter.c
-@@ -17,7 +17,9 @@ MODULE_LICENSE("GPL");
+@@ -17,28 +17,30 @@ MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Netfilter Core Team <coreteam at netfilter.org>");
  MODULE_DESCRIPTION("ip6tables filter table");
  
@@ -885949,7 +947532,14 @@
  
  static struct
  {
-@@ -31,14 +33,14 @@ static struct
+ 	struct ip6t_replace repl;
+ 	struct ip6t_standard entries[3];
+ 	struct ip6t_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "filter",
+ 		.valid_hooks = FILTER_VALID_HOOKS,
  		.num_entries = 4,
  		.size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
  		.hook_entry = {
@@ -885970,8 +947560,21 @@
  		},
  	},
  	.entries = {
-@@ -88,26 +90,26 @@ ip6t_local_out_hook(unsigned int hook,
- 	return ip6t_do_table(skb, hook, in, out, &packet_filter);
+@@ -65,7 +67,7 @@ ip6t_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ip6t_do_table(skb, hook, in, out, &packet_filter);
++	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter);
+ }
+ 
+ static unsigned int
+@@ -85,29 +87,29 @@ ip6t_local_out_hook(unsigned int hook,
+ 	}
+ #endif
+ 
+-	return ip6t_do_table(skb, hook, in, out, &packet_filter);
++	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter);
  }
  
 -static struct nf_hook_ops ip6t_ops[] = {
@@ -886001,11 +947604,65 @@
  		.priority	= NF_IP6_PRI_FILTER,
  	},
  };
+@@ -116,6 +118,26 @@ static struct nf_hook_ops ip6t_ops[] = {
+ static int forward = NF_ACCEPT;
+ module_param(forward, bool, 0000);
+ 
++static int __net_init ip6table_filter_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv6.ip6table_filter =
++		ip6t_register_table(net, &packet_filter, &initial_table.repl);
++	if (IS_ERR(net->ipv6.ip6table_filter))
++		return PTR_ERR(net->ipv6.ip6table_filter);
++	return 0;
++}
++
++static void __net_exit ip6table_filter_net_exit(struct net *net)
++{
++	ip6t_unregister_table(net->ipv6.ip6table_filter);
++}
++
++static struct pernet_operations ip6table_filter_net_ops = {
++	.init = ip6table_filter_net_init,
++	.exit = ip6table_filter_net_exit,
++};
++
+ static int __init ip6table_filter_init(void)
+ {
+ 	int ret;
+@@ -128,8 +150,7 @@ static int __init ip6table_filter_init(void)
+ 	/* Entry 1 is the FORWARD hook */
+ 	initial_table.entries[1].target.verdict = -forward - 1;
+ 
+-	/* Register table */
+-	ret = ip6t_register_table(&packet_filter, &initial_table.repl);
++	ret = register_pernet_subsys(&ip6table_filter_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -141,14 +162,14 @@ static int __init ip6table_filter_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ip6t_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&ip6table_filter_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit ip6table_filter_fini(void)
+ {
+ 	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+-	ip6t_unregister_table(&packet_filter);
++	unregister_pernet_subsys(&ip6table_filter_net_ops);
+ }
+ 
+ module_init(ip6table_filter_init);
 diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
-index a0b6381..d608260 100644
+index a0b6381..035343a 100644
 --- a/net/ipv6/netfilter/ip6table_mangle.c
 +++ b/net/ipv6/netfilter/ip6table_mangle.c
-@@ -15,11 +15,11 @@ MODULE_LICENSE("GPL");
+@@ -15,36 +15,36 @@ MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Netfilter Core Team <coreteam at netfilter.org>");
  MODULE_DESCRIPTION("ip6tables mangle table");
  
@@ -886022,7 +947679,14 @@
  
  static struct
  {
-@@ -33,18 +33,18 @@ static struct
+ 	struct ip6t_replace repl;
+ 	struct ip6t_standard entries[5];
+ 	struct ip6t_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "mangle",
+ 		.valid_hooks = MANGLE_VALID_HOOKS,
  		.num_entries = 6,
  		.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
  		.hook_entry = {
@@ -886051,7 +947715,25 @@
  		},
  	},
  	.entries = {
-@@ -120,40 +120,40 @@ ip6t_local_hook(unsigned int hook,
+@@ -73,7 +73,7 @@ ip6t_route_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ip6t_do_table(skb, hook, in, out, &packet_mangler);
++	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
+ }
+ 
+ static unsigned int
+@@ -108,7 +108,7 @@ ip6t_local_hook(unsigned int hook,
+ 	/* flowlabel and prio (includes version, which shouldn't change either */
+ 	flowlabel = *((u_int32_t *)ipv6_hdr(skb));
+ 
+-	ret = ip6t_do_table(skb, hook, in, out, &packet_mangler);
++	ret = ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
+ 
+ 	if (ret != NF_DROP && ret != NF_STOLEN
+ 		&& (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr))
+@@ -120,50 +120,69 @@ ip6t_local_hook(unsigned int hook,
  	return ret;
  }
  
@@ -886098,11 +947780,59 @@
  		.priority	= NF_IP6_PRI_MANGLE,
  	},
  };
+ 
++static int __net_init ip6table_mangle_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv6.ip6table_mangle =
++		ip6t_register_table(net, &packet_mangler, &initial_table.repl);
++	if (IS_ERR(net->ipv6.ip6table_mangle))
++		return PTR_ERR(net->ipv6.ip6table_mangle);
++	return 0;
++}
++
++static void __net_exit ip6table_mangle_net_exit(struct net *net)
++{
++	ip6t_unregister_table(net->ipv6.ip6table_mangle);
++}
++
++static struct pernet_operations ip6table_mangle_net_ops = {
++	.init = ip6table_mangle_net_init,
++	.exit = ip6table_mangle_net_exit,
++};
++
+ static int __init ip6table_mangle_init(void)
+ {
+ 	int ret;
+ 
+-	/* Register table */
+-	ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
++	ret = register_pernet_subsys(&ip6table_mangle_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -175,14 +194,14 @@ static int __init ip6table_mangle_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ip6t_unregister_table(&packet_mangler);
++	unregister_pernet_subsys(&ip6table_mangle_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit ip6table_mangle_fini(void)
+ {
+ 	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+-	ip6t_unregister_table(&packet_mangler);
++	unregister_pernet_subsys(&ip6table_mangle_net_ops);
+ }
+ 
+ module_init(ip6table_mangle_init);
 diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
-index 8f7109f..eccbaaa 100644
+index 8f7109f..5cd8420 100644
 --- a/net/ipv6/netfilter/ip6table_raw.c
 +++ b/net/ipv6/netfilter/ip6table_raw.c
-@@ -6,7 +6,7 @@
+@@ -6,26 +6,26 @@
  #include <linux/module.h>
  #include <linux/netfilter_ipv6/ip6_tables.h>
  
@@ -886111,7 +947841,14 @@
  
  static struct
  {
-@@ -20,12 +20,12 @@ static struct
+ 	struct ip6t_replace repl;
+ 	struct ip6t_standard entries[2];
+ 	struct ip6t_error term;
+-} initial_table __initdata = {
++} initial_table __net_initdata = {
+ 	.repl = {
+ 		.name = "raw",
+ 		.valid_hooks = RAW_VALID_HOOKS,
  		.num_entries = 3,
  		.size = sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
  		.hook_entry = {
@@ -886128,8 +947865,12 @@
  		},
  	},
  	.entries = {
-@@ -54,18 +54,18 @@ ip6t_hook(unsigned int hook,
- 	return ip6t_do_table(skb, hook, in, out, &packet_raw);
+@@ -51,32 +51,51 @@ ip6t_hook(unsigned int hook,
+ 	 const struct net_device *out,
+ 	 int (*okfn)(struct sk_buff *))
+ {
+-	return ip6t_do_table(skb, hook, in, out, &packet_raw);
++	return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_raw);
  }
  
 -static struct nf_hook_ops ip6t_ops[] = {
@@ -886150,11 +947891,70 @@
  	  .priority = NF_IP6_PRI_FIRST,
  	  .owner = THIS_MODULE,
  	},
+ };
+ 
++static int __net_init ip6table_raw_net_init(struct net *net)
++{
++	/* Register table */
++	net->ipv6.ip6table_raw =
++		ip6t_register_table(net, &packet_raw, &initial_table.repl);
++	if (IS_ERR(net->ipv6.ip6table_raw))
++		return PTR_ERR(net->ipv6.ip6table_raw);
++	return 0;
++}
++
++static void __net_exit ip6table_raw_net_exit(struct net *net)
++{
++	ip6t_unregister_table(net->ipv6.ip6table_raw);
++}
++
++static struct pernet_operations ip6table_raw_net_ops = {
++	.init = ip6table_raw_net_init,
++	.exit = ip6table_raw_net_exit,
++};
++
+ static int __init ip6table_raw_init(void)
+ {
+ 	int ret;
+ 
+-	/* Register table */
+-	ret = ip6t_register_table(&packet_raw, &initial_table.repl);
++	ret = register_pernet_subsys(&ip6table_raw_net_ops);
+ 	if (ret < 0)
+ 		return ret;
+ 
+@@ -88,14 +107,14 @@ static int __init ip6table_raw_init(void)
+ 	return ret;
+ 
+  cleanup_table:
+-	ip6t_unregister_table(&packet_raw);
++	unregister_pernet_subsys(&ip6table_raw_net_ops);
+ 	return ret;
+ }
+ 
+ static void __exit ip6table_raw_fini(void)
+ {
+ 	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+-	ip6t_unregister_table(&packet_raw);
++	unregister_pernet_subsys(&ip6table_raw_net_ops);
+ }
+ 
+ module_init(ip6table_raw_init);
 diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
-index ad74bab..2d7b024 100644
+index ad74bab..3717bdf 100644
 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
 +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
-@@ -60,12 +60,6 @@ static int ipv6_print_tuple(struct seq_file *s,
+@@ -30,7 +30,8 @@
+ static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+ 			     struct nf_conntrack_tuple *tuple)
+ {
+-	u_int32_t _addrs[8], *ap;
++	const u_int32_t *ap;
++	u_int32_t _addrs[8];
+ 
+ 	ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
+ 				sizeof(_addrs), _addrs);
+@@ -60,12 +61,6 @@ static int ipv6_print_tuple(struct seq_file *s,
  			  NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
  }
  
@@ -886167,7 +947967,18 @@
  /*
   * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
   *
-@@ -258,80 +252,51 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
+@@ -152,8 +147,8 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
+ 				 int (*okfn)(struct sk_buff *))
+ {
+ 	struct nf_conn *ct;
+-	struct nf_conn_help *help;
+-	struct nf_conntrack_helper *helper;
++	const struct nf_conn_help *help;
++	const struct nf_conntrack_helper *helper;
+ 	enum ip_conntrack_info ctinfo;
+ 	unsigned int ret, protoff;
+ 	unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
+@@ -258,80 +253,51 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
  	return ipv6_conntrack_in(hooknum, skb, in, out, okfn);
  }
  
@@ -886255,7 +948066,7 @@
  #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  
  #include <linux/netfilter/nfnetlink.h>
-@@ -376,7 +341,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
+@@ -376,7 +342,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
  	.pkt_to_tuple		= ipv6_pkt_to_tuple,
  	.invert_tuple		= ipv6_invert_tuple,
  	.print_tuple		= ipv6_print_tuple,
@@ -886264,7 +948075,7 @@
  #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
  	.tuple_to_nlattr	= ipv6_tuple_to_nlattr,
 diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
-index fd9123f..da924c6 100644
+index fd9123f..0897d0f 100644
 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
 +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
 @@ -24,6 +24,7 @@
@@ -886275,7 +948086,26 @@
  
  static unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ;
  
-@@ -74,13 +75,6 @@ static int icmpv6_print_tuple(struct seq_file *s,
+@@ -31,7 +32,8 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
+ 			       unsigned int dataoff,
+ 			       struct nf_conntrack_tuple *tuple)
+ {
+-	struct icmp6hdr _hdr, *hp;
++	const struct icmp6hdr *hp;
++	struct icmp6hdr _hdr;
+ 
+ 	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ 	if (hp == NULL)
+@@ -44,7 +46,7 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
+ }
+ 
+ /* Add 1; spaces filled with 0. */
+-static u_int8_t invmap[] = {
++static const u_int8_t invmap[] = {
+ 	[ICMPV6_ECHO_REQUEST - 128]	= ICMPV6_ECHO_REPLY + 1,
+ 	[ICMPV6_ECHO_REPLY - 128]	= ICMPV6_ECHO_REQUEST + 1,
+ 	[ICMPV6_NI_QUERY - 128]		= ICMPV6_NI_QUERY + 1,
+@@ -74,13 +76,6 @@ static int icmpv6_print_tuple(struct seq_file *s,
  			  ntohs(tuple->src.u.icmp.id));
  }
  
@@ -886289,7 +948119,58 @@
  /* Returns verdict for packet, or -1 for invalid. */
  static int icmpv6_packet(struct nf_conn *ct,
  		       const struct sk_buff *skb,
-@@ -192,7 +186,7 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
+@@ -107,24 +102,24 @@ static int icmpv6_packet(struct nf_conn *ct,
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int icmpv6_new(struct nf_conn *conntrack,
++static int icmpv6_new(struct nf_conn *ct,
+ 		      const struct sk_buff *skb,
+ 		      unsigned int dataoff)
+ {
+-	static u_int8_t valid_new[] = {
++	static const u_int8_t valid_new[] = {
+ 		[ICMPV6_ECHO_REQUEST - 128] = 1,
+ 		[ICMPV6_NI_QUERY - 128] = 1
+ 	};
+-	int type = conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128;
++	int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128;
+ 
+ 	if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
+ 		/* Can't create a new ICMPv6 `conn' with this. */
+ 		pr_debug("icmpv6: can't create new conn with type %u\n",
+ 			 type + 128);
+-		NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
++		NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple);
+ 		return 0;
+ 	}
+-	atomic_set(&conntrack->proto.icmp.count, 0);
++	atomic_set(&ct->proto.icmp.count, 0);
+ 	return 1;
+ }
+ 
+@@ -135,8 +130,8 @@ icmpv6_error_message(struct sk_buff *skb,
+ 		     unsigned int hooknum)
+ {
+ 	struct nf_conntrack_tuple intuple, origtuple;
+-	struct nf_conntrack_tuple_hash *h;
+-	struct nf_conntrack_l4proto *inproto;
++	const struct nf_conntrack_tuple_hash *h;
++	const struct nf_conntrack_l4proto *inproto;
+ 
+ 	NF_CT_ASSERT(skb->nfct == NULL);
+ 
+@@ -182,7 +177,8 @@ static int
+ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
+ 	     enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+ {
+-	struct icmp6hdr _ih, *icmp6h;
++	const struct icmp6hdr *icmp6h;
++	struct icmp6hdr _ih;
+ 
+ 	icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
+ 	if (icmp6h == NULL) {
+@@ -192,7 +188,7 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
  		return -NF_ACCEPT;
  	}
  
@@ -886298,7 +948179,7 @@
  	    nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
  		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
  			      "nf_ct_icmpv6: ICMPv6 checksum failed\n");
-@@ -213,12 +207,9 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
+@@ -213,12 +209,9 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
  static int icmpv6_tuple_to_nlattr(struct sk_buff *skb,
  				  const struct nf_conntrack_tuple *t)
  {
@@ -886314,7 +948195,7 @@
  
  	return 0;
  
-@@ -240,12 +231,9 @@ static int icmpv6_nlattr_to_tuple(struct nlattr *tb[],
+@@ -240,12 +233,9 @@ static int icmpv6_nlattr_to_tuple(struct nlattr *tb[],
  	    || !tb[CTA_PROTO_ICMPV6_ID])
  		return -EINVAL;
  
@@ -886330,7 +948211,7 @@
  
  	if (tuple->dst.u.icmp.type < 128
  	    || tuple->dst.u.icmp.type - 128 >= sizeof(invmap)
-@@ -280,7 +268,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
+@@ -280,7 +270,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
  	.pkt_to_tuple		= icmpv6_pkt_to_tuple,
  	.invert_tuple		= icmpv6_invert_tuple,
  	.print_tuple		= icmpv6_print_tuple,
@@ -886339,10 +948220,18 @@
  	.new			= icmpv6_new,
  	.error			= icmpv6_error,
 diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
-index e170c67..022da6c 100644
+index e170c67..2a0d698 100644
 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c
 +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
-@@ -70,14 +70,37 @@ struct nf_ct_frag6_queue
+@@ -39,6 +39,7 @@
+ #include <net/rawv6.h>
+ #include <net/ndisc.h>
+ #include <net/addrconf.h>
++#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+ #include <linux/sysctl.h>
+ #include <linux/netfilter.h>
+ #include <linux/netfilter_ipv6.h>
+@@ -70,14 +71,37 @@ struct nf_ct_frag6_queue
  	__u16			nhoffset;
  };
  
@@ -886387,7 +948276,7 @@
  
  static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
  			       struct in6_addr *daddr)
-@@ -125,7 +148,7 @@ static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
+@@ -125,7 +149,7 @@ static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
  {
  	if (work)
  		*work -= skb->truesize;
@@ -886396,7 +948285,7 @@
  	nf_skb_free(skb);
  	kfree_skb(skb);
  }
-@@ -147,7 +170,7 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
+@@ -147,7 +171,7 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
  
  static void nf_ct_frag6_evictor(void)
  {
@@ -886405,7 +948294,7 @@
  }
  
  static void nf_ct_frag6_expire(unsigned long data)
-@@ -183,7 +206,7 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
+@@ -183,7 +207,7 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
  	arg.dst = dst;
  	hash = ip6qhashfn(id, src, dst);
  
@@ -886414,7 +948303,7 @@
  	if (q == NULL)
  		goto oom;
  
-@@ -352,7 +375,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
+@@ -352,7 +376,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
  	skb->dev = NULL;
  	fq->q.stamp = skb->tstamp;
  	fq->q.meat += skb->len;
@@ -886423,7 +948312,7 @@
  
  	/* The first fragment.
  	 * nhoffset is obtained from the first fragment, of course.
-@@ -362,7 +385,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
+@@ -362,7 +386,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
  		fq->q.last_in |= FIRST_IN;
  	}
  	write_lock(&nf_frags.lock);
@@ -886432,7 +948321,7 @@
  	write_unlock(&nf_frags.lock);
  	return 0;
  
-@@ -429,7 +452,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
+@@ -429,7 +453,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
  		clone->ip_summed = head->ip_summed;
  
  		NFCT_FRAG6_CB(clone)->orig = NULL;
@@ -886441,7 +948330,7 @@
  	}
  
  	/* We have to remove fragment header from datagram and to relocate
-@@ -443,7 +466,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
+@@ -443,7 +467,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
  	skb_shinfo(head)->frag_list = head->next;
  	skb_reset_transport_header(head);
  	skb_push(head, head->data - skb_network_header(head));
@@ -886450,7 +948339,7 @@
  
  	for (fp=head->next; fp; fp = fp->next) {
  		head->data_len += fp->len;
-@@ -453,7 +476,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
+@@ -453,7 +477,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
  		else if (head->ip_summed == CHECKSUM_COMPLETE)
  			head->csum = csum_add(head->csum, fp->csum);
  		head->truesize += fp->truesize;
@@ -886459,7 +948348,7 @@
  	}
  
  	head->next = NULL;
-@@ -603,7 +626,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
+@@ -603,7 +627,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
  		goto ret_orig;
  	}
  
@@ -886468,15 +948357,32 @@
  		nf_ct_frag6_evictor();
  
  	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
-@@ -674,7 +697,6 @@ int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
+@@ -657,24 +681,8 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+ 	nf_conntrack_put_reasm(skb);
+ }
  
+-int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
+-{
+-	struct sk_buff *s, *s2;
+-
+-	for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) {
+-
+-		s2 = s->next;
+-		kfree_skb(s);
+-	}
+-
+-	kfree_skb(skb);
+-
+-	return 0;
+-}
+-
  int nf_ct_frag6_init(void)
  {
 -	nf_frags.ctl = &nf_frags_ctl;
  	nf_frags.hashfn = nf_hashfn;
  	nf_frags.constructor = ip6_frag_init;
  	nf_frags.destructor = NULL;
-@@ -682,6 +704,11 @@ int nf_ct_frag6_init(void)
+@@ -682,6 +690,11 @@ int nf_ct_frag6_init(void)
  	nf_frags.qsize = sizeof(struct nf_ct_frag6_queue);
  	nf_frags.match = ip6_frag_match;
  	nf_frags.frag_expire = nf_ct_frag6_expire;
@@ -886488,7 +948394,7 @@
  	inet_frags_init(&nf_frags);
  
  	return 0;
-@@ -691,6 +718,6 @@ void nf_ct_frag6_cleanup(void)
+@@ -691,6 +704,6 @@ void nf_ct_frag6_cleanup(void)
  {
  	inet_frags_fini(&nf_frags);
  
@@ -886530,7 +948436,7 @@
  }
  
 diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
-index 807260d..4d88055 100644
+index 807260d..8897ccf 100644
 --- a/net/ipv6/raw.c
 +++ b/net/ipv6/raw.c
 @@ -54,39 +54,31 @@
@@ -886758,7 +948664,15 @@
  	goto out;
  }
  
-@@ -618,7 +655,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
+@@ -604,6 +641,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
+ 	skb_reserve(skb, hh_len);
+ 
+ 	skb->priority = sk->sk_priority;
++	skb->mark = sk->sk_mark;
+ 	skb->dst = dst_clone(&rt->u.dst);
+ 
+ 	skb_put(skb, length);
+@@ -618,7 +656,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
  		goto error_fault;
  
  	IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
@@ -886767,7 +948681,16 @@
  		      dst_output);
  	if (err > 0)
  		err = np->recverr ? net_xmit_errno(err) : 0;
-@@ -843,7 +880,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+@@ -730,6 +768,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+ 	 */
+ 	memset(&fl, 0, sizeof(fl));
+ 
++	fl.mark = sk->sk_mark;
++
+ 	if (sin6) {
+ 		if (addr_len < SIN6_LEN_RFC2133)
+ 			return -EINVAL;
+@@ -843,7 +883,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
  	if (final_p)
  		ipv6_addr_copy(&fl.fl6_dst, final_p);
  
@@ -886776,7 +948699,7 @@
  		if (err == -EREMOTE)
  			err = ip6_dst_blackhole(sk, &dst, &fl);
  		if (err < 0)
-@@ -1172,76 +1209,6 @@ struct proto rawv6_prot = {
+@@ -1172,76 +1212,6 @@ struct proto rawv6_prot = {
  };
  
  #ifdef CONFIG_PROC_FS
@@ -886853,7 +948776,7 @@
  static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
  {
  	struct ipv6_pinfo *np = inet6_sk(sp);
-@@ -1254,7 +1221,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
+@@ -1254,7 +1224,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
  	srcp  = inet_sk(sp)->num;
  	seq_printf(seq,
  		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
@@ -886862,7 +948785,7 @@
  		   i,
  		   src->s6_addr32[0], src->s6_addr32[1],
  		   src->s6_addr32[2], src->s6_addr32[3], srcp,
-@@ -1266,7 +1233,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
+@@ -1266,7 +1236,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
  		   0, 0L, 0,
  		   sock_i_uid(sp), 0,
  		   sock_i_ino(sp),
@@ -886871,7 +948794,7 @@
  }
  
  static int raw6_seq_show(struct seq_file *seq, void *v)
-@@ -1277,23 +1244,22 @@ static int raw6_seq_show(struct seq_file *seq, void *v)
+@@ -1277,23 +1247,22 @@ static int raw6_seq_show(struct seq_file *seq, void *v)
  			   "local_address                         "
  			   "remote_address                        "
  			   "st tx_queue rx_queue tr tm->when retrnsmt"
@@ -886897,11 +948820,11 @@
  {
 -	return seq_open_private(file, &raw6_seq_ops,
 -			sizeof(struct raw6_iter_state));
-+	return raw_seq_open(inode, file, &raw_v6_hashinfo, PF_INET6);
++	return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops);
  }
  
  static const struct file_operations raw6_seq_fops = {
-@@ -1301,18 +1267,86 @@ static const struct file_operations raw6_seq_fops = {
+@@ -1301,18 +1270,86 @@ static const struct file_operations raw6_seq_fops = {
  	.open =		raw6_seq_open,
  	.read =		seq_read,
  	.llseek =	seq_lseek,
@@ -887297,7 +949220,7 @@
 +	inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
  }
 diff --git a/net/ipv6/route.c b/net/ipv6/route.c
-index 20083e0..4004c5f 100644
+index 20083e0..513f72e 100644
 --- a/net/ipv6/route.c
 +++ b/net/ipv6/route.c
 @@ -73,21 +73,13 @@
@@ -887323,15 +949246,25 @@
  
  static int		ip6_pkt_discard(struct sk_buff *skb);
  static int		ip6_pkt_discard_out(struct sk_buff *skb);
-@@ -113,6 +105,7 @@ static struct dst_ops ip6_dst_ops = {
+@@ -113,7 +105,9 @@ static struct dst_ops ip6_dst_ops = {
  	.negative_advice	=	ip6_negative_advice,
  	.link_failure		=	ip6_link_failure,
  	.update_pmtu		=	ip6_rt_update_pmtu,
 +	.local_out		=	ip6_local_out,
  	.entry_size		=	sizeof(struct rt6_info),
++	.entries		=	ATOMIC_INIT(0),
+ };
+ 
+ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
+@@ -127,6 +121,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
+ 	.check			=	ip6_dst_check,
+ 	.update_pmtu		=	ip6_rt_blackhole_update_pmtu,
+ 	.entry_size		=	sizeof(struct rt6_info),
++	.entries		=	ATOMIC_INIT(0),
  };
  
-@@ -152,7 +145,6 @@ struct rt6_info ip6_null_entry = {
+ struct rt6_info ip6_null_entry = {
+@@ -152,7 +147,6 @@ struct rt6_info ip6_null_entry = {
  
  static int ip6_pkt_prohibit(struct sk_buff *skb);
  static int ip6_pkt_prohibit_out(struct sk_buff *skb);
@@ -887339,7 +949272,7 @@
  
  struct rt6_info ip6_prohibit_entry = {
  	.u = {
-@@ -181,8 +173,8 @@ struct rt6_info ip6_blk_hole_entry = {
+@@ -181,8 +175,8 @@ struct rt6_info ip6_blk_hole_entry = {
  			.obsolete	= -1,
  			.error		= -EINVAL,
  			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
@@ -887350,7 +949283,7 @@
  			.ops		= &ip6_dst_ops,
  			.path		= (struct dst_entry*)&ip6_blk_hole_entry,
  		}
-@@ -216,9 +208,12 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+@@ -216,9 +210,12 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  {
  	struct rt6_info *rt = (struct rt6_info *)dst;
  	struct inet6_dev *idev = rt->rt6i_idev;
@@ -887365,7 +949298,7 @@
  		if (loopback_idev != NULL) {
  			rt->rt6i_idev = loopback_idev;
  			in6_dev_put(idev);
-@@ -606,7 +601,10 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
+@@ -606,7 +603,10 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
  
  int ip6_ins_rt(struct rt6_info *rt)
  {
@@ -887377,7 +949310,7 @@
  }
  
  static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
-@@ -782,12 +780,6 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
+@@ -782,12 +782,6 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
  
  EXPORT_SYMBOL(ip6_route_output);
  
@@ -887390,7 +949323,7 @@
  int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl)
  {
  	struct rt6_info *ort = (struct rt6_info *) *dstp;
-@@ -800,8 +792,8 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
+@@ -800,8 +794,8 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
  
  		atomic_set(&new->__refcnt, 1);
  		new->__use = 1;
@@ -887401,7 +949334,7 @@
  
  		memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
  		new->dev = ort->u.dst.dev;
-@@ -896,8 +888,8 @@ static inline unsigned int ipv6_advmss(unsigned int mtu)
+@@ -896,8 +890,8 @@ static inline unsigned int ipv6_advmss(unsigned int mtu)
  {
  	mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
  
@@ -887412,7 +949345,7 @@
  
  	/*
  	 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
-@@ -991,25 +983,25 @@ int ndisc_dst_gc(int *more)
+@@ -991,25 +985,25 @@ int ndisc_dst_gc(int *more)
  	return freed;
  }
  
@@ -887444,7 +949377,7 @@
  }
  
  /* Clean host part of a prefix. Not necessary in radix tree,
-@@ -1269,7 +1261,10 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
+@@ -1269,7 +1263,10 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
  
  int ip6_del_rt(struct rt6_info *rt)
  {
@@ -887456,7 +949389,7 @@
  }
  
  static int ip6_route_del(struct fib6_config *cfg)
-@@ -1514,7 +1509,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
+@@ -1514,7 +1511,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
  		rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
  		if (allfrag)
  			rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
@@ -887465,7 +949398,7 @@
  		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
  		goto out;
  	}
-@@ -1540,7 +1535,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
+@@ -1540,7 +1537,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
  		 * which is 10 mins. After 10 mins the decreased pmtu is expired
  		 * and detecting PMTU increase will be automatically happened.
  		 */
@@ -887474,7 +949407,7 @@
  		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
  
  		ip6_ins_rt(nrt);
-@@ -1665,6 +1660,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
+@@ -1665,6 +1662,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
  	return rt;
  }
  
@@ -887483,7 +949416,7 @@
  struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
  				     struct net_device *dev,
  				     unsigned int pref)
-@@ -1766,8 +1763,7 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
+@@ -1766,8 +1765,7 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
   *	Drop the packet on the floor
   */
  
@@ -887493,7 +949426,7 @@
  {
  	int type;
  	switch (ipstats_mib_noroutes) {
-@@ -1811,12 +1807,6 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)
+@@ -1811,12 +1809,6 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)
  	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
  }
  
@@ -887506,7 +949439,24 @@
  #endif
  
  /*
-@@ -2015,9 +2005,13 @@ errout:
+@@ -1917,7 +1909,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
+ 	 */
+ 	if (rt->rt6i_dev == arg->dev &&
+ 	    !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
+-	    (dst_mtu(&rt->u.dst) > arg->mtu ||
++	    (dst_mtu(&rt->u.dst) >= arg->mtu ||
+ 	     (dst_mtu(&rt->u.dst) < arg->mtu &&
+ 	      dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
+ 		rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
+@@ -1970,6 +1962,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
+ 
+ 	cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
+ 	cfg->fc_nlinfo.nlh = nlh;
++	cfg->fc_nlinfo.nl_net = skb->sk->sk_net;
+ 
+ 	if (tb[RTA_GATEWAY]) {
+ 		nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
+@@ -2015,9 +2008,13 @@ errout:
  
  static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
  {
@@ -887520,7 +949470,7 @@
  	err = rtm_to_fib6_config(skb, nlh, &cfg);
  	if (err < 0)
  		return err;
-@@ -2027,9 +2021,13 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a
+@@ -2027,9 +2024,13 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a
  
  static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
  {
@@ -887534,7 +949484,7 @@
  	err = rtm_to_fib6_config(skb, nlh, &cfg);
  	if (err < 0)
  		return err;
-@@ -2164,6 +2162,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
+@@ -2164,6 +2165,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
  
  static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
  {
@@ -887542,7 +949492,7 @@
  	struct nlattr *tb[RTA_MAX+1];
  	struct rt6_info *rt;
  	struct sk_buff *skb;
-@@ -2171,6 +2170,9 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
+@@ -2171,6 +2173,9 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
  	struct flowi fl;
  	int err, iif = 0;
  
@@ -887552,7 +949502,7 @@
  	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
  	if (err < 0)
  		goto errout;
-@@ -2230,7 +2232,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
+@@ -2230,7 +2235,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
  		goto errout;
  	}
  
@@ -887561,7 +949511,7 @@
  errout:
  	return err;
  }
-@@ -2238,32 +2240,29 @@ errout:
+@@ -2238,32 +2243,29 @@ errout:
  void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
  {
  	struct sk_buff *skb;
@@ -887604,7 +949554,7 @@
  }
  
  /*
-@@ -2353,28 +2352,61 @@ static const struct file_operations rt6_stats_seq_fops = {
+@@ -2353,28 +2355,61 @@ static const struct file_operations rt6_stats_seq_fops = {
  	.llseek	 = seq_lseek,
  	.release = single_release,
  };
@@ -887671,7 +949621,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0200,
  		.proc_handler	=	&ipv6_sysctl_rtcache_flush
-@@ -2390,7 +2422,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2390,7 +2425,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_MAX_SIZE,
  		.procname	=	"max_size",
@@ -887680,7 +949630,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec,
-@@ -2398,7 +2430,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2398,7 +2433,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL,
  		.procname	=	"gc_min_interval",
@@ -887689,7 +949639,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2407,7 +2439,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2407,7 +2442,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_GC_TIMEOUT,
  		.procname	=	"gc_timeout",
@@ -887698,7 +949648,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2416,7 +2448,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2416,7 +2451,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_GC_INTERVAL,
  		.procname	=	"gc_interval",
@@ -887707,7 +949657,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2425,7 +2457,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2425,7 +2460,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_GC_ELASTICITY,
  		.procname	=	"gc_elasticity",
@@ -887716,7 +949666,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2434,7 +2466,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2434,7 +2469,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_MTU_EXPIRES,
  		.procname	=	"mtu_expires",
@@ -887725,7 +949675,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2443,7 +2475,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2443,7 +2478,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_MIN_ADVMSS,
  		.procname	=	"min_adv_mss",
@@ -887734,7 +949684,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_jiffies,
-@@ -2452,7 +2484,7 @@ ctl_table ipv6_route_table[] = {
+@@ -2452,7 +2487,7 @@ ctl_table ipv6_route_table[] = {
  	{
  		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,
  		.procname	=	"gc_min_interval_ms",
@@ -887743,7 +949693,7 @@
  		.maxlen		=	sizeof(int),
  		.mode		=	0644,
  		.proc_handler	=	&proc_dointvec_ms_jiffies,
-@@ -2461,42 +2493,74 @@ ctl_table ipv6_route_table[] = {
+@@ -2461,42 +2496,74 @@ ctl_table ipv6_route_table[] = {
  	{ .ctl_name = 0 }
  };
  
@@ -888275,7 +950225,7 @@
 +	unregister_pernet_subsys(&ipv6_sysctl_net_ops);
 +}
 diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
-index 93980c3..00c0839 100644
+index 93980c3..59d0029 100644
 --- a/net/ipv6/tcp_ipv6.c
 +++ b/net/ipv6/tcp_ipv6.c
 @@ -265,7 +265,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
@@ -888287,6 +950237,17 @@
  		if (err == -EREMOTE)
  			err = ip6_dst_blackhole(sk, &dst, &fl);
  		if (err < 0)
+@@ -330,8 +330,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	struct tcp_sock *tp;
+ 	__u32 seq;
+ 
+-	sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
+-			  th->source, skb->dev->ifindex);
++	sk = inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, &hdr->daddr,
++			th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
+ 
+ 	if (sk == NULL) {
+ 		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
 @@ -733,7 +733,7 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
  				   struct in6_addr *saddr,
  				   struct in6_addr *daddr,
@@ -888323,7 +950284,43 @@
  	__be32 *topt;
  #ifdef CONFIG_TCP_MD5SIG
  	struct tcp_md5sig_key *key;
-@@ -2166,14 +2166,36 @@ static struct inet_protosw tcpv6_protosw = {
+@@ -1208,9 +1208,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
+ 	if (req)
+ 		return tcp_check_req(sk, skb, req, prev);
+ 
+-	nsk = __inet6_lookup_established(&tcp_hashinfo, &ipv6_hdr(skb)->saddr,
+-					 th->source, &ipv6_hdr(skb)->daddr,
+-					 ntohs(th->dest), inet6_iif(skb));
++	nsk = __inet6_lookup_established(sk->sk_net, &tcp_hashinfo,
++			&ipv6_hdr(skb)->saddr, th->source,
++			&ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
+ 
+ 	if (nsk) {
+ 		if (nsk->sk_state != TCP_TIME_WAIT) {
+@@ -1710,9 +1710,10 @@ static int tcp_v6_rcv(struct sk_buff *skb)
+ 	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
+ 	TCP_SKB_CB(skb)->sacked = 0;
+ 
+-	sk = __inet6_lookup(&tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source,
+-			    &ipv6_hdr(skb)->daddr, ntohs(th->dest),
+-			    inet6_iif(skb));
++	sk = __inet6_lookup(skb->dev->nd_net, &tcp_hashinfo,
++			&ipv6_hdr(skb)->saddr, th->source,
++			&ipv6_hdr(skb)->daddr, ntohs(th->dest),
++			inet6_iif(skb));
+ 
+ 	if (!sk)
+ 		goto no_tcp_socket;
+@@ -1792,7 +1793,7 @@ do_time_wait:
+ 	{
+ 		struct sock *sk2;
+ 
+-		sk2 = inet6_lookup_listener(&tcp_hashinfo,
++		sk2 = inet6_lookup_listener(skb->dev->nd_net, &tcp_hashinfo,
+ 					    &ipv6_hdr(skb)->daddr,
+ 					    ntohs(th->dest), inet6_iif(skb));
+ 		if (sk2 != NULL) {
+@@ -2166,14 +2167,36 @@ static struct inet_protosw tcpv6_protosw = {
  				INET_PROTOSW_ICSK,
  };
  
@@ -888368,7 +950365,7 @@
 +	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
  }
 diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
-index ee1cc3f..bd4b9df 100644
+index ee1cc3f..53739de 100644
 --- a/net/ipv6/udp.c
 +++ b/net/ipv6/udp.c
 @@ -34,6 +34,7 @@
@@ -888379,7 +950376,7 @@
  #include <linux/skbuff.h>
  #include <asm/uaccess.h>
  
-@@ -50,8 +51,6 @@
+@@ -50,14 +51,13 @@
  #include <linux/seq_file.h>
  #include "udp_impl.h"
  
@@ -888388,7 +950385,25 @@
  static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
  {
  	return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
-@@ -121,6 +120,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
+ }
+ 
+-static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
++static struct sock *__udp6_lib_lookup(struct net *net,
++				      struct in6_addr *saddr, __be16 sport,
+ 				      struct in6_addr *daddr, __be16 dport,
+ 				      int dif, struct hlist_head udptable[])
+ {
+@@ -70,7 +70,8 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
+ 	sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
+ 		struct inet_sock *inet = inet_sk(sk);
+ 
+-		if (sk->sk_hash == hnum && sk->sk_family == PF_INET6) {
++		if (sk->sk_net == net && sk->sk_hash == hnum &&
++				sk->sk_family == PF_INET6) {
+ 			struct ipv6_pinfo *np = inet6_sk(sk);
+ 			int score = 0;
+ 			if (inet->dport) {
+@@ -121,6 +122,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
  	struct inet_sock *inet = inet_sk(sk);
  	struct sk_buff *skb;
  	unsigned int ulen, copied;
@@ -888396,7 +950411,7 @@
  	int err;
  	int is_udplite = IS_UDPLITE(sk);
  
-@@ -131,7 +131,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
+@@ -131,7 +133,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
  		return ipv6_recv_error(sk, msg, len);
  
  try_again:
@@ -888406,7 +950421,7 @@
  	if (!skb)
  		goto out;
  
-@@ -164,6 +165,9 @@ try_again:
+@@ -164,6 +167,9 @@ try_again:
  	if (err)
  		goto out_free;
  
@@ -888416,7 +950431,7 @@
  	sock_recv_timestamp(msg, sk, skb);
  
  	/* Copy the address. */
-@@ -200,13 +204,17 @@ try_again:
+@@ -200,13 +206,17 @@ try_again:
  		err = ulen;
  
  out_free:
@@ -888436,7 +950451,16 @@
  
  	if (flags & MSG_DONTWAIT)
  		return -EAGAIN;
-@@ -251,13 +259,14 @@ static __inline__ void udpv6_err(struct sk_buff *skb,
+@@ -225,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ 	struct sock *sk;
+ 	int err;
+ 
+-	sk = __udp6_lib_lookup(daddr, uh->dest,
++	sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest,
+ 			       saddr, uh->source, inet6_iif(skb), udptable);
+ 	if (sk == NULL)
+ 		return;
+@@ -251,13 +261,14 @@ static __inline__ void udpv6_err(struct sk_buff *skb,
  				 struct inet6_skb_parm *opt, int type,
  				 int code, int offset, __be32 info     )
  {
@@ -888452,7 +950476,7 @@
  
  	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
  		goto drop;
-@@ -265,7 +274,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -265,7 +276,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  	/*
  	 * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c).
  	 */
@@ -888461,7 +950485,7 @@
  
  		if (up->pcrlen == 0) {          /* full coverage was set  */
  			LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage"
-@@ -289,13 +298,13 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+@@ -289,13 +300,13 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
  	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
  		/* Note that an ENOMEM error is charged twice */
  		if (rc == -ENOMEM)
@@ -888478,7 +950502,7 @@
  	kfree_skb(skb);
  	return -1;
  }
-@@ -361,10 +370,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr,
+@@ -361,10 +372,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr,
  	while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr,
  					uh->source, saddr, dif))) {
  		struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
@@ -888503,7 +950527,16 @@
  out:
  	read_unlock(&udp_hash_lock);
  	return 0;
-@@ -477,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
+@@ -458,7 +480,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
+ 	 * check socket cache ... must talk to Alan about his plans
+ 	 * for sock caches... i'll skip this for now.
+ 	 */
+-	sk = __udp6_lib_lookup(saddr, uh->source,
++	sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source,
+ 			       daddr, uh->dest, inet6_iif(skb), udptable);
+ 
+ 	if (sk == NULL) {
+@@ -477,7 +499,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
  
  	/* deliver */
  
@@ -888517,7 +950550,7 @@
  	sock_put(sk);
  	return 0;
  
-@@ -523,6 +548,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
+@@ -523,6 +550,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
  	struct inet_sock *inet = inet_sk(sk);
  	struct flowi *fl = &inet->cork.fl;
  	int err = 0;
@@ -888525,7 +950558,7 @@
  	__wsum csum = 0;
  
  	/* Grab the skbuff where UDP header space exists. */
-@@ -538,7 +564,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
+@@ -538,7 +566,7 @@ static int udp_v6_push_pending_frames(struct sock *sk)
  	uh->len = htons(up->len);
  	uh->check = 0;
  
@@ -888534,7 +950567,7 @@
  		csum = udplite_csum_outgoing(sk, skb);
  	 else
  		csum = udp_csum_outgoing(sk, skb);
-@@ -554,7 +580,7 @@ out:
+@@ -554,7 +582,7 @@ out:
  	up->len = 0;
  	up->pending = 0;
  	if (!err)
@@ -888543,7 +950576,7 @@
  	return err;
  }
  
-@@ -578,7 +604,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
+@@ -578,7 +606,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
  	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
  	int err;
  	int connected = 0;
@@ -888552,7 +950585,7 @@
  	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
  
  	/* destination address check */
-@@ -748,7 +774,7 @@ do_udp_sendmsg:
+@@ -748,7 +776,7 @@ do_udp_sendmsg:
  	if (final_p)
  		ipv6_addr_copy(&fl.fl6_dst, final_p);
  
@@ -888561,7 +950594,7 @@
  		if (err == -EREMOTE)
  			err = ip6_dst_blackhole(sk, &dst, &fl);
  		if (err < 0)
-@@ -988,6 +1014,10 @@ struct proto udpv6_prot = {
+@@ -988,6 +1016,10 @@ struct proto udpv6_prot = {
  	.hash		   = udp_lib_hash,
  	.unhash		   = udp_lib_unhash,
  	.get_port	   = udp_v6_get_port,
@@ -888572,7 +950605,7 @@
  	.obj_size	   = sizeof(struct udp6_sock),
  #ifdef CONFIG_COMPAT
  	.compat_setsockopt = compat_udpv6_setsockopt,
-@@ -1007,9 +1037,27 @@ static struct inet_protosw udpv6_protosw = {
+@@ -1007,9 +1039,27 @@ static struct inet_protosw udpv6_protosw = {
  };
  
  
@@ -889287,7 +951320,7 @@
  		       xfrm6_output_finish);
  }
 diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
-index b8e9eb4..c25a6b5 100644
+index b8e9eb4..7d20199 100644
 --- a/net/ipv6/xfrm6_policy.c
 +++ b/net/ipv6/xfrm6_policy.c
 @@ -11,9 +11,11 @@
@@ -889615,15 +951648,18 @@
  		BUG_ON(!loopback_idev);
  
  		do {
-@@ -385,6 +269,7 @@ static struct dst_ops xfrm6_dst_ops = {
+@@ -385,8 +269,10 @@ static struct dst_ops xfrm6_dst_ops = {
  	.update_pmtu =		xfrm6_update_pmtu,
  	.destroy =		xfrm6_dst_destroy,
  	.ifdown =		xfrm6_dst_ifdown,
 +	.local_out =		__ip6_local_out,
  	.gc_thresh =		1024,
  	.entry_size =		sizeof(struct xfrm_dst),
++	.entries =		ATOMIC_INIT(0),
  };
-@@ -395,13 +280,15 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
+ 
+ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
+@@ -395,13 +281,15 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
  	.dst_lookup =		xfrm6_dst_lookup,
  	.get_saddr = 		xfrm6_get_saddr,
  	.find_bundle =		__xfrm6_find_bundle,
@@ -889642,7 +951678,7 @@
  }
  
  static void xfrm6_policy_fini(void)
-@@ -409,10 +296,22 @@ static void xfrm6_policy_fini(void)
+@@ -409,10 +297,22 @@ static void xfrm6_policy_fini(void)
  	xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
  }
  
@@ -889721,6 +951757,19 @@
  }
  
  void xfrm6_state_fini(void)
+diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
+index fae90ff..639fe8a 100644
+--- a/net/ipv6/xfrm6_tunnel.c
++++ b/net/ipv6/xfrm6_tunnel.c
+@@ -319,7 +319,7 @@ static void xfrm6_tunnel_destroy(struct xfrm_state *x)
+ 	xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
+ }
+ 
+-static struct xfrm_type xfrm6_tunnel_type = {
++static const struct xfrm_type xfrm6_tunnel_type = {
+ 	.description	= "IP6IP6",
+ 	.owner          = THIS_MODULE,
+ 	.proto		= IPPROTO_IPV6,
 diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c
 index 0cf5264..92fef86 100644
 --- a/net/ipx/sysctl_net_ipx.c
@@ -890257,9 +952306,45 @@
  
  	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
 diff --git a/net/key/af_key.c b/net/key/af_key.c
-index 76dcd88..16b72b5 100644
+index 76dcd88..45c3c27 100644
 --- a/net/key/af_key.c
 +++ b/net/key/af_key.c
+@@ -1466,7 +1466,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
+ 		err = xfrm_state_update(x);
+ 
+ 	xfrm_audit_state_add(x, err ? 0 : 1,
+-			     audit_get_loginuid(current->audit_context), 0);
++			     audit_get_loginuid(current), 0);
+ 
+ 	if (err < 0) {
+ 		x->km.state = XFRM_STATE_DEAD;
+@@ -1520,7 +1520,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
+ 	km_state_notify(x, &c);
+ out:
+ 	xfrm_audit_state_delete(x, err ? 0 : 1,
+-			       audit_get_loginuid(current->audit_context), 0);
++			       audit_get_loginuid(current), 0);
+ 	xfrm_state_put(x);
+ 
+ 	return err;
+@@ -1695,7 +1695,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
+ 	if (proto == 0)
+ 		return -EINVAL;
+ 
+-	audit_info.loginuid = audit_get_loginuid(current->audit_context);
++	audit_info.loginuid = audit_get_loginuid(current);
+ 	audit_info.secid = 0;
+ 	err = xfrm_state_flush(proto, &audit_info);
+ 	if (err)
+@@ -2273,7 +2273,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
+ 				 hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+ 
+ 	xfrm_audit_policy_add(xp, err ? 0 : 1,
+-			     audit_get_loginuid(current->audit_context), 0);
++			     audit_get_loginuid(current), 0);
+ 
+ 	if (err)
+ 		goto out;
 @@ -2291,8 +2291,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
  	return 0;
  
@@ -890270,6 +952355,33 @@
  	return err;
  }
  
+@@ -2357,7 +2356,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
+ 		return -ENOENT;
+ 
+ 	xfrm_audit_policy_delete(xp, err ? 0 : 1,
+-				audit_get_loginuid(current->audit_context), 0);
++				audit_get_loginuid(current), 0);
+ 
+ 	if (err)
+ 		goto out;
+@@ -2618,7 +2617,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
+ 
+ 	if (delete) {
+ 		xfrm_audit_policy_delete(xp, err ? 0 : 1,
+-				audit_get_loginuid(current->audit_context), 0);
++				audit_get_loginuid(current), 0);
+ 
+ 		if (err)
+ 			goto out;
+@@ -2695,7 +2694,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
+ 	struct xfrm_audit audit_info;
+ 	int err;
+ 
+-	audit_info.loginuid = audit_get_loginuid(current->audit_context);
++	audit_info.loginuid = audit_get_loginuid(current);
+ 	audit_info.secid = 0;
+ 	err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
+ 	if (err)
 @@ -3236,8 +3235,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
  	return xp;
  
@@ -895148,7 +957260,7 @@
 +module_exit(rc80211_simple_exit);
 +#endif
 diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
-index 00f908d..89e1e30 100644
+index 00f908d..d44c872 100644
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
 @@ -24,6 +24,10 @@
@@ -895334,25 +957446,57 @@
  			rate = &mode->rates[i];
  			break;
  		}
-@@ -308,16 +336,13 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+@@ -308,8 +336,38 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
  
  	/* Divide channel_use by 8 to avoid wrapping around the counter */
  	load >>= CHAN_UTIL_SHIFT;
 -	local->channel_use_raw += load;
 -	rx->u.rx.load = load;
- 
--	return TXRX_CONTINUE;
++
 +	return load;
- }
++}
++
++static ieee80211_txrx_result
++ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
++{
++	int hdrlen;
++
++	/*
++	 * Drivers are required to align the payload data in a way that
++	 * guarantees that the contained IP header is aligned to a four-
++	 * byte boundary. In the case of regular frames, this simply means
++	 * aligning the payload to a four-byte boundary (because either
++	 * the IP header is directly contained, or IV/RFC1042 headers that
++	 * have a length divisible by four are in front of it.
++	 *
++	 * With A-MSDU frames, however, the payload data address must
++	 * yield two modulo four because there are 14-byte 802.3 headers
++	 * within the A-MSDU frames that push the IP header further back
++	 * to a multiple of four again. Thankfully, the specs were sane
++	 * enough this time around to require padding each A-MSDU subframe
++	 * to a length that is a multiple of four.
++	 *
++	 * Padding like atheros hardware adds which is inbetween the 802.11
++	 * header and the payload is not supported, the driver is required
++	 * to move the 802.11 header further back in that case.
++	 */
++	hdrlen = ieee80211_get_hdrlen(rx->fc);
++	if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
++		hdrlen += ETH_HLEN;
++	WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
  
+ 	return TXRX_CONTINUE;
+ }
+@@ -317,7 +375,7 @@ ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
  ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
  {
  	ieee80211_rx_h_parse_qos,
 -	ieee80211_rx_h_load_stats,
++	ieee80211_rx_h_verify_ip_alignment,
  	NULL
  };
  
-@@ -338,8 +363,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+@@ -338,8 +396,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
  	struct ieee80211_local *local = rx->local;
  	struct sk_buff *skb = rx->skb;
  
@@ -895369,7 +957513,7 @@
  		return TXRX_QUEUED;
  	}
  
-@@ -377,18 +408,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+@@ -377,18 +441,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
  		return TXRX_DROP;
  	}
  
@@ -895388,7 +957532,7 @@
  	/* Drop disallowed frame classes based on STA auth/assoc state;
  	 * IEEE 802.11, Chap 5.5.
  	 *
-@@ -400,7 +419,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+@@ -400,7 +452,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
  	if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
  		      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
  		       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
@@ -895397,7 +957541,7 @@
  		     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
  		if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
  		     !(rx->fc & IEEE80211_FCTL_TODS) &&
-@@ -620,13 +639,14 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+@@ -620,13 +672,14 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
  	/* Update last_rx only for IBSS packets which are for the current
  	 * BSSID to avoid keeping the current IBSS network alive in cases where
  	 * other STAs are using different BSSID. */
@@ -895415,7 +957559,7 @@
  		/* Update last_rx only for unicast frames in order to prevent
  		 * the Probe Request frames (the only broadcast frames from a
  		 * STA in infrastructure mode) from keeping a connection alive.
-@@ -870,6 +890,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+@@ -870,6 +923,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
  static ieee80211_txrx_result
  ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
  {
@@ -895423,7 +957567,7 @@
  	struct sk_buff *skb;
  	int no_pending_pkts;
  	DECLARE_MAC_BUF(mac);
-@@ -880,6 +901,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+@@ -880,6 +934,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
  		   !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
  		return TXRX_CONTINUE;
  
@@ -895434,7 +957578,7 @@
  	skb = skb_dequeue(&rx->sta->tx_filtered);
  	if (!skb) {
  		skb = skb_dequeue(&rx->sta->ps_tx_buf);
-@@ -956,68 +981,54 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+@@ -956,68 +1014,54 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
  	return TXRX_CONTINUE;
  }
  
@@ -895520,7 +957664,7 @@
  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  	DECLARE_MAC_BUF(mac);
  	DECLARE_MAC_BUF(mac2);
-@@ -1025,11 +1036,9 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1025,11 +1069,9 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  	DECLARE_MAC_BUF(mac4);
  
  	fc = rx->fc;
@@ -895533,7 +957677,7 @@
  
  	hdrlen = ieee80211_get_hdrlen(fc);
  
-@@ -1049,8 +1058,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1049,8 +1091,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  		memcpy(dst, hdr->addr3, ETH_ALEN);
  		memcpy(src, hdr->addr2, ETH_ALEN);
  
@@ -895544,7 +957688,7 @@
  			if (net_ratelimit())
  				printk(KERN_DEBUG "%s: dropped ToDS frame "
  				       "(BSSID=%s SA=%s DA=%s)\n",
-@@ -1058,7 +1067,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1058,7 +1100,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  				       print_mac(mac, hdr->addr1),
  				       print_mac(mac2, hdr->addr2),
  				       print_mac(mac3, hdr->addr3));
@@ -895553,7 +957697,7 @@
  		}
  		break;
  	case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-@@ -1066,7 +1075,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1066,7 +1108,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  		memcpy(dst, hdr->addr3, ETH_ALEN);
  		memcpy(src, hdr->addr4, ETH_ALEN);
  
@@ -895562,7 +957706,7 @@
  			if (net_ratelimit())
  				printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
  				       "frame (RA=%s TA=%s DA=%s SA=%s)\n",
-@@ -1075,7 +1084,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1075,7 +1117,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  				       print_mac(mac2, hdr->addr2),
  				       print_mac(mac3, hdr->addr3),
  				       print_mac(mac4, hdr->addr4));
@@ -895571,7 +957715,7 @@
  		}
  		break;
  	case IEEE80211_FCTL_FROMDS:
-@@ -1083,17 +1092,17 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1083,17 +1125,17 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  		memcpy(dst, hdr->addr1, ETH_ALEN);
  		memcpy(src, hdr->addr3, ETH_ALEN);
  
@@ -895592,7 +957736,7 @@
  			if (net_ratelimit()) {
  				printk(KERN_DEBUG "%s: dropped IBSS frame "
  				       "(DA=%s SA=%s BSSID=%s)\n",
-@@ -1102,21 +1111,20 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1102,21 +1144,20 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  				       print_mac(mac2, hdr->addr2),
  				       print_mac(mac3, hdr->addr3));
  			}
@@ -895617,7 +957761,7 @@
  	ethertype = (payload[6] << 8) | payload[7];
  
  	if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-@@ -1130,6 +1138,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1130,6 +1171,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  	} else {
  		struct ethhdr *ehdr;
  		__be16 len;
@@ -895625,7 +957769,7 @@
  		skb_pull(skb, hdrlen);
  		len = htons(skb->len);
  		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-@@ -1137,36 +1146,72 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1137,36 +1179,72 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  		memcpy(ehdr->h_source, src, ETH_ALEN);
  		ehdr->h_proto = len;
  	}
@@ -895657,9 +957801,7 @@
 +	if (ieee80211_802_1x_port_control(rx) ||
 +	    ieee80211_drop_unencrypted(rx))
 +		return false;
- 
--	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
--	    || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
++
 +	return true;
 +}
 +
@@ -895678,7 +957820,9 @@
 +
 +	skb = rx->skb;
 +	xmit_skb = NULL;
-+
+ 
+-	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
+-	    || sdata->type == IEEE80211_IF_TYPE_VLAN) &&
 +	if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
 +				      sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
  	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
@@ -895719,7 +957863,7 @@
  				skb = NULL;
  			}
  			if (dsta)
-@@ -1181,18 +1226,207 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+@@ -1181,18 +1259,207 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
  		netif_rx(skb);
  	}
  
@@ -895734,7 +957878,7 @@
 +		skb_reset_network_header(xmit_skb);
 +		skb_reset_mac_header(xmit_skb);
 +		dev_queue_xmit(xmit_skb);
- 	}
++	}
 +}
 +
 +static ieee80211_txrx_result
@@ -895849,12 +957993,12 @@
 +		}
 +
 +		ieee80211_deliver_skb(rx);
-+	}
-+
-+	return TXRX_QUEUED;
-+}
-+
-+static ieee80211_txrx_result
+ 	}
+ 
+ 	return TXRX_QUEUED;
+ }
+ 
+ static ieee80211_txrx_result
 +ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 +{
 +	struct net_device *dev = rx->dev;
@@ -895881,11 +958025,11 @@
 +	dev->stats.rx_bytes += rx->skb->len;
 +
 +	ieee80211_deliver_skb(rx);
- 
- 	return TXRX_QUEUED;
- }
- 
- static ieee80211_txrx_result
++
++	return TXRX_QUEUED;
++}
++
++static ieee80211_txrx_result
 +ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
 +{
 +	struct ieee80211_local *local = rx->local;
@@ -895932,7 +958076,7 @@
  ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
  {
  	struct ieee80211_sub_if_data *sdata;
-@@ -1201,8 +1435,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+@@ -1201,8 +1468,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
  		return TXRX_DROP;
  
  	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
@@ -895943,7 +958087,7 @@
  	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
  		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
  	else
-@@ -1294,7 +1528,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
+@@ -1294,7 +1561,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
  		goto ignore;
  	}
  
@@ -895952,7 +958096,7 @@
  		/*
  		 * APs with pairwise keys should never receive Michael MIC
  		 * errors for non-zero keyidx because these are reserved for
-@@ -1341,9 +1575,9 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
+@@ -1341,9 +1608,9 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
  	 * are not passed to user space by these functions
  	 */
  	ieee80211_rx_h_remove_qos_control,
@@ -895964,7 +958108,7 @@
  	ieee80211_rx_h_mgmt,
  	NULL
  };
-@@ -1356,7 +1590,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
+@@ -1356,7 +1623,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
  {
  	int multicast = is_multicast_ether_addr(hdr->addr1);
  
@@ -895973,7 +958117,7 @@
  	case IEEE80211_IF_TYPE_STA:
  		if (!bssid)
  			return 0;
-@@ -1427,11 +1661,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
+@@ -1427,11 +1694,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
  }
  
  /*
@@ -895991,7 +958135,7 @@
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct ieee80211_sub_if_data *sdata;
-@@ -1439,29 +1675,11 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1439,36 +1708,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  	struct ieee80211_hdr *hdr;
  	struct ieee80211_txrx_data rx;
  	u16 type;
@@ -896000,7 +958144,7 @@
  	struct ieee80211_sub_if_data *prev = NULL;
  	struct sk_buff *skb_new;
  	u8 *bssid;
--
+ 
 -	/*
 -	 * key references and virtual interfaces are protected using RCU
 -	 * and this requires that we are in a read-side RCU section during
@@ -896019,11 +958163,10 @@
 -		rcu_read_unlock();
 -		return;
 -	}
-+	int hdrlen;
- 
+-
  	hdr = (struct ieee80211_hdr *) skb->data;
  	memset(&rx, 0, sizeof(rx));
-@@ -1469,9 +1687,22 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ 	rx.skb = skb;
  	rx.local = local;
  
  	rx.u.rx.status = status;
@@ -896031,22 +958174,7 @@
  	rx.fc = le16_to_cpu(hdr->frame_control);
  	type = rx.fc & IEEE80211_FCTL_FTYPE;
  
-+	/*
-+	 * Drivers are required to align the payload data to a four-byte
-+	 * boundary, so the last two bits of the address where it starts
-+	 * may not be set. The header is required to be directly before
-+	 * the payload data, padding like atheros hardware adds which is
-+	 * inbetween the 802.11 header and the payload is not supported,
-+	 * the driver is required to move the 802.11 header further back
-+	 * in that case.
-+	 */
-+	hdrlen = ieee80211_get_hdrlen(rx.fc);
-+	WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3);
-+
- 	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
- 		local->dot11ReceivedFragmentCount++;
- 
-@@ -1486,7 +1717,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1486,7 +1737,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  		goto end;
  	}
  
@@ -896055,7 +958183,7 @@
  		rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
  
  	if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
-@@ -1501,25 +1732,23 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1501,25 +1752,23 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
  					     rx.sta);
  		sta_info_put(sta);
@@ -896085,7 +958213,7 @@
  			continue;
  
  		/*
-@@ -1547,6 +1776,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1547,6 +1796,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  				       prev->dev->name);
  			continue;
  		}
@@ -896093,7 +958221,7 @@
  		rx.skb = skb_new;
  		rx.dev = prev->dev;
  		rx.sdata = prev;
-@@ -1555,6 +1785,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1555,6 +1805,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  		prev = sdata;
  	}
  	if (prev) {
@@ -896101,7 +958229,7 @@
  		rx.skb = skb;
  		rx.dev = prev->dev;
  		rx.sdata = prev;
-@@ -1564,10 +1795,230 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1564,10 +1815,230 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
  		dev_kfree_skb(skb);
  
   end:
@@ -896112,7 +958240,7 @@
 +
 +#define SEQ_MODULO 0x1000
 +#define SEQ_MASK   0xfff
-+
+ 
 +static inline int seq_less(u16 sq1, u16 sq2)
 +{
 +	return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1));
@@ -896198,7 +958326,7 @@
 +		dev_kfree_skb(skb);
 +		return 1;
 +	}
- 
++
 +	/* if arrived mpdu is in the right order and nothing else stored */
 +	/* release it immediately */
 +	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
@@ -896263,7 +958391,7 @@
 +		goto end_reorder;
 +
 +	/* null data frames are excluded */
-+	if (unlikely(fc & IEEE80211_STYPE_QOS_NULLFUNC))
++	if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
 +		goto end_reorder;
 +
 +	/* new un-ordered ampdu frame - process it */
@@ -898398,19 +960526,474 @@
 +EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path);
 +#endif /* CONFIG_SYSCTL */
 diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
-index a4d5cde..078fff0 100644
+index a4d5cde..327e847 100644
 --- a/net/netfilter/nf_conntrack_core.c
 +++ b/net/netfilter/nf_conntrack_core.c
-@@ -81,7 +81,7 @@ static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
- 		   ((__force __u16)tuple->src.u.all << 16) |
- 		    (__force __u16)tuple->dst.u.all);
+@@ -40,7 +40,7 @@
+ 
+ #define NF_CONNTRACK_VERSION	"0.5.0"
  
+-DEFINE_RWLOCK(nf_conntrack_lock);
++DEFINE_SPINLOCK(nf_conntrack_lock);
+ EXPORT_SYMBOL_GPL(nf_conntrack_lock);
+ 
+ /* nf_conntrack_standalone needs this */
+@@ -73,15 +73,19 @@ static unsigned int nf_conntrack_hash_rnd;
+ static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
+ 				  unsigned int size, unsigned int rnd)
+ {
+-	unsigned int a, b;
+-
+-	a = jhash2(tuple->src.u3.all, ARRAY_SIZE(tuple->src.u3.all),
+-		   (tuple->src.l3num << 16) | tuple->dst.protonum);
+-	b = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
+-		   ((__force __u16)tuple->src.u.all << 16) |
+-		    (__force __u16)tuple->dst.u.all);
+-
 -	return jhash_2words(a, b, rnd) % size;
-+	return ((u64)jhash_2words(a, b, rnd) * size) >> 32;
++	unsigned int n;
++	u_int32_t h;
++
++	/* The direction must be ignored, so we hash everything up to the
++	 * destination ports (which is a multiple of 4) and treat the last
++	 * three bytes manually.
++	 */
++	n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32);
++	h = jhash2((u32 *)tuple, n,
++		   rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
++			  tuple->dst.protonum));
++
++	return ((u64)h * size) >> 32;
  }
  
  static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
-@@ -831,10 +831,8 @@ EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
+@@ -166,8 +170,8 @@ static void
+ clean_from_lists(struct nf_conn *ct)
+ {
+ 	pr_debug("clean_from_lists(%p)\n", ct);
+-	hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
+-	hlist_del(&ct->tuplehash[IP_CT_DIR_REPLY].hnode);
++	hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
++	hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode);
+ 
+ 	/* Destroy all pending expectations */
+ 	nf_ct_remove_expectations(ct);
+@@ -199,7 +203,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
+ 
+ 	rcu_read_unlock();
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	/* Expectations will have been removed in clean_from_lists,
+ 	 * except TFTP can create an expectation on the first packet,
+ 	 * before connection is in the list, so we need to clean here,
+@@ -213,7 +217,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
+ 	}
+ 
+ 	NF_CT_STAT_INC(delete);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 
+ 	if (ct->master)
+ 		nf_ct_put(ct->master);
+@@ -236,26 +240,24 @@ static void death_by_timeout(unsigned long ul_conntrack)
+ 		rcu_read_unlock();
+ 	}
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	/* Inside lock so preempt is disabled on module removal path.
+ 	 * Otherwise we can get spurious warnings. */
+ 	NF_CT_STAT_INC(delete_list);
+ 	clean_from_lists(ct);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	nf_ct_put(ct);
+ }
+ 
+ struct nf_conntrack_tuple_hash *
+-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
+-		    const struct nf_conn *ignored_conntrack)
++__nf_conntrack_find(const struct nf_conntrack_tuple *tuple)
+ {
+ 	struct nf_conntrack_tuple_hash *h;
+ 	struct hlist_node *n;
+ 	unsigned int hash = hash_conntrack(tuple);
+ 
+-	hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
+-		if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
+-		    nf_ct_tuple_equal(tuple, &h->tuple)) {
++	hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
++		if (nf_ct_tuple_equal(tuple, &h->tuple)) {
+ 			NF_CT_STAT_INC(found);
+ 			return h;
+ 		}
+@@ -271,12 +273,16 @@ struct nf_conntrack_tuple_hash *
+ nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple)
+ {
+ 	struct nf_conntrack_tuple_hash *h;
++	struct nf_conn *ct;
+ 
+-	read_lock_bh(&nf_conntrack_lock);
+-	h = __nf_conntrack_find(tuple, NULL);
+-	if (h)
+-		atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
++	h = __nf_conntrack_find(tuple);
++	if (h) {
++		ct = nf_ct_tuplehash_to_ctrack(h);
++		if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
++			h = NULL;
++	}
++	rcu_read_unlock();
+ 
+ 	return h;
+ }
+@@ -286,10 +292,10 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct,
+ 				       unsigned int hash,
+ 				       unsigned int repl_hash)
+ {
+-	hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+-		       &nf_conntrack_hash[hash]);
+-	hlist_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
+-		       &nf_conntrack_hash[repl_hash]);
++	hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
++			   &nf_conntrack_hash[hash]);
++	hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
++			   &nf_conntrack_hash[repl_hash]);
+ }
+ 
+ void nf_conntrack_hash_insert(struct nf_conn *ct)
+@@ -299,9 +305,9 @@ void nf_conntrack_hash_insert(struct nf_conn *ct)
+ 	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ 	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	__nf_conntrack_hash_insert(ct, hash, repl_hash);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert);
+ 
+@@ -338,7 +344,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
+ 	NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
+ 	pr_debug("Confirming conntrack %p\n", ct);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 
+ 	/* See if there's one in the list already, including reverse:
+ 	   NAT could have grabbed it without realizing, since we're
+@@ -364,7 +370,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
+ 	atomic_inc(&ct->ct_general.use);
+ 	set_bit(IPS_CONFIRMED_BIT, &ct->status);
+ 	NF_CT_STAT_INC(insert);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	help = nfct_help(ct);
+ 	if (help && help->helper)
+ 		nf_conntrack_event_cache(IPCT_HELPER, skb);
+@@ -379,7 +385,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
+ 
+ out:
+ 	NF_CT_STAT_INC(insert_failed);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	return NF_DROP;
+ }
+ EXPORT_SYMBOL_GPL(__nf_conntrack_confirm);
+@@ -391,12 +397,22 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
+ 			 const struct nf_conn *ignored_conntrack)
+ {
+ 	struct nf_conntrack_tuple_hash *h;
++	struct hlist_node *n;
++	unsigned int hash = hash_conntrack(tuple);
+ 
+-	read_lock_bh(&nf_conntrack_lock);
+-	h = __nf_conntrack_find(tuple, ignored_conntrack);
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
++	hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
++		if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
++		    nf_ct_tuple_equal(tuple, &h->tuple)) {
++			NF_CT_STAT_INC(found);
++			rcu_read_unlock();
++			return 1;
++		}
++		NF_CT_STAT_INC(searched);
++	}
++	rcu_read_unlock();
+ 
+-	return h != NULL;
++	return 0;
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
+ 
+@@ -404,7 +420,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
+ 
+ /* There's a small race here where we may free a just-assured
+    connection.  Too bad: we're in trouble anyway. */
+-static int early_drop(unsigned int hash)
++static noinline int early_drop(unsigned int hash)
+ {
+ 	/* Use oldest entry, which is roughly LRU */
+ 	struct nf_conntrack_tuple_hash *h;
+@@ -413,21 +429,23 @@ static int early_drop(unsigned int hash)
+ 	unsigned int i, cnt = 0;
+ 	int dropped = 0;
+ 
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	for (i = 0; i < nf_conntrack_htable_size; i++) {
+-		hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
++		hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash],
++					 hnode) {
+ 			tmp = nf_ct_tuplehash_to_ctrack(h);
+ 			if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
+ 				ct = tmp;
+ 			cnt++;
+ 		}
++
++		if (ct && unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
++			ct = NULL;
+ 		if (ct || cnt >= NF_CT_EVICTION_RANGE)
+ 			break;
+ 		hash = (hash + 1) % nf_conntrack_htable_size;
+ 	}
+-	if (ct)
+-		atomic_inc(&ct->ct_general.use);
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ 
+ 	if (!ct)
+ 		return dropped;
+@@ -444,7 +462,7 @@ static int early_drop(unsigned int hash)
+ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+ 				   const struct nf_conntrack_tuple *repl)
+ {
+-	struct nf_conn *conntrack = NULL;
++	struct nf_conn *ct = NULL;
+ 
+ 	if (unlikely(!nf_conntrack_hash_rnd_initted)) {
+ 		get_random_bytes(&nf_conntrack_hash_rnd, 4);
+@@ -454,8 +472,8 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+ 	/* We don't want any race condition at early drop stage */
+ 	atomic_inc(&nf_conntrack_count);
+ 
+-	if (nf_conntrack_max
+-	    && atomic_read(&nf_conntrack_count) > nf_conntrack_max) {
++	if (nf_conntrack_max &&
++	    unlikely(atomic_read(&nf_conntrack_count) > nf_conntrack_max)) {
+ 		unsigned int hash = hash_conntrack(orig);
+ 		if (!early_drop(hash)) {
+ 			atomic_dec(&nf_conntrack_count);
+@@ -467,30 +485,37 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+ 		}
+ 	}
+ 
+-	conntrack = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC);
+-	if (conntrack == NULL) {
++	ct = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC);
++	if (ct == NULL) {
+ 		pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
+ 		atomic_dec(&nf_conntrack_count);
+ 		return ERR_PTR(-ENOMEM);
+ 	}
+ 
+-	atomic_set(&conntrack->ct_general.use, 1);
+-	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+-	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
++	atomic_set(&ct->ct_general.use, 1);
++	ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
++	ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
+ 	/* Don't set timer yet: wait for confirmation */
+-	setup_timer(&conntrack->timeout, death_by_timeout,
+-		    (unsigned long)conntrack);
++	setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
++	INIT_RCU_HEAD(&ct->rcu);
+ 
+-	return conntrack;
++	return ct;
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
+ 
+-void nf_conntrack_free(struct nf_conn *conntrack)
++static void nf_conntrack_free_rcu(struct rcu_head *head)
+ {
+-	nf_ct_ext_free(conntrack);
+-	kmem_cache_free(nf_conntrack_cachep, conntrack);
++	struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
++
++	nf_ct_ext_free(ct);
++	kmem_cache_free(nf_conntrack_cachep, ct);
+ 	atomic_dec(&nf_conntrack_count);
+ }
++
++void nf_conntrack_free(struct nf_conn *ct)
++{
++	call_rcu(&ct->rcu, nf_conntrack_free_rcu);
++}
+ EXPORT_SYMBOL_GPL(nf_conntrack_free);
+ 
+ /* Allocate a new conntrack: we return -ENOMEM if classification
+@@ -502,7 +527,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
+ 	       struct sk_buff *skb,
+ 	       unsigned int dataoff)
+ {
+-	struct nf_conn *conntrack;
++	struct nf_conn *ct;
+ 	struct nf_conn_help *help;
+ 	struct nf_conntrack_tuple repl_tuple;
+ 	struct nf_conntrack_expect *exp;
+@@ -512,46 +537,46 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
+ 		return NULL;
+ 	}
+ 
+-	conntrack = nf_conntrack_alloc(tuple, &repl_tuple);
+-	if (conntrack == NULL || IS_ERR(conntrack)) {
++	ct = nf_conntrack_alloc(tuple, &repl_tuple);
++	if (ct == NULL || IS_ERR(ct)) {
+ 		pr_debug("Can't allocate conntrack.\n");
+-		return (struct nf_conntrack_tuple_hash *)conntrack;
++		return (struct nf_conntrack_tuple_hash *)ct;
+ 	}
+ 
+-	if (!l4proto->new(conntrack, skb, dataoff)) {
+-		nf_conntrack_free(conntrack);
++	if (!l4proto->new(ct, skb, dataoff)) {
++		nf_conntrack_free(ct);
+ 		pr_debug("init conntrack: can't track with proto module\n");
+ 		return NULL;
+ 	}
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	exp = nf_ct_find_expectation(tuple);
+ 	if (exp) {
+ 		pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
+-			 conntrack, exp);
++			 ct, exp);
+ 		/* Welcome, Mr. Bond.  We've been expecting you... */
+-		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+-		conntrack->master = exp->master;
++		__set_bit(IPS_EXPECTED_BIT, &ct->status);
++		ct->master = exp->master;
+ 		if (exp->helper) {
+-			help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
++			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+ 			if (help)
+ 				rcu_assign_pointer(help->helper, exp->helper);
+ 		}
+ 
+ #ifdef CONFIG_NF_CONNTRACK_MARK
+-		conntrack->mark = exp->master->mark;
++		ct->mark = exp->master->mark;
+ #endif
+ #ifdef CONFIG_NF_CONNTRACK_SECMARK
+-		conntrack->secmark = exp->master->secmark;
++		ct->secmark = exp->master->secmark;
+ #endif
+-		nf_conntrack_get(&conntrack->master->ct_general);
++		nf_conntrack_get(&ct->master->ct_general);
+ 		NF_CT_STAT_INC(expect_new);
+ 	} else {
+ 		struct nf_conntrack_helper *helper;
+ 
+ 		helper = __nf_ct_helper_find(&repl_tuple);
+ 		if (helper) {
+-			help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
++			help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+ 			if (help)
+ 				rcu_assign_pointer(help->helper, helper);
+ 		}
+@@ -559,18 +584,17 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
+ 	}
+ 
+ 	/* Overload tuple linked list to put us in unconfirmed list. */
+-	hlist_add_head(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+-		       &unconfirmed);
++	hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, &unconfirmed);
+ 
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 
+ 	if (exp) {
+ 		if (exp->expectfn)
+-			exp->expectfn(conntrack, exp);
++			exp->expectfn(ct, exp);
+ 		nf_ct_expect_put(exp);
+ 	}
+ 
+-	return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
++	return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
+ }
+ 
+ /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+@@ -729,7 +753,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
+ 	struct nf_conn_help *help = nfct_help(ct);
+ 	struct nf_conntrack_helper *helper;
+ 
+-	write_lock_bh(&nf_conntrack_lock);
+ 	/* Should be unconfirmed, so not in hash table yet */
+ 	NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
+ 
+@@ -738,8 +761,9 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
+ 
+ 	ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
+ 	if (ct->master || (help && help->expecting != 0))
+-		goto out;
++		return;
+ 
++	rcu_read_lock();
+ 	helper = __nf_ct_helper_find(newreply);
+ 	if (helper == NULL) {
+ 		if (help)
+@@ -757,7 +781,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
+ 
+ 	rcu_assign_pointer(help->helper, helper);
+ out:
+-	write_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
+ 
+@@ -773,13 +797,11 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
+ 	NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
+ 	NF_CT_ASSERT(skb);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 
+ 	/* Only update if this is not a fixed timeout */
+-	if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
+-		write_unlock_bh(&nf_conntrack_lock);
+-		return;
+-	}
++	if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status))
++		goto acct;
+ 
+ 	/* If not in hash table, timer will not be active yet */
+ 	if (!nf_ct_is_confirmed(ct)) {
+@@ -799,6 +821,7 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
+ 		}
+ 	}
+ 
++acct:
+ #ifdef CONFIG_NF_CT_ACCT
+ 	if (do_acct) {
+ 		ct->counters[CTINFO2DIR(ctinfo)].packets++;
+@@ -811,7 +834,7 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
+ 	}
+ #endif
+ 
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 
+ 	/* must be unlocked when calling event cache */
+ 	if (event)
+@@ -831,10 +854,8 @@ EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
  int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
  			       const struct nf_conntrack_tuple *tuple)
  {
@@ -898423,7 +961006,7 @@
  	return 0;
  
  nla_put_failure:
-@@ -854,8 +852,8 @@ int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[],
+@@ -854,8 +875,8 @@ int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[],
  	if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT])
  		return -EINVAL;
  
@@ -898434,7 +961017,7 @@
  
  	return 0;
  }
-@@ -863,7 +861,7 @@ EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple);
+@@ -863,7 +884,7 @@ EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple);
  #endif
  
  /* Used by ipt_REJECT and ip6t_REJECT. */
@@ -898443,15 +961026,113 @@
  {
  	struct nf_conn *ct;
  	enum ip_conntrack_info ctinfo;
-@@ -880,7 +878,6 @@ void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
+@@ -880,15 +901,6 @@ void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
  	nskb->nfctinfo = ctinfo;
  	nf_conntrack_get(nskb->nfct);
  }
 -EXPORT_SYMBOL_GPL(__nf_conntrack_attach);
+-
+-static inline int
+-do_iter(const struct nf_conntrack_tuple_hash *i,
+-	int (*iter)(struct nf_conn *i, void *data),
+-	void *data)
+-{
+-	return iter(nf_ct_tuplehash_to_ctrack(i), data);
+-}
  
- static inline int
- do_iter(const struct nf_conntrack_tuple_hash *i,
-@@ -1124,7 +1121,7 @@ int __init nf_conntrack_init(void)
+ /* Bring out ya dead! */
+ static struct nf_conn *
+@@ -899,7 +911,7 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
+ 	struct nf_conn *ct;
+ 	struct hlist_node *n;
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
+ 		hlist_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnode) {
+ 			ct = nf_ct_tuplehash_to_ctrack(h);
+@@ -912,11 +924,11 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
+ 		if (iter(ct, data))
+ 			set_bit(IPS_DYING_BIT, &ct->status);
+ 	}
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	return NULL;
+ found:
+ 	atomic_inc(&ct->ct_general.use);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	return ct;
+ }
+ 
+@@ -942,7 +954,7 @@ static int kill_all(struct nf_conn *i, void *data)
+ 	return 1;
+ }
+ 
+-void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, int size)
++void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int size)
+ {
+ 	if (vmalloced)
+ 		vfree(hash);
+@@ -991,7 +1003,7 @@ void nf_conntrack_cleanup(void)
+ 	nf_conntrack_expect_fini();
+ }
+ 
+-struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced)
++struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced)
+ {
+ 	struct hlist_head *hash;
+ 	unsigned int size, i;
+@@ -1018,8 +1030,8 @@ EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
+ 
+ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
+ {
+-	int i, bucket, hashsize, vmalloced;
+-	int old_vmalloced, old_size;
++	int i, bucket, vmalloced, old_vmalloced;
++	unsigned int hashsize, old_size;
+ 	int rnd;
+ 	struct hlist_head *hash, *old_hash;
+ 	struct nf_conntrack_tuple_hash *h;
+@@ -1028,7 +1040,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
+ 	if (!nf_conntrack_htable_size)
+ 		return param_set_uint(val, kp);
+ 
+-	hashsize = simple_strtol(val, NULL, 0);
++	hashsize = simple_strtoul(val, NULL, 0);
+ 	if (!hashsize)
+ 		return -EINVAL;
+ 
+@@ -1040,12 +1052,17 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
+ 	 * use a newrandom seed */
+ 	get_random_bytes(&rnd, 4);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	/* Lookups in the old hash might happen in parallel, which means we
++	 * might get false negatives during connection lookup. New connections
++	 * created because of a false negative won't make it into the hash
++	 * though since that required taking the lock.
++	 */
++	spin_lock_bh(&nf_conntrack_lock);
+ 	for (i = 0; i < nf_conntrack_htable_size; i++) {
+ 		while (!hlist_empty(&nf_conntrack_hash[i])) {
+ 			h = hlist_entry(nf_conntrack_hash[i].first,
+ 					struct nf_conntrack_tuple_hash, hnode);
+-			hlist_del(&h->hnode);
++			hlist_del_rcu(&h->hnode);
+ 			bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
+ 			hlist_add_head(&h->hnode, &hash[bucket]);
+ 		}
+@@ -1058,7 +1075,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
+ 	nf_conntrack_vmalloc = vmalloced;
+ 	nf_conntrack_hash = hash;
+ 	nf_conntrack_hash_rnd = rnd;
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 
+ 	nf_ct_free_hashtable(old_hash, old_vmalloced, old_size);
+ 	return 0;
+@@ -1124,7 +1141,7 @@ int __init nf_conntrack_init(void)
  		goto out_fini_expect;
  
  	/* For use by REJECT target */
@@ -898461,10 +961142,29 @@
  
  	/* Set up fake conntrack:
 diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
-index 175c8d1..e0cd9d0 100644
+index 175c8d1..e06bf00 100644
 --- a/net/netfilter/nf_conntrack_expect.c
 +++ b/net/netfilter/nf_conntrack_expect.c
-@@ -73,15 +73,17 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect)
+@@ -50,7 +50,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
+ 	NF_CT_ASSERT(master_help);
+ 	NF_CT_ASSERT(!timer_pending(&exp->timeout));
+ 
+-	hlist_del(&exp->hnode);
++	hlist_del_rcu(&exp->hnode);
+ 	nf_ct_expect_count--;
+ 
+ 	hlist_del(&exp->lnode);
+@@ -65,23 +65,25 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect)
+ {
+ 	struct nf_conntrack_expect *exp = (void *)ul_expect;
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	nf_ct_unlink_expect(exp);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	nf_ct_expect_put(exp);
+ }
  
  static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple)
  {
@@ -898485,7 +961185,53 @@
  }
  
  struct nf_conntrack_expect *
-@@ -226,8 +228,8 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+@@ -95,7 +97,7 @@ __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
+ 		return NULL;
+ 
+ 	h = nf_ct_expect_dst_hash(tuple);
+-	hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
++	hlist_for_each_entry_rcu(i, n, &nf_ct_expect_hash[h], hnode) {
+ 		if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
+ 			return i;
+ 	}
+@@ -109,11 +111,11 @@ nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
+ {
+ 	struct nf_conntrack_expect *i;
+ 
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	i = __nf_ct_expect_find(tuple);
+-	if (i)
+-		atomic_inc(&i->use);
+-	read_unlock_bh(&nf_conntrack_lock);
++	if (i && !atomic_inc_not_zero(&i->use))
++		i = NULL;
++	rcu_read_unlock();
+ 
+ 	return i;
+ }
+@@ -199,12 +201,12 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
+ /* Generally a bad idea to call this: could have matched already. */
+ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
+ {
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	if (del_timer(&exp->timeout)) {
+ 		nf_ct_unlink_expect(exp);
+ 		nf_ct_expect_put(exp);
+ 	}
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
+ 
+@@ -221,13 +223,14 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
+ 
+ 	new->master = me;
+ 	atomic_set(&new->use, 1);
++	INIT_RCU_HEAD(&new->rcu);
+ 	return new;
+ }
  EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
  
  void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
@@ -898496,6 +961242,104 @@
  		       u_int8_t proto, __be16 *src, __be16 *dst)
  {
  	int len;
+@@ -276,10 +279,18 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_init);
+ 
++static void nf_ct_expect_free_rcu(struct rcu_head *head)
++{
++	struct nf_conntrack_expect *exp;
++
++	exp = container_of(head, struct nf_conntrack_expect, rcu);
++	kmem_cache_free(nf_ct_expect_cachep, exp);
++}
++
+ void nf_ct_expect_put(struct nf_conntrack_expect *exp)
+ {
+ 	if (atomic_dec_and_test(&exp->use))
+-		kmem_cache_free(nf_ct_expect_cachep, exp);
++		call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_put);
+ 
+@@ -293,7 +304,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
+ 	hlist_add_head(&exp->lnode, &master_help->expectations);
+ 	master_help->expecting++;
+ 
+-	hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]);
++	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
+ 	nf_ct_expect_count++;
+ 
+ 	setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
+@@ -344,7 +355,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
+ 
+ 	NF_CT_ASSERT(master_help);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	if (!master_help->helper) {
+ 		ret = -ESHUTDOWN;
+ 		goto out;
+@@ -379,7 +390,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
+ 	nf_ct_expect_event(IPEXP_NEW, expect);
+ 	ret = 0;
+ out:
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	return ret;
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_expect_related);
+@@ -392,10 +403,12 @@ struct ct_expect_iter_state {
+ static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
+ {
+ 	struct ct_expect_iter_state *st = seq->private;
++	struct hlist_node *n;
+ 
+ 	for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
+-		if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
+-			return nf_ct_expect_hash[st->bucket].first;
++		n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
++		if (n)
++			return n;
+ 	}
+ 	return NULL;
+ }
+@@ -405,11 +418,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
+ {
+ 	struct ct_expect_iter_state *st = seq->private;
+ 
+-	head = head->next;
++	head = rcu_dereference(head->next);
+ 	while (head == NULL) {
+ 		if (++st->bucket >= nf_ct_expect_hsize)
+ 			return NULL;
+-		head = nf_ct_expect_hash[st->bucket].first;
++		head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+ 	}
+ 	return head;
+ }
+@@ -425,8 +438,9 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
+ }
+ 
+ static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(RCU)
+ {
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	return ct_expect_get_idx(seq, *pos);
+ }
+ 
+@@ -437,8 +451,9 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ }
+ 
+ static void exp_seq_stop(struct seq_file *seq, void *v)
++	__releases(RCU)
+ {
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ }
+ 
+ static int exp_seq_show(struct seq_file *s, void *v)
 diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
 index 6df2590..6770baf 100644
 --- a/net/netfilter/nf_conntrack_ftp.c
@@ -898510,10 +961354,24 @@
  	unsigned int i;
  	int found = 0, ends_in_nl;
 diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c
-index a869403..ff66fba 100644
+index a869403..8678823 100644
 --- a/net/netfilter/nf_conntrack_h323_asn1.c
 +++ b/net/netfilter/nf_conntrack_h323_asn1.c
-@@ -100,10 +100,10 @@ typedef struct {
+@@ -87,7 +87,7 @@ typedef struct field_t {
+ 	unsigned char ub;
+ 	unsigned short attr;
+ 	unsigned short offset;
+-	struct field_t *fields;
++	const struct field_t *fields;
+ } field_t;
+ 
+ /* Bit Stream */
+@@ -96,37 +96,37 @@ typedef struct {
+ 	unsigned char *beg;
+ 	unsigned char *end;
+ 	unsigned char *cur;
+-	unsigned bit;
++	unsigned int bit;
  } bitstr_t;
  
  /* Tool Functions */
@@ -898521,15 +961379,394 @@
 -#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;}
 -#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;}
 -#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND)
+-static unsigned get_len(bitstr_t * bs);
+-static unsigned get_bit(bitstr_t * bs);
+-static unsigned get_bits(bitstr_t * bs, unsigned b);
+-static unsigned get_bitmap(bitstr_t * bs, unsigned b);
+-static unsigned get_uint(bitstr_t * bs, int b);
 +#define INC_BIT(bs) if((++(bs)->bit)>7){(bs)->cur++;(bs)->bit=0;}
 +#define INC_BITS(bs,b) if(((bs)->bit+=(b))>7){(bs)->cur+=(bs)->bit>>3;(bs)->bit&=7;}
 +#define BYTE_ALIGN(bs) if((bs)->bit){(bs)->cur++;(bs)->bit=0;}
 +#define CHECK_BOUND(bs,n) if((bs)->cur+(n)>(bs)->end)return(H323_ERROR_BOUND)
- static unsigned get_len(bitstr_t * bs);
- static unsigned get_bit(bitstr_t * bs);
- static unsigned get_bits(bitstr_t * bs, unsigned b);
++static unsigned int get_len(bitstr_t *bs);
++static unsigned int get_bit(bitstr_t *bs);
++static unsigned int get_bits(bitstr_t *bs, unsigned int b);
++static unsigned int get_bitmap(bitstr_t *bs, unsigned int b);
++static unsigned int get_uint(bitstr_t *bs, int b);
+ 
+ /* Decoder Functions */
+-static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_int(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level);
+-static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level);
++static int decode_nul(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_bool(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_oid(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_int(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_enum(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_bitstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_numstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_octstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_bmpstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_seq(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_seqof(bitstr_t *bs, const struct field_t *f, char *base, int level);
++static int decode_choice(bitstr_t *bs, const struct field_t *f, char *base, int level);
+ 
+ /* Decoder Functions Vector */
+-typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int);
+-static decoder_t Decoders[] = {
++typedef int (*decoder_t)(bitstr_t *, const struct field_t *, char *, int);
++static const decoder_t Decoders[] = {
+ 	decode_nul,
+ 	decode_bool,
+ 	decode_oid,
+@@ -150,9 +150,9 @@ static decoder_t Decoders[] = {
+  * Functions
+  ****************************************************************************/
+ /* Assume bs is aligned && v < 16384 */
+-unsigned get_len(bitstr_t * bs)
++static unsigned int get_len(bitstr_t *bs)
+ {
+-	unsigned v;
++	unsigned int v;
+ 
+ 	v = *bs->cur++;
+ 
+@@ -166,9 +166,9 @@ unsigned get_len(bitstr_t * bs)
+ }
+ 
+ /****************************************************************************/
+-unsigned get_bit(bitstr_t * bs)
++static unsigned int get_bit(bitstr_t *bs)
+ {
+-	unsigned b = (*bs->cur) & (0x80 >> bs->bit);
++	unsigned int b = (*bs->cur) & (0x80 >> bs->bit);
+ 
+ 	INC_BIT(bs);
+ 
+@@ -177,9 +177,9 @@ unsigned get_bit(bitstr_t * bs)
+ 
+ /****************************************************************************/
+ /* Assume b <= 8 */
+-unsigned get_bits(bitstr_t * bs, unsigned b)
++static unsigned int get_bits(bitstr_t *bs, unsigned int b)
+ {
+-	unsigned v, l;
++	unsigned int v, l;
+ 
+ 	v = (*bs->cur) & (0xffU >> bs->bit);
+ 	l = b + bs->bit;
+@@ -203,9 +203,9 @@ unsigned get_bits(bitstr_t * bs, unsigned b)
+ 
+ /****************************************************************************/
+ /* Assume b <= 32 */
+-unsigned get_bitmap(bitstr_t * bs, unsigned b)
++static unsigned int get_bitmap(bitstr_t *bs, unsigned int b)
+ {
+-	unsigned v, l, shift, bytes;
++	unsigned int v, l, shift, bytes;
+ 
+ 	if (!b)
+ 		return 0;
+@@ -213,18 +213,18 @@ unsigned get_bitmap(bitstr_t * bs, unsigned b)
+ 	l = bs->bit + b;
+ 
+ 	if (l < 8) {
+-		v = (unsigned) (*bs->cur) << (bs->bit + 24);
++		v = (unsigned int)(*bs->cur) << (bs->bit + 24);
+ 		bs->bit = l;
+ 	} else if (l == 8) {
+-		v = (unsigned) (*bs->cur++) << (bs->bit + 24);
++		v = (unsigned int)(*bs->cur++) << (bs->bit + 24);
+ 		bs->bit = 0;
+ 	} else {
+ 		for (bytes = l >> 3, shift = 24, v = 0; bytes;
+ 		     bytes--, shift -= 8)
+-			v |= (unsigned) (*bs->cur++) << shift;
++			v |= (unsigned int)(*bs->cur++) << shift;
+ 
+ 		if (l < 32) {
+-			v |= (unsigned) (*bs->cur) << shift;
++			v |= (unsigned int)(*bs->cur) << shift;
+ 			v <<= bs->bit;
+ 		} else if (l > 32) {
+ 			v <<= bs->bit;
+@@ -242,9 +242,9 @@ unsigned get_bitmap(bitstr_t * bs, unsigned b)
+ /****************************************************************************
+  * Assume bs is aligned and sizeof(unsigned int) == 4
+  ****************************************************************************/
+-unsigned get_uint(bitstr_t * bs, int b)
++static unsigned int get_uint(bitstr_t *bs, int b)
+ {
+-	unsigned v = 0;
++	unsigned int v = 0;
+ 
+ 	switch (b) {
+ 	case 4:
+@@ -264,7 +264,8 @@ unsigned get_uint(bitstr_t * bs, int b)
+ }
+ 
+ /****************************************************************************/
+-int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_nul(bitstr_t *bs, const struct field_t *f,
++                      char *base, int level)
+ {
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -272,7 +273,8 @@ int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_bool(bitstr_t *bs, const struct field_t *f,
++                       char *base, int level)
+ {
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -283,7 +285,8 @@ int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_oid(bitstr_t *bs, const struct field_t *f,
++                      char *base, int level)
+ {
+ 	int len;
+ 
+@@ -299,9 +302,10 @@ int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_int(bitstr_t *bs, const struct field_t *f,
++                      char *base, int level)
+ {
+-	unsigned len;
++	unsigned int len;
+ 
+ 	PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
+ 
+@@ -318,9 +322,9 @@ int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
+ 		len = get_bits(bs, 2) + 1;
+ 		BYTE_ALIGN(bs);
+ 		if (base && (f->attr & DECODE)) {	/* timeToLive */
+-			unsigned v = get_uint(bs, len) + f->lb;
++			unsigned int v = get_uint(bs, len) + f->lb;
+ 			PRINT(" = %u", v);
+-			*((unsigned *) (base + f->offset)) = v;
++			*((unsigned int *)(base + f->offset)) = v;
+ 		}
+ 		bs->cur += len;
+ 		break;
+@@ -342,7 +346,8 @@ int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_enum(bitstr_t *bs, const struct field_t *f,
++                       char *base, int level)
+ {
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -357,9 +362,10 @@ int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_bitstr(bitstr_t *bs, const struct field_t *f,
++                         char *base, int level)
+ {
+-	unsigned len;
++	unsigned int len;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -390,9 +396,10 @@ int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_numstr(bitstr_t *bs, const struct field_t *f,
++                         char *base, int level)
+ {
+-	unsigned len;
++	unsigned int len;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -407,9 +414,10 @@ int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_octstr(bitstr_t *bs, const struct field_t *f,
++                         char *base, int level)
+ {
+-	unsigned len;
++	unsigned int len;
+ 
+ 	PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
+ 
+@@ -424,7 +432,7 @@ int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
+ 					     bs->cur[0], bs->cur[1],
+ 					     bs->cur[2], bs->cur[3],
+ 					     bs->cur[4] * 256 + bs->cur[5]));
+-				*((unsigned *) (base + f->offset)) =
++				*((unsigned int *)(base + f->offset)) =
+ 				    bs->cur - bs->buf;
+ 			}
+ 		}
+@@ -455,9 +463,10 @@ int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_bmpstr(bitstr_t *bs, const struct field_t *f,
++                         char *base, int level)
+ {
+-	unsigned len;
++	unsigned int len;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+ 
+@@ -480,11 +489,12 @@ int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_seq(bitstr_t *bs, const struct field_t *f,
++                      char *base, int level)
+ {
+-	unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
++	unsigned int ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
+ 	int err;
+-	field_t *son;
++	const struct field_t *son;
+ 	unsigned char *beg = NULL;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+@@ -498,7 +508,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
+ 	/* Get fields bitmap */
+ 	bmp = get_bitmap(bs, f->sz);
+ 	if (base)
+-		*(unsigned *) base = bmp;
++		*(unsigned int *)base = bmp;
+ 
+ 	/* Decode the root components */
+ 	for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
+@@ -550,7 +560,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
+ 	bmp2 = get_bitmap(bs, bmp2_len);
+ 	bmp |= bmp2 >> f->sz;
+ 	if (base)
+-		*(unsigned *) base = bmp;
++		*(unsigned int *)base = bmp;
+ 	BYTE_ALIGN(bs);
+ 
+ 	/* Decode the extension components */
+@@ -596,11 +606,12 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_seqof(bitstr_t *bs, const struct field_t *f,
++                        char *base, int level)
+ {
+-	unsigned count, effective_count = 0, i, len = 0;
++	unsigned int count, effective_count = 0, i, len = 0;
+ 	int err;
+-	field_t *son;
++	const struct field_t *son;
+ 	unsigned char *beg = NULL;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+@@ -636,8 +647,8 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
+ 	/* Write Count */
+ 	if (base) {
+ 		effective_count = count > f->ub ? f->ub : count;
+-		*(unsigned *) base = effective_count;
+-		base += sizeof(unsigned);
++		*(unsigned int *)base = effective_count;
++		base += sizeof(unsigned int);
+ 	}
+ 
+ 	/* Decode nested field */
+@@ -685,11 +696,12 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
+ 
+ 
+ /****************************************************************************/
+-int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
++static int decode_choice(bitstr_t *bs, const struct field_t *f,
++                         char *base, int level)
+ {
+-	unsigned type, ext, len = 0;
++	unsigned int type, ext, len = 0;
+ 	int err;
+-	field_t *son;
++	const struct field_t *son;
+ 	unsigned char *beg = NULL;
+ 
+ 	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
+@@ -710,7 +722,7 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
+ 
+ 	/* Write Type */
+ 	if (base)
+-		*(unsigned *) base = type;
++		*(unsigned int *)base = type;
+ 
+ 	/* Check Range */
+ 	if (type >= f->ub) {	/* Newer version? */
+@@ -754,9 +766,9 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
+ }
+ 
+ /****************************************************************************/
+-int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
++int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras)
+ {
+-	static field_t ras_message = {
++	static const struct field_t ras_message = {
+ 		FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
+ 		0, _RasMessage
+ 	};
+@@ -771,9 +783,9 @@ int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
+ 
+ /****************************************************************************/
+ static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
+-				      size_t sz, H323_UserInformation * uuie)
++				      size_t sz, H323_UserInformation *uuie)
+ {
+-	static field_t h323_userinformation = {
++	static const struct field_t h323_userinformation = {
+ 		FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
+ 		0, _H323_UserInformation
+ 	};
+@@ -792,7 +804,7 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
+ 					 MultimediaSystemControlMessage *
+ 					 mscm)
+ {
+-	static field_t multimediasystemcontrolmessage = {
++	static const struct field_t multimediasystemcontrolmessage = {
+ 		FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
+ 		DECODE | EXT, 0, _MultimediaSystemControlMessage
+ 	};
+@@ -807,7 +819,7 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
+ }
+ 
+ /****************************************************************************/
+-int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931)
++int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
+ {
+ 	unsigned char *p = buf;
+ 	int len;
 diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
-index f23fd95..872c1aa 100644
+index f23fd95..6213787 100644
 --- a/net/netfilter/nf_conntrack_h323_main.c
 +++ b/net/netfilter/nf_conntrack_h323_main.c
 @@ -50,12 +50,12 @@ MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "
@@ -898547,16 +961784,32 @@
  			   __read_mostly;
  int (*set_sig_addr_hook) (struct sk_buff *skb,
  			  struct nf_conn *ct,
-@@ -214,7 +214,7 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
+@@ -114,7 +114,8 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
+ {
+ 	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+ 	int dir = CTINFO2DIR(ctinfo);
+-	struct tcphdr _tcph, *th;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
+ 	int tcpdatalen;
+ 	int tcpdataoff;
+ 	unsigned char *tpkt;
+@@ -212,11 +213,11 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
+ }
+ 
  /****************************************************************************/
- static int get_h245_addr(struct nf_conn *ct, unsigned char *data,
+-static int get_h245_addr(struct nf_conn *ct, unsigned char *data,
++static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
  			 H245_TransportAddress *taddr,
 -			 union nf_conntrack_address *addr, __be16 *port)
 +			 union nf_inet_addr *addr, __be16 *port)
  {
- 	unsigned char *p;
+-	unsigned char *p;
++	const unsigned char *p;
  	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
-@@ -257,7 +257,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
+ 	int len;
+ 
+@@ -257,7 +258,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
  	int ret = 0;
  	__be16 port;
  	__be16 rtp_port, rtcp_port;
@@ -898565,7 +961818,7 @@
  	struct nf_conntrack_expect *rtp_exp;
  	struct nf_conntrack_expect *rtcp_exp;
  	typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
-@@ -330,7 +330,7 @@ static int expect_t120(struct sk_buff *skb,
+@@ -330,7 +331,7 @@ static int expect_t120(struct sk_buff *skb,
  	int dir = CTINFO2DIR(ctinfo);
  	int ret = 0;
  	__be16 port;
@@ -898574,16 +961827,19 @@
  	struct nf_conntrack_expect *exp;
  	typeof(nat_t120_hook) nat_t120;
  
-@@ -623,7 +623,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
+@@ -623,9 +624,9 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
  /****************************************************************************/
  int get_h225_addr(struct nf_conn *ct, unsigned char *data,
  		  TransportAddress *taddr,
 -		  union nf_conntrack_address *addr, __be16 *port)
 +		  union nf_inet_addr *addr, __be16 *port)
  {
- 	unsigned char *p;
+-	unsigned char *p;
++	const unsigned char *p;
  	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
-@@ -662,7 +662,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+ 	int len;
+ 
+@@ -662,7 +663,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
  	int dir = CTINFO2DIR(ctinfo);
  	int ret = 0;
  	__be16 port;
@@ -898592,15 +961848,15 @@
  	struct nf_conntrack_expect *exp;
  	typeof(nat_h245_hook) nat_h245;
  
-@@ -704,13 +704,19 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
+@@ -704,13 +705,18 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
  
  /* If the calling party is on the same side of the forward-to party,
   * we don't need to track the second call */
 -static int callforward_do_filter(union nf_conntrack_address *src,
 -				 union nf_conntrack_address *dst,
-+static int callforward_do_filter(union nf_inet_addr *src,
-+				 union nf_inet_addr *dst,
- 				 int family)
+-				 int family)
++static int callforward_do_filter(const union nf_inet_addr *src,
++                                 const union nf_inet_addr *dst, int family)
  {
 +	const struct nf_afinfo *afinfo;
  	struct flowi fl1, fl2;
@@ -898664,7 +961920,17 @@
  	typeof(set_h225_addr_hook) set_h225_addr;
  
  	pr_debug("nf_ct_q931: Setup\n");
-@@ -1195,7 +1200,7 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
+@@ -1180,7 +1185,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
+ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
+ 				   int *datalen)
+ {
+-	struct udphdr _uh, *uh;
++	const struct udphdr *uh;
++	struct udphdr _uh;
+ 	int dataoff;
+ 
+ 	uh = skb_header_pointer(skb, protoff, sizeof(_uh), &_uh);
+@@ -1195,7 +1201,7 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
  
  /****************************************************************************/
  static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
@@ -898673,7 +961939,7 @@
  					       __be16 port)
  {
  	struct nf_conntrack_expect *exp;
-@@ -1237,7 +1242,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
+@@ -1237,7 +1243,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
  	int ret = 0;
  	int i;
  	__be16 port;
@@ -898682,7 +961948,7 @@
  	struct nf_conntrack_expect *exp;
  	typeof(nat_q931_hook) nat_q931;
  
-@@ -1306,7 +1311,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
+@@ -1306,7 +1312,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
  	int dir = CTINFO2DIR(ctinfo);
  	int ret = 0;
  	__be16 port;
@@ -898691,8 +961957,30 @@
  	struct nf_conntrack_expect *exp;
  
  	pr_debug("nf_ct_ras: GCF\n");
-@@ -1466,7 +1471,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
- 	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+@@ -1410,7 +1416,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
+ 		nf_ct_refresh(ct, skb, info->timeout * HZ);
+ 
+ 		/* Set expect timeout */
+-		read_lock_bh(&nf_conntrack_lock);
++		spin_lock_bh(&nf_conntrack_lock);
+ 		exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3,
+ 				  info->sig_port[!dir]);
+ 		if (exp) {
+@@ -1420,7 +1426,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
+ 			NF_CT_DUMP_TUPLE(&exp->tuple);
+ 			set_expect_timeout(exp, info->timeout);
+ 		}
+-		read_unlock_bh(&nf_conntrack_lock);
++		spin_unlock_bh(&nf_conntrack_lock);
+ 	}
+ 
+ 	return 0;
+@@ -1463,10 +1469,10 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
+ 		       enum ip_conntrack_info ctinfo,
+ 		       unsigned char **data, AdmissionRequest *arq)
+ {
+-	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
++	const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
  	int dir = CTINFO2DIR(ctinfo);
  	__be16 port;
 -	union nf_conntrack_address addr;
@@ -898700,7 +961988,7 @@
  	typeof(set_h225_addr_hook) set_h225_addr;
  
  	pr_debug("nf_ct_ras: ARQ\n");
-@@ -1508,7 +1513,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
+@@ -1508,7 +1514,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
  	int dir = CTINFO2DIR(ctinfo);
  	int ret = 0;
  	__be16 port;
@@ -898709,7 +961997,7 @@
  	struct nf_conntrack_expect *exp;
  	typeof(set_sig_addr_hook) set_sig_addr;
  
-@@ -1571,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
+@@ -1571,7 +1577,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
  	int dir = CTINFO2DIR(ctinfo);
  	int ret = 0;
  	__be16 port;
@@ -898718,6 +962006,1449 @@
  	struct nf_conntrack_expect *exp;
  
  	pr_debug("nf_ct_ras: LCF\n");
+diff --git a/net/netfilter/nf_conntrack_h323_types.c b/net/netfilter/nf_conntrack_h323_types.c
+index 3a21fdf..d880f35 100644
+--- a/net/netfilter/nf_conntrack_h323_types.c
++++ b/net/netfilter/nf_conntrack_h323_types.c
+@@ -5,22 +5,22 @@
+  * This source code is licensed under General Public License version 2.
+  */
+ 
+-static field_t _TransportAddress_ipAddress[] = {	/* SEQUENCE */
++static const struct field_t _TransportAddress_ipAddress[] = {	/* SEQUENCE */
+ 	{FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE,
+ 	 offsetof(TransportAddress_ipAddress, ip), NULL},
+ 	{FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TransportAddress_ipSourceRoute_route[] = {	/* SEQUENCE OF */
++static const struct field_t _TransportAddress_ipSourceRoute_route[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TransportAddress_ipSourceRoute_routing[] = {	/* CHOICE */
++static const struct field_t _TransportAddress_ipSourceRoute_routing[] = {	/* CHOICE */
+ 	{FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TransportAddress_ipSourceRoute[] = {	/* SEQUENCE */
++static const struct field_t _TransportAddress_ipSourceRoute[] = {	/* SEQUENCE */
+ 	{FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ 	{FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0,
+@@ -29,37 +29,37 @@ static field_t _TransportAddress_ipSourceRoute[] = {	/* SEQUENCE */
+ 	 _TransportAddress_ipSourceRoute_routing},
+ };
+ 
+-static field_t _TransportAddress_ipxAddress[] = {	/* SEQUENCE */
++static const struct field_t _TransportAddress_ipxAddress[] = {	/* SEQUENCE */
+ 	{FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
+ 	{FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ 	{FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TransportAddress_ip6Address[] = {	/* SEQUENCE */
++static const struct field_t _TransportAddress_ip6Address[] = {	/* SEQUENCE */
+ 	{FNAME("ip") OCTSTR, FIXD, 16, 0, DECODE,
+ 	 offsetof(TransportAddress_ip6Address, ip), NULL},
+ 	{FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H221NonStandard[] = {	/* SEQUENCE */
++static const struct field_t _H221NonStandard[] = {	/* SEQUENCE */
+ 	{FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _NonStandardIdentifier[] = {	/* CHOICE */
++static const struct field_t _NonStandardIdentifier[] = {	/* CHOICE */
+ 	{FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0,
+ 	 _H221NonStandard},
+ };
+ 
+-static field_t _NonStandardParameter[] = {	/* SEQUENCE */
++static const struct field_t _NonStandardParameter[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+ 	 _NonStandardIdentifier},
+ 	{FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TransportAddress[] = {	/* CHOICE */
++static const struct field_t _TransportAddress[] = {	/* CHOICE */
+ 	{FNAME("ipAddress") SEQ, 0, 2, 2, DECODE,
+ 	 offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress},
+ 	{FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0,
+@@ -75,7 +75,7 @@ static field_t _TransportAddress[] = {	/* CHOICE */
+ 	 _NonStandardParameter},
+ };
+ 
+-static field_t _AliasAddress[] = {	/* CHOICE */
++static const struct field_t _AliasAddress[] = {	/* CHOICE */
+ 	{FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL},
+@@ -85,78 +85,78 @@ static field_t _AliasAddress[] = {	/* CHOICE */
+ 	{FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _Setup_UUIE_sourceAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _Setup_UUIE_sourceAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _VendorIdentifier[] = {	/* SEQUENCE */
++static const struct field_t _VendorIdentifier[] = {	/* SEQUENCE */
+ 	{FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard},
+ 	{FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _GatekeeperInfo[] = {	/* SEQUENCE */
++static const struct field_t _GatekeeperInfo[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ };
+ 
+-static field_t _H310Caps[] = {	/* SEQUENCE */
++static const struct field_t _H310Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H320Caps[] = {	/* SEQUENCE */
++static const struct field_t _H320Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H321Caps[] = {	/* SEQUENCE */
++static const struct field_t _H321Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H322Caps[] = {	/* SEQUENCE */
++static const struct field_t _H322Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H323Caps[] = {	/* SEQUENCE */
++static const struct field_t _H323Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H324Caps[] = {	/* SEQUENCE */
++static const struct field_t _H324Caps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _VoiceCaps[] = {	/* SEQUENCE */
++static const struct field_t _VoiceCaps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _T120OnlyCaps[] = {	/* SEQUENCE */
++static const struct field_t _T120OnlyCaps[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _SupportedProtocols[] = {	/* CHOICE */
++static const struct field_t _SupportedProtocols[] = {	/* CHOICE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps},
+@@ -171,29 +171,29 @@ static field_t _SupportedProtocols[] = {	/* CHOICE */
+ 	{FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _GatewayInfo_protocol[] = {	/* SEQUENCE OF */
++static const struct field_t _GatewayInfo_protocol[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols},
+ };
+ 
+-static field_t _GatewayInfo[] = {	/* SEQUENCE */
++static const struct field_t _GatewayInfo[] = {	/* SEQUENCE */
+ 	{FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+ 	 _GatewayInfo_protocol},
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ };
+ 
+-static field_t _McuInfo[] = {	/* SEQUENCE */
++static const struct field_t _McuInfo[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _TerminalInfo[] = {	/* SEQUENCE */
++static const struct field_t _TerminalInfo[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ };
+ 
+-static field_t _EndpointType[] = {	/* SEQUENCE */
++static const struct field_t _EndpointType[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0,
+@@ -210,19 +210,19 @@ static field_t _EndpointType[] = {	/* SEQUENCE */
+ 	 0, NULL},
+ };
+ 
+-static field_t _Setup_UUIE_destinationAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _Setup_UUIE_destinationAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _Setup_UUIE_destExtraCallInfo[] = {	/* SEQUENCE OF */
++static const struct field_t _Setup_UUIE_destExtraCallInfo[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _Setup_UUIE_destExtraCRV[] = {	/* SEQUENCE OF */
++static const struct field_t _Setup_UUIE_destExtraCRV[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _Setup_UUIE_conferenceGoal[] = {	/* CHOICE */
++static const struct field_t _Setup_UUIE_conferenceGoal[] = {	/* CHOICE */
+ 	{FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -231,12 +231,12 @@ static field_t _Setup_UUIE_conferenceGoal[] = {	/* CHOICE */
+ 	 0, NULL},
+ };
+ 
+-static field_t _Q954Details[] = {	/* SEQUENCE */
++static const struct field_t _Q954Details[] = {	/* SEQUENCE */
+ 	{FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _QseriesOptions[] = {	/* SEQUENCE */
++static const struct field_t _QseriesOptions[] = {	/* SEQUENCE */
+ 	{FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -247,32 +247,32 @@ static field_t _QseriesOptions[] = {	/* SEQUENCE */
+ 	{FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details},
+ };
+ 
+-static field_t _CallType[] = {	/* CHOICE */
++static const struct field_t _CallType[] = {	/* CHOICE */
+ 	{FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H245_NonStandardIdentifier_h221NonStandard[] = {	/* SEQUENCE */
++static const struct field_t _H245_NonStandardIdentifier_h221NonStandard[] = {	/* SEQUENCE */
+ 	{FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H245_NonStandardIdentifier[] = {	/* CHOICE */
++static const struct field_t _H245_NonStandardIdentifier[] = {	/* CHOICE */
+ 	{FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _H245_NonStandardIdentifier_h221NonStandard},
+ };
+ 
+-static field_t _H245_NonStandardParameter[] = {	/* SEQUENCE */
++static const struct field_t _H245_NonStandardParameter[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardIdentifier},
+ 	{FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H261VideoCapability[] = {	/* SEQUENCE */
++static const struct field_t _H261VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0,
+@@ -282,7 +282,7 @@ static field_t _H261VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H262VideoCapability[] = {	/* SEQUENCE */
++static const struct field_t _H262VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -304,7 +304,7 @@ static field_t _H262VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H263VideoCapability[] = {	/* SEQUENCE */
++static const struct field_t _H263VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
+@@ -330,7 +330,7 @@ static field_t _H263VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _IS11172VideoCapability[] = {	/* SEQUENCE */
++static const struct field_t _IS11172VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
+@@ -341,7 +341,7 @@ static field_t _IS11172VideoCapability[] = {	/* SEQUENCE */
+ 	{FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _VideoCapability[] = {	/* CHOICE */
++static const struct field_t _VideoCapability[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0,
+@@ -355,12 +355,12 @@ static field_t _VideoCapability[] = {	/* CHOICE */
+ 	{FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _AudioCapability_g7231[] = {	/* SEQUENCE */
++static const struct field_t _AudioCapability_g7231[] = {	/* SEQUENCE */
+ 	{FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _IS11172AudioCapability[] = {	/* SEQUENCE */
++static const struct field_t _IS11172AudioCapability[] = {	/* SEQUENCE */
+ 	{FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -372,7 +372,7 @@ static field_t _IS11172AudioCapability[] = {	/* SEQUENCE */
+ 	{FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _IS13818AudioCapability[] = {	/* SEQUENCE */
++static const struct field_t _IS13818AudioCapability[] = {	/* SEQUENCE */
+ 	{FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -396,7 +396,7 @@ static field_t _IS13818AudioCapability[] = {	/* SEQUENCE */
+ 	{FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _AudioCapability[] = {	/* CHOICE */
++static const struct field_t _AudioCapability[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL},
+@@ -424,7 +424,7 @@ static field_t _AudioCapability[] = {	/* CHOICE */
+ 	{FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _DataProtocolCapability[] = {	/* CHOICE */
++static const struct field_t _DataProtocolCapability[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -442,7 +442,7 @@ static field_t _DataProtocolCapability[] = {	/* CHOICE */
+ 	{FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _T84Profile_t84Restricted[] = {	/* SEQUENCE */
++static const struct field_t _T84Profile_t84Restricted[] = {	/* SEQUENCE */
+ 	{FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -464,25 +464,25 @@ static field_t _T84Profile_t84Restricted[] = {	/* SEQUENCE */
+ 	{FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _T84Profile[] = {	/* CHOICE */
++static const struct field_t _T84Profile[] = {	/* CHOICE */
+ 	{FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0,
+ 	 _T84Profile_t84Restricted},
+ };
+ 
+-static field_t _DataApplicationCapability_application_t84[] = {	/* SEQUENCE */
++static const struct field_t _DataApplicationCapability_application_t84[] = {	/* SEQUENCE */
+ 	{FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+ 	 _DataProtocolCapability},
+ 	{FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile},
+ };
+ 
+-static field_t _DataApplicationCapability_application_nlpid[] = {	/* SEQUENCE */
++static const struct field_t _DataApplicationCapability_application_nlpid[] = {	/* SEQUENCE */
+ 	{FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
+ 	 _DataProtocolCapability},
+ 	{FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _DataApplicationCapability_application[] = {	/* CHOICE */
++static const struct field_t _DataApplicationCapability_application[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT,
+@@ -509,20 +509,20 @@ static field_t _DataApplicationCapability_application[] = {	/* CHOICE */
+ 	{FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _DataApplicationCapability[] = {	/* SEQUENCE */
++static const struct field_t _DataApplicationCapability[] = {	/* SEQUENCE */
+ 	{FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT,
+ 	 offsetof(DataApplicationCapability, application),
+ 	 _DataApplicationCapability_application},
+ 	{FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _EncryptionMode[] = {	/* CHOICE */
++static const struct field_t _EncryptionMode[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _DataType[] = {	/* CHOICE */
++static const struct field_t _DataType[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -538,7 +538,7 @@ static field_t _DataType[] = {	/* CHOICE */
+ 	{FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _H222LogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _H222LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+@@ -546,12 +546,12 @@ static field_t _H222LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = {	/* SEQUENCE */
++static const struct field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = {	/* SEQUENCE */
+ 	{FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H223LogicalChannelParameters_adaptationLayerType[] = {	/* CHOICE */
++static const struct field_t _H223LogicalChannelParameters_adaptationLayerType[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _H245_NonStandardParameter},
+ 	{FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -565,53 +565,53 @@ static field_t _H223LogicalChannelParameters_adaptationLayerType[] = {	/* CHOICE
+ 	{FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _H223LogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _H223LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0,
+ 	 _H223LogicalChannelParameters_adaptationLayerType},
+ 	{FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CRCLength[] = {	/* CHOICE */
++static const struct field_t _CRCLength[] = {	/* CHOICE */
+ 	{FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V76HDLCParameters[] = {	/* SEQUENCE */
++static const struct field_t _V76HDLCParameters[] = {	/* SEQUENCE */
+ 	{FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength},
+ 	{FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V76LogicalChannelParameters_suspendResume[] = {	/* CHOICE */
++static const struct field_t _V76LogicalChannelParameters_suspendResume[] = {	/* CHOICE */
+ 	{FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = {	/* CHOICE */
++static const struct field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = {	/* CHOICE */
+ 	{FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V76LogicalChannelParameters_mode_eRM[] = {	/* SEQUENCE */
++static const struct field_t _V76LogicalChannelParameters_mode_eRM[] = {	/* SEQUENCE */
+ 	{FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+ 	 _V76LogicalChannelParameters_mode_eRM_recovery},
+ };
+ 
+-static field_t _V76LogicalChannelParameters_mode[] = {	/* CHOICE */
++static const struct field_t _V76LogicalChannelParameters_mode[] = {	/* CHOICE */
+ 	{FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0,
+ 	 _V76LogicalChannelParameters_mode_eRM},
+ 	{FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V75Parameters[] = {	/* SEQUENCE */
++static const struct field_t _V75Parameters[] = {	/* SEQUENCE */
+ 	{FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _V76LogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _V76LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0,
+ 	 _V76HDLCParameters},
+ 	{FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+@@ -622,38 +622,38 @@ static field_t _V76LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters},
+ };
+ 
+-static field_t _H2250LogicalChannelParameters_nonStandard[] = {	/* SEQUENCE OF */
++static const struct field_t _H2250LogicalChannelParameters_nonStandard[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
+ };
+ 
+-static field_t _UnicastAddress_iPAddress[] = {	/* SEQUENCE */
++static const struct field_t _UnicastAddress_iPAddress[] = {	/* SEQUENCE */
+ 	{FNAME("network") OCTSTR, FIXD, 4, 0, DECODE,
+ 	 offsetof(UnicastAddress_iPAddress, network), NULL},
+ 	{FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _UnicastAddress_iPXAddress[] = {	/* SEQUENCE */
++static const struct field_t _UnicastAddress_iPXAddress[] = {	/* SEQUENCE */
+ 	{FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
+ 	{FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ 	{FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _UnicastAddress_iP6Address[] = {	/* SEQUENCE */
++static const struct field_t _UnicastAddress_iP6Address[] = {	/* SEQUENCE */
+ 	{FNAME("network") OCTSTR, FIXD, 16, 0, DECODE,
+ 	 offsetof(UnicastAddress_iP6Address, network), NULL},
+ 	{FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = {	/* CHOICE */
++static const struct field_t _UnicastAddress_iPSourceRouteAddress_routing[] = {	/* CHOICE */
+ 	{FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _UnicastAddress_iPSourceRouteAddress_route[] = {	/* SEQUENCE OF */
++static const struct field_t _UnicastAddress_iPSourceRouteAddress_route[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _UnicastAddress_iPSourceRouteAddress[] = {	/* SEQUENCE */
++static const struct field_t _UnicastAddress_iPSourceRouteAddress[] = {	/* SEQUENCE */
+ 	{FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0,
+ 	 _UnicastAddress_iPSourceRouteAddress_routing},
+ 	{FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+@@ -662,7 +662,7 @@ static field_t _UnicastAddress_iPSourceRouteAddress[] = {	/* SEQUENCE */
+ 	 _UnicastAddress_iPSourceRouteAddress_route},
+ };
+ 
+-static field_t _UnicastAddress[] = {	/* CHOICE */
++static const struct field_t _UnicastAddress[] = {	/* CHOICE */
+ 	{FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT,
+ 	 offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress},
+ 	{FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0,
+@@ -676,17 +676,17 @@ static field_t _UnicastAddress[] = {	/* CHOICE */
+ 	{FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
+ };
+ 
+-static field_t _MulticastAddress_iPAddress[] = {	/* SEQUENCE */
++static const struct field_t _MulticastAddress_iPAddress[] = {	/* SEQUENCE */
+ 	{FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
+ 	{FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _MulticastAddress_iP6Address[] = {	/* SEQUENCE */
++static const struct field_t _MulticastAddress_iP6Address[] = {	/* SEQUENCE */
+ 	{FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+ 	{FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _MulticastAddress[] = {	/* CHOICE */
++static const struct field_t _MulticastAddress[] = {	/* CHOICE */
+ 	{FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0,
+ 	 _MulticastAddress_iPAddress},
+ 	{FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0,
+@@ -695,14 +695,14 @@ static field_t _MulticastAddress[] = {	/* CHOICE */
+ 	{FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H245_TransportAddress[] = {	/* CHOICE */
++static const struct field_t _H245_TransportAddress[] = {	/* CHOICE */
+ 	{FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT,
+ 	 offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress},
+ 	{FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0,
+ 	 _MulticastAddress},
+ };
+ 
+-static field_t _H2250LogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _H2250LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+ 	 _H2250LogicalChannelParameters_nonStandard},
+ 	{FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL},
+@@ -728,7 +728,7 @@ static field_t _H2250LogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
++static const struct field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
+ 	{FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
+ 	 _H222LogicalChannelParameters},
+ 	{FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
+@@ -742,7 +742,7 @@ static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexPara
+ 	{FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT,
+ 	 offsetof(OpenLogicalChannel_forwardLogicalChannelParameters,
+@@ -756,7 +756,7 @@ static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {	/* SEQU
+ 	{FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
++static const struct field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
+ 	{FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
+ 	 _H223LogicalChannelParameters},
+ 	{FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0,
+@@ -767,7 +767,7 @@ static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexPara
+ 	  h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
+ };
+ 
+-static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType},
+ 	{FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT,
+ 	 offsetof(OpenLogicalChannel_reverseLogicalChannelParameters,
+@@ -778,23 +778,23 @@ static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {	/* SEQU
+ 	{FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _NetworkAccessParameters_distribution[] = {	/* CHOICE */
++static const struct field_t _NetworkAccessParameters_distribution[] = {	/* CHOICE */
+ 	{FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _Q2931Address_address[] = {	/* CHOICE */
++static const struct field_t _Q2931Address_address[] = {	/* CHOICE */
+ 	{FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _Q2931Address[] = {	/* SEQUENCE */
++static const struct field_t _Q2931Address[] = {	/* SEQUENCE */
+ 	{FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0,
+ 	 _Q2931Address_address},
+ 	{FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _NetworkAccessParameters_networkAddress[] = {	/* CHOICE */
++static const struct field_t _NetworkAccessParameters_networkAddress[] = {	/* CHOICE */
+ 	{FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address},
+ 	{FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT,
+@@ -802,7 +802,7 @@ static field_t _NetworkAccessParameters_networkAddress[] = {	/* CHOICE */
+ 	 _H245_TransportAddress},
+ };
+ 
+-static field_t _NetworkAccessParameters[] = {	/* SEQUENCE */
++static const struct field_t _NetworkAccessParameters[] = {	/* SEQUENCE */
+ 	{FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0,
+ 	 _NetworkAccessParameters_distribution},
+ 	{FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT,
+@@ -814,7 +814,7 @@ static field_t _NetworkAccessParameters[] = {	/* SEQUENCE */
+ 	 NULL},
+ };
+ 
+-static field_t _OpenLogicalChannel[] = {	/* SEQUENCE */
++static const struct field_t _OpenLogicalChannel[] = {	/* SEQUENCE */
+ 	{FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT,
+ 	 offsetof(OpenLogicalChannel, forwardLogicalChannelParameters),
+@@ -829,13 +829,13 @@ static field_t _OpenLogicalChannel[] = {	/* SEQUENCE */
+ 	{FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _Setup_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _Setup_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _Setup_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Setup_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+ 	 offsetof(Setup_UUIE, h245Address), _TransportAddress},
+@@ -894,13 +894,13 @@ static field_t _Setup_UUIE[] = {	/* SEQUENCE */
+ 	 NULL},
+ };
+ 
+-static field_t _CallProceeding_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _CallProceeding_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _CallProceeding_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _CallProceeding_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+ 	 _EndpointType},
+@@ -920,13 +920,13 @@ static field_t _CallProceeding_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _Connect_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _Connect_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _Connect_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Connect_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+ 	 offsetof(Connect_UUIE, h245Address), _TransportAddress},
+@@ -954,13 +954,13 @@ static field_t _Connect_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _Alerting_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _Alerting_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _Alerting_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Alerting_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+ 	 _EndpointType},
+@@ -986,7 +986,7 @@ static field_t _Alerting_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _Information_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Information_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
+ 	{FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
+@@ -996,7 +996,7 @@ static field_t _Information_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _ReleaseCompleteReason[] = {	/* CHOICE */
++static const struct field_t _ReleaseCompleteReason[] = {	/* CHOICE */
+ 	{FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -1022,7 +1022,7 @@ static field_t _ReleaseCompleteReason[] = {	/* CHOICE */
+ 	{FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _ReleaseComplete_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _ReleaseComplete_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0,
+ 	 _ReleaseCompleteReason},
+@@ -1039,11 +1039,11 @@ static field_t _ReleaseComplete_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _Facility_UUIE_alternativeAliasAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _Facility_UUIE_alternativeAliasAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _FacilityReason[] = {	/* CHOICE */
++static const struct field_t _FacilityReason[] = {	/* CHOICE */
+ 	{FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+@@ -1057,13 +1057,13 @@ static field_t _FacilityReason[] = {	/* CHOICE */
+ 	{FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _Facility_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _Facility_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _Facility_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Facility_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
+ 	 offsetof(Facility_UUIE, alternativeAddress), _TransportAddress},
+@@ -1094,17 +1094,17 @@ static field_t _Facility_UUIE[] = {	/* SEQUENCE */
+ 	 NULL},
+ };
+ 
+-static field_t _CallIdentifier[] = {	/* SEQUENCE */
++static const struct field_t _CallIdentifier[] = {	/* SEQUENCE */
+ 	{FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _SecurityServiceMode[] = {	/* CHOICE */
++static const struct field_t _SecurityServiceMode[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
+ 	{FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _SecurityCapabilities[] = {	/* SEQUENCE */
++static const struct field_t _SecurityCapabilities[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0,
+@@ -1115,30 +1115,30 @@ static field_t _SecurityCapabilities[] = {	/* SEQUENCE */
+ 	 _SecurityServiceMode},
+ };
+ 
+-static field_t _H245Security[] = {	/* CHOICE */
++static const struct field_t _H245Security[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
+ 	{FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
+ 	{FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
+ };
+ 
+-static field_t _DHset[] = {	/* SEQUENCE */
++static const struct field_t _DHset[] = {	/* SEQUENCE */
+ 	{FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _TypedCertificate[] = {	/* SEQUENCE */
++static const struct field_t _TypedCertificate[] = {	/* SEQUENCE */
+ 	{FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _H235_NonStandardParameter[] = {	/* SEQUENCE */
++static const struct field_t _H235_NonStandardParameter[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _ClearToken[] = {	/* SEQUENCE */
++static const struct field_t _ClearToken[] = {	/* SEQUENCE */
+ 	{FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+@@ -1154,120 +1154,120 @@ static field_t _ClearToken[] = {	/* SEQUENCE */
+ 	{FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _Progress_UUIE_tokens[] = {	/* SEQUENCE OF */
++static const struct field_t _Progress_UUIE_tokens[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
+ };
+ 
+-static field_t _Params[] = {	/* SEQUENCE */
++static const struct field_t _Params[] = {	/* SEQUENCE */
+ 	{FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoEPPwdHash_token[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoEPPwdHash[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoEPPwdHash[] = {	/* SEQUENCE */
+ 	{FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ 	{FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _CryptoH323Token_cryptoEPPwdHash_token},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoGKPwdHash_token[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoGKPwdHash[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoGKPwdHash[] = {	/* SEQUENCE */
+ 	{FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _CryptoH323Token_cryptoGKPwdHash_token},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoEPPwdEncr[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoEPPwdEncr[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoGKPwdEncr[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoGKPwdEncr[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoEPCert[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoEPCert[] = {	/* SEQUENCE */
+ 	{FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoGKCert[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoGKCert[] = {	/* SEQUENCE */
+ 	{FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoH323Token_cryptoFastStart[] = {	/* SEQUENCE */
++static const struct field_t _CryptoH323Token_cryptoFastStart[] = {	/* SEQUENCE */
+ 	{FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoToken_cryptoEncryptedToken_token[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoEncryptedToken_token[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoToken_cryptoEncryptedToken[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoEncryptedToken[] = {	/* SEQUENCE */
+ 	{FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _CryptoToken_cryptoEncryptedToken_token},
+ };
+ 
+-static field_t _CryptoToken_cryptoSignedToken_token[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoSignedToken_token[] = {	/* SEQUENCE */
+ 	{FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoToken_cryptoSignedToken[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoSignedToken[] = {	/* SEQUENCE */
+ 	{FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("token") SEQ, 0, 4, 4, SKIP, 0,
+ 	 _CryptoToken_cryptoSignedToken_token},
+ };
+ 
+-static field_t _CryptoToken_cryptoHashedToken_token[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoHashedToken_token[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoToken_cryptoHashedToken[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoHashedToken[] = {	/* SEQUENCE */
+ 	{FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
+ 	{FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _CryptoToken_cryptoHashedToken_token},
+ };
+ 
+-static field_t _CryptoToken_cryptoPwdEncr[] = {	/* SEQUENCE */
++static const struct field_t _CryptoToken_cryptoPwdEncr[] = {	/* SEQUENCE */
+ 	{FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
+ 	{FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _CryptoToken[] = {	/* CHOICE */
++static const struct field_t _CryptoToken[] = {	/* CHOICE */
+ 	{FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0,
+ 	 _CryptoToken_cryptoEncryptedToken},
+ 	{FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0,
+@@ -1278,7 +1278,7 @@ static field_t _CryptoToken[] = {	/* CHOICE */
+ 	 _CryptoToken_cryptoPwdEncr},
+ };
+ 
+-static field_t _CryptoH323Token[] = {	/* CHOICE */
++static const struct field_t _CryptoH323Token[] = {	/* CHOICE */
+ 	{FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0,
+ 	 _CryptoH323Token_cryptoEPPwdHash},
+ 	{FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0,
+@@ -1297,17 +1297,17 @@ static field_t _CryptoH323Token[] = {	/* CHOICE */
+ 	 _CryptoToken},
+ };
+ 
+-static field_t _Progress_UUIE_cryptoTokens[] = {	/* SEQUENCE OF */
++static const struct field_t _Progress_UUIE_cryptoTokens[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token},
+ };
+ 
+-static field_t _Progress_UUIE_fastStart[] = {	/* SEQUENCE OF */
++static const struct field_t _Progress_UUIE_fastStart[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
+ 	 sizeof(OpenLogicalChannel), _OpenLogicalChannel}
+ 	,
+ };
+ 
+-static field_t _Progress_UUIE[] = {	/* SEQUENCE */
++static const struct field_t _Progress_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
+ 	 _EndpointType},
+@@ -1328,7 +1328,7 @@ static field_t _Progress_UUIE[] = {	/* SEQUENCE */
+ 	{FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _H323_UU_PDU_h323_message_body[] = {	/* CHOICE */
++static const struct field_t _H323_UU_PDU_h323_message_body[] = {	/* CHOICE */
+ 	{FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT,
+ 	 offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE},
+ 	{FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT,
+@@ -1352,7 +1352,7 @@ static field_t _H323_UU_PDU_h323_message_body[] = {	/* CHOICE */
+ 	{FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
+ };
+ 
+-static field_t _RequestMessage[] = {	/* CHOICE */
++static const struct field_t _RequestMessage[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+ 	{FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
+ 	{FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL},
+@@ -1372,7 +1372,7 @@ static field_t _RequestMessage[] = {	/* CHOICE */
+ 	 NULL},
+ };
+ 
+-static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
++static const struct field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = {	/* CHOICE */
+ 	{FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
+ 	 _H222LogicalChannelParameters},
+ 	{FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT,
+@@ -1381,7 +1381,7 @@ static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexP
+ 	  h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
+ };
+ 
+-static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {	/* SEQUENCE */
++static const struct field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {	/* SEQUENCE */
+ 	{FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT,
+@@ -1391,11 +1391,11 @@ static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {	/* S
+ 	{FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _H2250LogicalChannelAckParameters_nonStandard[] = {	/* SEQUENCE OF */
++static const struct field_t _H2250LogicalChannelAckParameters_nonStandard[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
+ };
+ 
+-static field_t _H2250LogicalChannelAckParameters[] = {	/* SEQUENCE */
++static const struct field_t _H2250LogicalChannelAckParameters[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
+ 	 _H2250LogicalChannelAckParameters_nonStandard},
+ 	{FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL},
+@@ -1410,14 +1410,14 @@ static field_t _H2250LogicalChannelAckParameters[] = {	/* SEQUENCE */
+ 	{FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
+ };
+ 
+-static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = {	/* CHOICE */
++static const struct field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = {	/* CHOICE */
+ 	{FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT,
+ 	 offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters,
+ 		  h2250LogicalChannelAckParameters),
+ 	 _H2250LogicalChannelAckParameters},
+ };
+ 
+-static field_t _OpenLogicalChannelAck[] = {	/* SEQUENCE */
++static const struct field_t _OpenLogicalChannelAck[] = {	/* SEQUENCE */
+ 	{FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4,
+ 	 DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck,
+@@ -1433,7 +1433,7 @@ static field_t _OpenLogicalChannelAck[] = {	/* SEQUENCE */
+ 	{FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _ResponseMessage[] = {	/* CHOICE */
++static const struct field_t _ResponseMessage[] = {	/* CHOICE */
+ 	{FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
+ 	{FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0,
+ 	 NULL},
+@@ -1469,7 +1469,7 @@ static field_t _ResponseMessage[] = {	/* CHOICE */
+ 	{FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL},
+ };
+ 
+-static field_t _MultimediaSystemControlMessage[] = {	/* CHOICE */
++static const struct field_t _MultimediaSystemControlMessage[] = {	/* CHOICE */
+ 	{FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT,
+ 	 offsetof(MultimediaSystemControlMessage, request), _RequestMessage},
+ 	{FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT,
+@@ -1479,14 +1479,14 @@ static field_t _MultimediaSystemControlMessage[] = {	/* CHOICE */
+ 	{FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL},
+ };
+ 
+-static field_t _H323_UU_PDU_h245Control[] = {	/* SEQUENCE OF */
++static const struct field_t _H323_UU_PDU_h245Control[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT,
+ 	 sizeof(MultimediaSystemControlMessage),
+ 	 _MultimediaSystemControlMessage}
+ 	,
+ };
+ 
+-static field_t _H323_UU_PDU[] = {	/* SEQUENCE */
++static const struct field_t _H323_UU_PDU[] = {	/* SEQUENCE */
+ 	{FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT,
+ 	 offsetof(H323_UU_PDU, h323_message_body),
+ 	 _H323_UU_PDU_h323_message_body},
+@@ -1507,13 +1507,13 @@ static field_t _H323_UU_PDU[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _H323_UserInformation[] = {	/* SEQUENCE */
++static const struct field_t _H323_UserInformation[] = {	/* SEQUENCE */
+ 	{FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT,
+ 	 offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU},
+ 	{FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _GatekeeperRequest[] = {	/* SEQUENCE */
++static const struct field_t _GatekeeperRequest[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+@@ -1537,7 +1537,7 @@ static field_t _GatekeeperRequest[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _GatekeeperConfirm[] = {	/* SEQUENCE */
++static const struct field_t _GatekeeperConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+@@ -1557,23 +1557,23 @@ static field_t _GatekeeperConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _RegistrationRequest_callSignalAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _RegistrationRequest_callSignalAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 sizeof(TransportAddress), _TransportAddress}
+ 	,
+ };
+ 
+-static field_t _RegistrationRequest_rasAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _RegistrationRequest_rasAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 sizeof(TransportAddress), _TransportAddress}
+ 	,
+ };
+ 
+-static field_t _RegistrationRequest_terminalAlias[] = {	/* SEQUENCE OF */
++static const struct field_t _RegistrationRequest_terminalAlias[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _RegistrationRequest[] = {	/* SEQUENCE */
++static const struct field_t _RegistrationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+@@ -1621,17 +1621,17 @@ static field_t _RegistrationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _RegistrationConfirm_callSignalAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _RegistrationConfirm_callSignalAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 sizeof(TransportAddress), _TransportAddress}
+ 	,
+ };
+ 
+-static field_t _RegistrationConfirm_terminalAlias[] = {	/* SEQUENCE OF */
++static const struct field_t _RegistrationConfirm_terminalAlias[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _RegistrationConfirm[] = {	/* SEQUENCE */
++static const struct field_t _RegistrationConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+@@ -1667,13 +1667,13 @@ static field_t _RegistrationConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _UnregistrationRequest_callSignalAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _UnregistrationRequest_callSignalAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 sizeof(TransportAddress), _TransportAddress}
+ 	,
+ };
+ 
+-static field_t _UnregistrationRequest[] = {	/* SEQUENCE */
++static const struct field_t _UnregistrationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
+ 	 offsetof(UnregistrationRequest, callSignalAddress),
+@@ -1694,24 +1694,24 @@ static field_t _UnregistrationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _CallModel[] = {	/* CHOICE */
++static const struct field_t _CallModel[] = {	/* CHOICE */
+ 	{FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
+ };
+ 
+-static field_t _AdmissionRequest_destinationInfo[] = {	/* SEQUENCE OF */
++static const struct field_t _AdmissionRequest_destinationInfo[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _AdmissionRequest_destExtraCallInfo[] = {	/* SEQUENCE OF */
++static const struct field_t _AdmissionRequest_destExtraCallInfo[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _AdmissionRequest_srcInfo[] = {	/* SEQUENCE OF */
++static const struct field_t _AdmissionRequest_srcInfo[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _AdmissionRequest[] = {	/* SEQUENCE */
++static const struct field_t _AdmissionRequest[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType},
+ 	{FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel},
+@@ -1755,7 +1755,7 @@ static field_t _AdmissionRequest[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _AdmissionConfirm[] = {	/* SEQUENCE */
++static const struct field_t _AdmissionConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL},
+ 	{FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel},
+@@ -1790,11 +1790,11 @@ static field_t _AdmissionConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _LocationRequest_destinationInfo[] = {	/* SEQUENCE OF */
++static const struct field_t _LocationRequest_destinationInfo[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
+ };
+ 
+-static field_t _LocationRequest[] = {	/* SEQUENCE */
++static const struct field_t _LocationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
+ 	{FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0,
+@@ -1818,7 +1818,7 @@ static field_t _LocationRequest[] = {	/* SEQUENCE */
+ 	{FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
+ };
+ 
+-static field_t _LocationConfirm[] = {	/* SEQUENCE */
++static const struct field_t _LocationConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+ 	{FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 offsetof(LocationConfirm, callSignalAddress), _TransportAddress},
+@@ -1844,13 +1844,13 @@ static field_t _LocationConfirm[] = {	/* SEQUENCE */
+ 	{FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _InfoRequestResponse_callSignalAddress[] = {	/* SEQUENCE OF */
++static const struct field_t _InfoRequestResponse_callSignalAddress[] = {	/* SEQUENCE OF */
+ 	{FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
+ 	 sizeof(TransportAddress), _TransportAddress}
+ 	,
+ };
+ 
+-static field_t _InfoRequestResponse[] = {	/* SEQUENCE */
++static const struct field_t _InfoRequestResponse[] = {	/* SEQUENCE */
+ 	{FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
+ 	 _NonStandardParameter},
+ 	{FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
+@@ -1873,7 +1873,7 @@ static field_t _InfoRequestResponse[] = {	/* SEQUENCE */
+ 	{FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
+ };
+ 
+-static field_t _RasMessage[] = {	/* CHOICE */
++static const struct field_t _RasMessage[] = {	/* CHOICE */
+ 	{FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT,
+ 	 offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest},
+ 	{FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT,
+diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
+index 96aa637..b1fd21c 100644
+--- a/net/netfilter/nf_conntrack_helper.c
++++ b/net/netfilter/nf_conntrack_helper.c
+@@ -28,6 +28,7 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_extend.h>
+ 
++static DEFINE_MUTEX(nf_ct_helper_mutex);
+ static struct hlist_head *nf_ct_helper_hash __read_mostly;
+ static unsigned int nf_ct_helper_hsize __read_mostly;
+ static unsigned int nf_ct_helper_count __read_mostly;
+@@ -54,42 +55,13 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
+ 		return NULL;
+ 
+ 	h = helper_hash(tuple);
+-	hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) {
++	hlist_for_each_entry_rcu(helper, n, &nf_ct_helper_hash[h], hnode) {
+ 		if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
+ 			return helper;
+ 	}
+ 	return NULL;
+ }
+-
+-struct nf_conntrack_helper *
+-nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple)
+-{
+-	struct nf_conntrack_helper *helper;
+-
+-	/* need nf_conntrack_lock to assure that helper exists until
+-	 * try_module_get() is called */
+-	read_lock_bh(&nf_conntrack_lock);
+-
+-	helper = __nf_ct_helper_find(tuple);
+-	if (helper) {
+-		/* need to increase module usage count to assure helper will
+-		 * not go away while the caller is e.g. busy putting a
+-		 * conntrack in the hash that uses the helper */
+-		if (!try_module_get(helper->me))
+-			helper = NULL;
+-	}
+-
+-	read_unlock_bh(&nf_conntrack_lock);
+-
+-	return helper;
+-}
+-EXPORT_SYMBOL_GPL(nf_ct_helper_find_get);
+-
+-void nf_ct_helper_put(struct nf_conntrack_helper *helper)
+-{
+-	module_put(helper->me);
+-}
+-EXPORT_SYMBOL_GPL(nf_ct_helper_put);
++EXPORT_SYMBOL_GPL(__nf_ct_helper_find);
+ 
+ struct nf_conntrack_helper *
+ __nf_conntrack_helper_find_byname(const char *name)
+@@ -99,7 +71,7 @@ __nf_conntrack_helper_find_byname(const char *name)
+ 	unsigned int i;
+ 
+ 	for (i = 0; i < nf_ct_helper_hsize; i++) {
+-		hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) {
++		hlist_for_each_entry_rcu(h, n, &nf_ct_helper_hash[i], hnode) {
+ 			if (!strcmp(h->name, name))
+ 				return h;
+ 		}
+@@ -140,10 +112,10 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
+ 
+ 	BUG_ON(me->timeout == 0);
+ 
+-	write_lock_bh(&nf_conntrack_lock);
+-	hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]);
++	mutex_lock(&nf_ct_helper_mutex);
++	hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
+ 	nf_ct_helper_count++;
+-	write_unlock_bh(&nf_conntrack_lock);
++	mutex_unlock(&nf_ct_helper_mutex);
+ 
+ 	return 0;
+ }
+@@ -156,10 +128,17 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ 	struct hlist_node *n, *next;
+ 	unsigned int i;
+ 
+-	/* Need write lock here, to delete helper. */
+-	write_lock_bh(&nf_conntrack_lock);
+-	hlist_del(&me->hnode);
++	mutex_lock(&nf_ct_helper_mutex);
++	hlist_del_rcu(&me->hnode);
+ 	nf_ct_helper_count--;
++	mutex_unlock(&nf_ct_helper_mutex);
++
++	/* Make sure every nothing is still using the helper unless its a
++	 * connection in the hash.
++	 */
++	synchronize_rcu();
++
++	spin_lock_bh(&nf_conntrack_lock);
+ 
+ 	/* Get rid of expectations */
+ 	for (i = 0; i < nf_ct_expect_hsize; i++) {
+@@ -181,10 +160,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
+ 		hlist_for_each_entry(h, n, &nf_conntrack_hash[i], hnode)
+ 			unhelp(h, me);
+ 	}
+-	write_unlock_bh(&nf_conntrack_lock);
+-
+-	/* Someone could be still looking at the helper in a bh. */
+-	synchronize_net();
++	spin_unlock_bh(&nf_conntrack_lock);
+ }
+ EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+ 
+diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
+index dfaed4b..c336b07 100644
+--- a/net/netfilter/nf_conntrack_irc.c
++++ b/net/netfilter/nf_conntrack_irc.c
+@@ -23,7 +23,7 @@
+ 
+ #define MAX_PORTS 8
+ static unsigned short ports[MAX_PORTS];
+-static int ports_c;
++static unsigned int ports_c;
+ static unsigned int max_dcc_channels = 8;
+ static unsigned int dcc_timeout __read_mostly = 300;
+ /* This is slow, but it's simple. --RR */
 diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
 index 991c52c..8e914e5 100644
 --- a/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -898744,7 +963475,7 @@
  };
  EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_generic);
 diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
-index 7d23124..38141f1 100644
+index 7d23124..4a1b42b 100644
 --- a/net/netfilter/nf_conntrack_netlink.c
 +++ b/net/netfilter/nf_conntrack_netlink.c
 @@ -59,7 +59,7 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb,
@@ -898965,17 +963696,20 @@
  		goto nla_put_failure;
  
  	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
-@@ -419,11 +496,24 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
- 		    && ctnetlink_dump_mark(skb, ct) < 0)
+@@ -414,9 +491,9 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
+ 		    && ctnetlink_dump_helpinfo(skb, ct) < 0)
  			goto nla_put_failure;
- #endif
+ 
+-#ifdef CONFIG_NF_CONNTRACK_MARK
+-		if ((events & IPCT_MARK || ct->mark)
+-		    && ctnetlink_dump_mark(skb, ct) < 0)
 +#ifdef CONFIG_NF_CONNTRACK_SECMARK
 +		if ((events & IPCT_SECMARK || ct->secmark)
 +		    && ctnetlink_dump_secmark(skb, ct) < 0)
-+			goto nla_put_failure;
-+#endif
+ 			goto nla_put_failure;
+ #endif
  
- 		if (events & IPCT_COUNTER_FILLING &&
+@@ -424,8 +501,22 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
  		    (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
  		     ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0))
  			goto nla_put_failure;
@@ -898989,8 +963723,16 @@
 +			goto nla_put_failure;
  	}
  
++#ifdef CONFIG_NF_CONNTRACK_MARK
++	if ((events & IPCT_MARK || ct->mark)
++	    && ctnetlink_dump_mark(skb, ct) < 0)
++		goto nla_put_failure;
++#endif
++
  	nlh->nlmsg_len = skb->tail - b;
-@@ -444,7 +534,7 @@ static int ctnetlink_done(struct netlink_callback *cb)
+ 	nfnetlink_send(skb, 0, group, 0);
+ 	return NOTIFY_DONE;
+@@ -444,7 +535,7 @@ static int ctnetlink_done(struct netlink_callback *cb)
  	return 0;
  }
  
@@ -898999,7 +963741,42 @@
  
  static int
  ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
-@@ -542,7 +632,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
+@@ -455,12 +546,12 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+ 	struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
+ 	u_int8_t l3proto = nfmsg->nfgen_family;
+ 
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	last = (struct nf_conn *)cb->args[1];
+ 	for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
+ restart:
+-		hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],
+-				     hnode) {
++		hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[cb->args[0]],
++					 hnode) {
+ 			if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+ 				continue;
+ 			ct = nf_ct_tuplehash_to_ctrack(h);
+@@ -478,7 +569,8 @@ restart:
+ 						cb->nlh->nlmsg_seq,
+ 						IPCTNL_MSG_CT_NEW,
+ 						1, ct) < 0) {
+-				nf_conntrack_get(&ct->ct_general);
++				if (!atomic_inc_not_zero(&ct->ct_general.use))
++					continue;
+ 				cb->args[1] = (unsigned long)ct;
+ 				goto out;
+ 			}
+@@ -494,7 +586,7 @@ restart:
+ 		}
+ 	}
+ out:
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ 	if (last)
+ 		nf_ct_put(last);
+ 
+@@ -542,7 +634,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
  
  	if (!tb[CTA_PROTO_NUM])
  		return -EINVAL;
@@ -899008,7 +963785,7 @@
  
  	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
  
-@@ -558,7 +648,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
+@@ -558,7 +650,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
  	return ret;
  }
  
@@ -899017,7 +963794,7 @@
  ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple,
  		      enum ctattr_tuple type, u_int8_t l3num)
  {
-@@ -605,7 +695,7 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr,
+@@ -605,7 +697,7 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr,
  				     struct nf_nat_range *range)
  {
  	struct nlattr *tb[CTA_PROTONAT_MAX+1];
@@ -899026,7 +963803,7 @@
  	int err;
  
  	err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
-@@ -647,12 +737,12 @@ nfnetlink_parse_nat(struct nlattr *nat,
+@@ -647,12 +739,12 @@ nfnetlink_parse_nat(struct nlattr *nat,
  		return err;
  
  	if (tb[CTA_NAT_MINIP])
@@ -899041,7 +963818,7 @@
  
  	if (range->min_ip)
  		range->flags |= IP_NAT_RANGE_MAP_IPS;
-@@ -722,7 +812,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
+@@ -722,7 +814,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
  	ct = nf_ct_tuplehash_to_ctrack(h);
  
  	if (cda[CTA_ID]) {
@@ -899050,7 +963827,7 @@
  		if (id != (u32)(unsigned long)ct) {
  			nf_ct_put(ct);
  			return -ENOENT;
-@@ -798,11 +888,11 @@ out:
+@@ -798,11 +890,11 @@ out:
  	return err;
  }
  
@@ -899064,7 +963841,7 @@
  	d = ct->status ^ status;
  
  	if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
-@@ -828,19 +918,17 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
+@@ -828,19 +920,17 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
  			if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct,
  						&range) < 0)
  				return -EINVAL;
@@ -899088,7 +963865,7 @@
  		}
  #endif
  	}
-@@ -904,7 +992,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
+@@ -904,7 +994,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
  static inline int
  ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[])
  {
@@ -899097,7 +963874,7 @@
  
  	if (!del_timer(&ct->timeout))
  		return -ETIME;
-@@ -935,6 +1023,66 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
+@@ -935,6 +1025,66 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
  	return err;
  }
  
@@ -899164,7 +963941,7 @@
  static int
  ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
  {
-@@ -966,7 +1114,15 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
+@@ -966,7 +1116,15 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
  
  #if defined(CONFIG_NF_CONNTRACK_MARK)
  	if (cda[CTA_MARK])
@@ -899181,7 +963958,7 @@
  #endif
  
  	return 0;
-@@ -989,7 +1145,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
+@@ -989,7 +1147,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
  
  	if (!cda[CTA_TIMEOUT])
  		goto err;
@@ -899190,7 +963967,7 @@
  
  	ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
  	ct->status |= IPS_CONFIRMED;
-@@ -1008,7 +1164,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
+@@ -1008,14 +1166,15 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
  
  #if defined(CONFIG_NF_CONNTRACK_MARK)
  	if (cda[CTA_MARK])
@@ -899198,8 +963975,74 @@
 +		ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
  #endif
  
- 	helper = nf_ct_helper_find_get(rtuple);
-@@ -1193,13 +1349,15 @@ nla_put_failure:
+-	helper = nf_ct_helper_find_get(rtuple);
++	rcu_read_lock();
++	helper = __nf_ct_helper_find(rtuple);
+ 	if (helper) {
+ 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
+ 		if (help == NULL) {
+-			nf_ct_helper_put(helper);
++			rcu_read_unlock();
+ 			err = -ENOMEM;
+ 			goto err;
+ 		}
+@@ -1031,9 +1190,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
+ 
+ 	add_timer(&ct->timeout);
+ 	nf_conntrack_hash_insert(ct);
+-
+-	if (helper)
+-		nf_ct_helper_put(helper);
++	rcu_read_unlock();
+ 
+ 	return 0;
+ 
+@@ -1064,11 +1221,11 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
+ 			return err;
+ 	}
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	if (cda[CTA_TUPLE_ORIG])
+-		h = __nf_conntrack_find(&otuple, NULL);
++		h = __nf_conntrack_find(&otuple);
+ 	else if (cda[CTA_TUPLE_REPLY])
+-		h = __nf_conntrack_find(&rtuple, NULL);
++		h = __nf_conntrack_find(&rtuple);
+ 
+ 	if (h == NULL) {
+ 		struct nf_conntrack_tuple master;
+@@ -1081,9 +1238,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
+ 						    CTA_TUPLE_MASTER,
+ 						    u3);
+ 			if (err < 0)
+-				return err;
++				goto out_unlock;
+ 
+-			master_h = __nf_conntrack_find(&master, NULL);
++			master_h = __nf_conntrack_find(&master);
+ 			if (master_h == NULL) {
+ 				err = -ENOENT;
+ 				goto out_unlock;
+@@ -1092,7 +1249,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
+ 			atomic_inc(&master_ct->ct_general.use);
+ 		}
+ 
+-		write_unlock_bh(&nf_conntrack_lock);
++		spin_unlock_bh(&nf_conntrack_lock);
+ 		err = -ENOENT;
+ 		if (nlh->nlmsg_flags & NLM_F_CREATE)
+ 			err = ctnetlink_create_conntrack(cda,
+@@ -1125,7 +1282,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
+ 	}
+ 
+ out_unlock:
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 	return err;
+ }
+ 
+@@ -1193,13 +1350,15 @@ nla_put_failure:
  	return -1;
  }
  
@@ -899218,7 +964061,7 @@
  
  	if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
  		goto nla_put_failure;
-@@ -1210,8 +1368,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
+@@ -1210,8 +1369,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
  				 CTA_EXPECT_MASTER) < 0)
  		goto nla_put_failure;
  
@@ -899229,7 +964072,35 @@
  
  	return 0;
  
-@@ -1384,7 +1542,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
+@@ -1314,7 +1473,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+ 	struct hlist_node *n;
+ 	u_int8_t l3proto = nfmsg->nfgen_family;
+ 
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	last = (struct nf_conntrack_expect *)cb->args[1];
+ 	for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
+ restart:
+@@ -1331,7 +1490,8 @@ restart:
+ 						    cb->nlh->nlmsg_seq,
+ 						    IPCTNL_MSG_EXP_NEW,
+ 						    1, exp) < 0) {
+-				atomic_inc(&exp->use);
++				if (!atomic_inc_not_zero(&exp->use))
++					continue;
+ 				cb->args[1] = (unsigned long)exp;
+ 				goto out;
+ 			}
+@@ -1342,7 +1502,7 @@ restart:
+ 		}
+ 	}
+ out:
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ 	if (last)
+ 		nf_ct_expect_put(last);
+ 
+@@ -1384,7 +1544,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
  		return -ENOENT;
  
  	if (cda[CTA_EXPECT_ID]) {
@@ -899238,7 +964109,7 @@
  		if (ntohl(id) != (u32)(unsigned long)exp) {
  			nf_ct_expect_put(exp);
  			return -ENOENT;
-@@ -1438,7 +1596,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
+@@ -1438,7 +1598,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
  			return -ENOENT;
  
  		if (cda[CTA_EXPECT_ID]) {
@@ -899247,6 +964118,110 @@
  			if (ntohl(id) != (u32)(unsigned long)exp) {
  				nf_ct_expect_put(exp);
  				return -ENOENT;
+@@ -1455,10 +1615,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
+ 		struct nf_conn_help *m_help;
+ 
+ 		/* delete all expectations for this helper */
+-		write_lock_bh(&nf_conntrack_lock);
++		spin_lock_bh(&nf_conntrack_lock);
+ 		h = __nf_conntrack_helper_find_byname(name);
+ 		if (!h) {
+-			write_unlock_bh(&nf_conntrack_lock);
++			spin_unlock_bh(&nf_conntrack_lock);
+ 			return -EINVAL;
+ 		}
+ 		for (i = 0; i < nf_ct_expect_hsize; i++) {
+@@ -1473,10 +1633,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
+ 				}
+ 			}
+ 		}
+-		write_unlock_bh(&nf_conntrack_lock);
++		spin_unlock_bh(&nf_conntrack_lock);
+ 	} else {
+ 		/* This basically means we have to flush everything*/
+-		write_lock_bh(&nf_conntrack_lock);
++		spin_lock_bh(&nf_conntrack_lock);
+ 		for (i = 0; i < nf_ct_expect_hsize; i++) {
+ 			hlist_for_each_entry_safe(exp, n, next,
+ 						  &nf_ct_expect_hash[i],
+@@ -1487,7 +1647,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
+ 				}
+ 			}
+ 		}
+-		write_unlock_bh(&nf_conntrack_lock);
++		spin_unlock_bh(&nf_conntrack_lock);
+ 	}
+ 
+ 	return 0;
+@@ -1573,11 +1733,11 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
+ 	if (err < 0)
+ 		return err;
+ 
+-	write_lock_bh(&nf_conntrack_lock);
++	spin_lock_bh(&nf_conntrack_lock);
+ 	exp = __nf_ct_expect_find(&tuple);
+ 
+ 	if (!exp) {
+-		write_unlock_bh(&nf_conntrack_lock);
++		spin_unlock_bh(&nf_conntrack_lock);
+ 		err = -ENOENT;
+ 		if (nlh->nlmsg_flags & NLM_F_CREATE)
+ 			err = ctnetlink_create_expect(cda, u3);
+@@ -1587,7 +1747,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
+ 	err = -EEXIST;
+ 	if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+ 		err = ctnetlink_change_expect(exp, cda);
+-	write_unlock_bh(&nf_conntrack_lock);
++	spin_unlock_bh(&nf_conntrack_lock);
+ 
+ 	return err;
+ }
+diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
+index 099b6df..b5cb8e8 100644
+--- a/net/netfilter/nf_conntrack_pptp.c
++++ b/net/netfilter/nf_conntrack_pptp.c
+@@ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
+ 
+ #ifdef DEBUG
+ /* PptpControlMessageType names */
+-const char *pptp_msg_name[] = {
++const char *const pptp_msg_name[] = {
+ 	"UNKNOWN_MESSAGE",
+ 	"START_SESSION_REQUEST",
+ 	"START_SESSION_REPLY",
+@@ -136,7 +136,7 @@ static void pptp_expectfn(struct nf_conn *ct,
+ 
+ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
+ {
+-	struct nf_conntrack_tuple_hash *h;
++	const struct nf_conntrack_tuple_hash *h;
+ 	struct nf_conntrack_expect *exp;
+ 	struct nf_conn *sibling;
+ 
+@@ -168,7 +168,7 @@ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
+ /* timeout GRE data connections */
+ static void pptp_destroy_siblings(struct nf_conn *ct)
+ {
+-	struct nf_conn_help *help = nfct_help(ct);
++	const struct nf_conn_help *help = nfct_help(ct);
+ 	struct nf_conntrack_tuple t;
+ 
+ 	nf_ct_gre_keymap_destroy(ct);
+@@ -497,9 +497,11 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
+ 
+ {
+ 	int dir = CTINFO2DIR(ctinfo);
+-	struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
+-	struct tcphdr _tcph, *tcph;
+-	struct pptp_pkt_hdr _pptph, *pptph;
++	const struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
++	const struct tcphdr *tcph;
++	struct tcphdr _tcph;
++	const struct pptp_pkt_hdr *pptph;
++	struct pptp_pkt_hdr _pptph;
+ 	struct PptpControlHeader _ctlh, *ctlh;
+ 	union pptp_ctrl_union _pptpReq, *pptpReq;
+ 	unsigned int tcplen = skb->len - protoff;
 diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
 index 6d94706..8595b59 100644
 --- a/net/netfilter/nf_conntrack_proto.c
@@ -899276,10 +964251,10 @@
  }
  #endif
 diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
-index 13f8191..22c5dcb 100644
+index 13f8191..5545891 100644
 --- a/net/netfilter/nf_conntrack_proto_generic.c
 +++ b/net/netfilter/nf_conntrack_proto_generic.c
-@@ -40,13 +40,6 @@ static int generic_print_tuple(struct seq_file *s,
+@@ -40,27 +40,20 @@ static int generic_print_tuple(struct seq_file *s,
  	return 0;
  }
  
@@ -899291,8 +964266,25 @@
 -}
 -
  /* Returns verdict for packet, or -1 for invalid. */
- static int packet(struct nf_conn *conntrack,
+-static int packet(struct nf_conn *conntrack,
++static int packet(struct nf_conn *ct,
  		  const struct sk_buff *skb,
+ 		  unsigned int dataoff,
+ 		  enum ip_conntrack_info ctinfo,
+ 		  int pf,
+ 		  unsigned int hooknum)
+ {
+-	nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout);
++	nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout);
+ 	return NF_ACCEPT;
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int new(struct nf_conn *conntrack, const struct sk_buff *skb,
++static int new(struct nf_conn *ct, const struct sk_buff *skb,
+ 	       unsigned int dataoff)
+ {
+ 	return 1;
 @@ -104,7 +97,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
  	.pkt_to_tuple		= generic_pkt_to_tuple,
  	.invert_tuple		= generic_invert_tuple,
@@ -899301,10 +964293,37 @@
  	.packet			= packet,
  	.new			= new,
  #ifdef CONFIG_SYSCTL
+diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
+index 4a185f6..e10024a 100644
+--- a/net/netfilter/nf_conntrack_proto_gre.c
++++ b/net/netfilter/nf_conntrack_proto_gre.c
+@@ -161,9 +161,11 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb,
+ 			   unsigned int dataoff,
+ 			   struct nf_conntrack_tuple *tuple)
+ {
+-	struct gre_hdr_pptp _pgrehdr, *pgrehdr;
++	const struct gre_hdr_pptp *pgrehdr;
++	struct gre_hdr_pptp _pgrehdr;
+ 	__be16 srckey;
+-	struct gre_hdr _grehdr, *grehdr;
++	const struct gre_hdr *grehdr;
++	struct gre_hdr _grehdr;
+ 
+ 	/* first only delinearize old RFC1701 GRE header */
+ 	grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
 diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
-index cb04675..21d29e7 100644
+index cb04675..f9a0837 100644
 --- a/net/netfilter/nf_conntrack_proto_sctp.c
 +++ b/net/netfilter/nf_conntrack_proto_sctp.c
+@@ -25,7 +25,7 @@
+ #include <net/netfilter/nf_conntrack_l4proto.h>
+ #include <net/netfilter/nf_conntrack_ecache.h>
+ 
+-/* Protects conntrack->proto.sctp */
++/* Protects ct->proto.sctp */
+ static DEFINE_RWLOCK(sctp_lock);
+ 
+ /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
 @@ -49,24 +49,15 @@ static const char *sctp_conntrack_names[] = {
  #define HOURS * 60 MINS
  #define DAYS  * 24 HOURS
@@ -899896,18 +964915,48 @@
  #ifdef CONFIG_SYSCTL
  	.ctl_table_users	= &sctp_sysctl_table_users,
  	.ctl_table_header	= &sctp_sysctl_header,
+@@ -626,7 +624,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
+ #endif
+ };
+ 
+-int __init nf_conntrack_proto_sctp_init(void)
++static int __init nf_conntrack_proto_sctp_init(void)
+ {
+ 	int ret;
+ 
+@@ -649,7 +647,7 @@ int __init nf_conntrack_proto_sctp_init(void)
+ 	return ret;
+ }
+ 
+-void __exit nf_conntrack_proto_sctp_fini(void)
++static void __exit nf_conntrack_proto_sctp_fini(void)
+ {
+ 	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
+ 	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
 diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
-index 7a3f64c..64c9b91 100644
+index 7a3f64c..3e0ccca 100644
 --- a/net/netfilter/nf_conntrack_proto_tcp.c
 +++ b/net/netfilter/nf_conntrack_proto_tcp.c
-@@ -24,6 +24,7 @@
+@@ -24,8 +24,9 @@
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_l4proto.h>
  #include <net/netfilter/nf_conntrack_ecache.h>
 +#include <net/netfilter/nf_log.h>
  
- /* Protects conntrack->proto.tcp */
+-/* Protects conntrack->proto.tcp */
++/* Protects ct->proto.tcp */
  static DEFINE_RWLOCK(tcp_lock);
+ 
+ /* "Be conservative in what you do,
+@@ -45,7 +46,7 @@ static int nf_ct_tcp_max_retrans __read_mostly = 3;
+   /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+      closely.  They're more complex. --RR */
+ 
+-static const char *tcp_conntrack_names[] = {
++static const char *const tcp_conntrack_names[] = {
+ 	"NONE",
+ 	"SYN_SENT",
+ 	"SYN_RECV",
 @@ -63,32 +64,21 @@ static const char *tcp_conntrack_names[] = {
  #define HOURS * 60 MINS
  #define DAYS * 24 HOURS
@@ -899960,7 +965009,143 @@
  	{
  /* ORIGINAL */
  /* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-@@ -783,9 +773,7 @@ static int tcp_error(struct sk_buff *skb,
+@@ -271,7 +261,8 @@ static int tcp_pkt_to_tuple(const struct sk_buff *skb,
+ 			    unsigned int dataoff,
+ 			    struct nf_conntrack_tuple *tuple)
+ {
+-	struct tcphdr _hdr, *hp;
++	const struct tcphdr *hp;
++	struct tcphdr _hdr;
+ 
+ 	/* Actually only need first 8 bytes. */
+ 	hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+@@ -302,13 +293,12 @@ static int tcp_print_tuple(struct seq_file *s,
+ }
+ 
+ /* Print out the private part of the conntrack. */
+-static int tcp_print_conntrack(struct seq_file *s,
+-			       const struct nf_conn *conntrack)
++static int tcp_print_conntrack(struct seq_file *s, const struct nf_conn *ct)
+ {
+ 	enum tcp_conntrack state;
+ 
+ 	read_lock_bh(&tcp_lock);
+-	state = conntrack->proto.tcp.state;
++	state = ct->proto.tcp.state;
+ 	read_unlock_bh(&tcp_lock);
+ 
+ 	return seq_printf(s, "%s ", tcp_conntrack_names[state]);
+@@ -354,7 +344,7 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
+ static inline __u32 segment_seq_plus_len(__u32 seq,
+ 					 size_t len,
+ 					 unsigned int dataoff,
+-					 struct tcphdr *tcph)
++					 const struct tcphdr *tcph)
+ {
+ 	/* XXX Should I use payload length field in IP/IPv6 header ?
+ 	 * - YK */
+@@ -373,11 +363,11 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
+  */
+ static void tcp_options(const struct sk_buff *skb,
+ 			unsigned int dataoff,
+-			struct tcphdr *tcph,
++			const struct tcphdr *tcph,
+ 			struct ip_ct_tcp_state *state)
+ {
+ 	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
+-	unsigned char *ptr;
++	const unsigned char *ptr;
+ 	int length = (tcph->doff*4) - sizeof(struct tcphdr);
+ 
+ 	if (!length)
+@@ -428,10 +418,10 @@ static void tcp_options(const struct sk_buff *skb,
+ }
+ 
+ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
+-		     struct tcphdr *tcph, __u32 *sack)
++                     const struct tcphdr *tcph, __u32 *sack)
+ {
+ 	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
+-	unsigned char *ptr;
++	const unsigned char *ptr;
+ 	int length = (tcph->doff*4) - sizeof(struct tcphdr);
+ 	__u32 tmp;
+ 
+@@ -488,18 +478,18 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
+ 	}
+ }
+ 
+-static int tcp_in_window(struct nf_conn *ct,
++static int tcp_in_window(const struct nf_conn *ct,
+ 			 struct ip_ct_tcp *state,
+ 			 enum ip_conntrack_dir dir,
+ 			 unsigned int index,
+ 			 const struct sk_buff *skb,
+ 			 unsigned int dataoff,
+-			 struct tcphdr *tcph,
++			 const struct tcphdr *tcph,
+ 			 int pf)
+ {
+ 	struct ip_ct_tcp_state *sender = &state->seen[dir];
+ 	struct ip_ct_tcp_state *receiver = &state->seen[!dir];
+-	struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
++	const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
+ 	__u32 seq, ack, sack, end, win, swin;
+ 	int res;
+ 
+@@ -697,14 +687,14 @@ static int tcp_in_window(struct nf_conn *ct,
+ #ifdef CONFIG_NF_NAT_NEEDED
+ /* Update sender->td_end after NAT successfully mangled the packet */
+ /* Caller must linearize skb at tcp header. */
+-void nf_conntrack_tcp_update(struct sk_buff *skb,
++void nf_conntrack_tcp_update(const struct sk_buff *skb,
+ 			     unsigned int dataoff,
+-			     struct nf_conn *conntrack,
++			     struct nf_conn *ct,
+ 			     int dir)
+ {
+-	struct tcphdr *tcph = (void *)skb->data + dataoff;
+-	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
+-	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
++	const struct tcphdr *tcph = (const void *)skb->data + dataoff;
++	const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
++	const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir];
+ 	__u32 end;
+ 
+ 	end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
+@@ -713,9 +703,9 @@ void nf_conntrack_tcp_update(struct sk_buff *skb,
+ 	/*
+ 	 * We have to worry for the ack in the reply packet only...
+ 	 */
+-	if (after(end, conntrack->proto.tcp.seen[dir].td_end))
+-		conntrack->proto.tcp.seen[dir].td_end = end;
+-	conntrack->proto.tcp.last_end = end;
++	if (after(end, ct->proto.tcp.seen[dir].td_end))
++		ct->proto.tcp.seen[dir].td_end = end;
++	ct->proto.tcp.last_end = end;
+ 	write_unlock_bh(&tcp_lock);
+ 	pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
+ 		 "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+@@ -737,7 +727,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update);
+ #define	TH_CWR	0x80
+ 
+ /* table of valid flag combinations - PUSH, ECE and CWR are always valid */
+-static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
++static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
+ {
+ 	[TH_SYN]			= 1,
+ 	[TH_SYN|TH_URG]			= 1,
+@@ -757,7 +747,8 @@ static int tcp_error(struct sk_buff *skb,
+ 		     int pf,
+ 		     unsigned int hooknum)
+ {
+-	struct tcphdr _tcph, *th;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
+ 	unsigned int tcplen = skb->len - dataoff;
+ 	u_int8_t tcpflags;
+ 
+@@ -783,9 +774,7 @@ static int tcp_error(struct sk_buff *skb,
  	 * because the checksum is assumed to be correct.
  	 */
  	/* FIXME: Source route IP option packets --RR */
@@ -899971,18 +965156,281 @@
  	    nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
  		if (LOG_INVALID(IPPROTO_TCP))
  			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
-@@ -942,8 +930,8 @@ static int tcp_packet(struct nf_conn *conntrack,
+@@ -806,7 +795,7 @@ static int tcp_error(struct sk_buff *skb,
+ }
+ 
+ /* Returns verdict for packet, or -1 for invalid. */
+-static int tcp_packet(struct nf_conn *conntrack,
++static int tcp_packet(struct nf_conn *ct,
+ 		      const struct sk_buff *skb,
+ 		      unsigned int dataoff,
+ 		      enum ip_conntrack_info ctinfo,
+@@ -816,7 +805,8 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 	struct nf_conntrack_tuple *tuple;
+ 	enum tcp_conntrack new_state, old_state;
+ 	enum ip_conntrack_dir dir;
+-	struct tcphdr *th, _tcph;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
+ 	unsigned long timeout;
+ 	unsigned int index;
+ 
+@@ -824,26 +814,24 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 	BUG_ON(th == NULL);
+ 
+ 	write_lock_bh(&tcp_lock);
+-	old_state = conntrack->proto.tcp.state;
++	old_state = ct->proto.tcp.state;
+ 	dir = CTINFO2DIR(ctinfo);
+ 	index = get_conntrack_index(th);
+ 	new_state = tcp_conntracks[dir][index][old_state];
+-	tuple = &conntrack->tuplehash[dir].tuple;
++	tuple = &ct->tuplehash[dir].tuple;
+ 
+ 	switch (new_state) {
+ 	case TCP_CONNTRACK_SYN_SENT:
+ 		if (old_state < TCP_CONNTRACK_TIME_WAIT)
+ 			break;
+-		if ((conntrack->proto.tcp.seen[!dir].flags &
+-			IP_CT_TCP_FLAG_CLOSE_INIT)
+-		    || (conntrack->proto.tcp.last_dir == dir
+-		        && conntrack->proto.tcp.last_index == TCP_RST_SET)) {
++		if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_CLOSE_INIT)
++		    || (ct->proto.tcp.last_dir == dir
++		        && ct->proto.tcp.last_index == TCP_RST_SET)) {
+ 			/* Attempt to reopen a closed/aborted connection.
+ 			 * Delete this connection and look up again. */
+ 			write_unlock_bh(&tcp_lock);
+-			if (del_timer(&conntrack->timeout))
+-				conntrack->timeout.function((unsigned long)
+-							    conntrack);
++			if (del_timer(&ct->timeout))
++				ct->timeout.function((unsigned long)ct);
+ 			return -NF_REPEAT;
+ 		}
+ 		/* Fall through */
+@@ -855,10 +843,9 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 		 * c) ACK in reply direction after initial SYN in original.
+ 		 */
+ 		if (index == TCP_SYNACK_SET
+-		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
+-		    && conntrack->proto.tcp.last_dir != dir
+-		    && ntohl(th->ack_seq) ==
+-			     conntrack->proto.tcp.last_end) {
++		    && ct->proto.tcp.last_index == TCP_SYN_SET
++		    && ct->proto.tcp.last_dir != dir
++		    && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
+ 			/* This SYN/ACK acknowledges a SYN that we earlier
+ 			 * ignored as invalid. This means that the client and
+ 			 * the server are both in sync, while the firewall is
+@@ -870,15 +857,14 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 			if (LOG_INVALID(IPPROTO_TCP))
+ 				nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ 					  "nf_ct_tcp: killing out of sync session ");
+-			if (del_timer(&conntrack->timeout))
+-				conntrack->timeout.function((unsigned long)
+-							    conntrack);
++			if (del_timer(&ct->timeout))
++				ct->timeout.function((unsigned long)ct);
+ 			return -NF_DROP;
+ 		}
+-		conntrack->proto.tcp.last_index = index;
+-		conntrack->proto.tcp.last_dir = dir;
+-		conntrack->proto.tcp.last_seq = ntohl(th->seq);
+-		conntrack->proto.tcp.last_end =
++		ct->proto.tcp.last_index = index;
++		ct->proto.tcp.last_dir = dir;
++		ct->proto.tcp.last_seq = ntohl(th->seq);
++		ct->proto.tcp.last_end =
+ 		    segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
+ 
+ 		write_unlock_bh(&tcp_lock);
+@@ -897,11 +883,11 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 		return -NF_ACCEPT;
+ 	case TCP_CONNTRACK_CLOSE:
+ 		if (index == TCP_RST_SET
+-		    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
+-			 && conntrack->proto.tcp.last_index == TCP_SYN_SET)
+-			|| (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
+-			    && conntrack->proto.tcp.last_index == TCP_ACK_SET))
+-		    && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
++		    && ((test_bit(IPS_SEEN_REPLY_BIT, &ct->status)
++			 && ct->proto.tcp.last_index == TCP_SYN_SET)
++			|| (!test_bit(IPS_ASSURED_BIT, &ct->status)
++			    && ct->proto.tcp.last_index == TCP_ACK_SET))
++		    && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
+ 			/* RST sent to invalid SYN or ACK we had let through
+ 			 * at a) and c) above:
+ 			 *
+@@ -919,15 +905,15 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 		break;
+ 	}
+ 
+-	if (!tcp_in_window(conntrack, &conntrack->proto.tcp, dir, index,
++	if (!tcp_in_window(ct, &ct->proto.tcp, dir, index,
+ 			   skb, dataoff, th, pf)) {
+ 		write_unlock_bh(&tcp_lock);
+ 		return -NF_ACCEPT;
+ 	}
+      in_window:
+ 	/* From now on we have got in-window packets */
+-	conntrack->proto.tcp.last_index = index;
+-	conntrack->proto.tcp.last_dir = dir;
++	ct->proto.tcp.last_index = index;
++	ct->proto.tcp.last_dir = dir;
+ 
+ 	pr_debug("tcp_conntracks: ");
+ 	NF_CT_DUMP_TUPLE(tuple);
+@@ -936,55 +922,55 @@ static int tcp_packet(struct nf_conn *conntrack,
+ 		 (th->fin ? 1 : 0), (th->rst ? 1 : 0),
+ 		 old_state, new_state);
+ 
+-	conntrack->proto.tcp.state = new_state;
++	ct->proto.tcp.state = new_state;
+ 	if (old_state != new_state
+ 	    && (new_state == TCP_CONNTRACK_FIN_WAIT
  		|| new_state == TCP_CONNTRACK_CLOSE))
- 		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
- 	timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans
+-		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
+-	timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans
 -		  && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
 -		  ? nf_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
++		ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
++	timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans
 +		  && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
 +		  ? nf_ct_tcp_timeout_max_retrans : tcp_timeouts[new_state];
  	write_unlock_bh(&tcp_lock);
  
  	nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
-@@ -1074,14 +1062,13 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
+ 	if (new_state != old_state)
+ 		nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
+ 
+-	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
++	if (!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+ 		/* If only reply is a RST, we can consider ourselves not to
+ 		   have an established connection: this is a fairly common
+ 		   problem case, so we can delete the conntrack
+ 		   immediately.  --RR */
+ 		if (th->rst) {
+-			if (del_timer(&conntrack->timeout))
+-				conntrack->timeout.function((unsigned long)
+-							    conntrack);
++			if (del_timer(&ct->timeout))
++				ct->timeout.function((unsigned long)ct);
+ 			return NF_ACCEPT;
+ 		}
+-	} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
++	} else if (!test_bit(IPS_ASSURED_BIT, &ct->status)
+ 		   && (old_state == TCP_CONNTRACK_SYN_RECV
+ 		       || old_state == TCP_CONNTRACK_ESTABLISHED)
+ 		   && new_state == TCP_CONNTRACK_ESTABLISHED) {
+ 		/* Set ASSURED if we see see valid ack in ESTABLISHED
+ 		   after SYN_RECV or a valid answer for a picked up
+ 		   connection. */
+-		set_bit(IPS_ASSURED_BIT, &conntrack->status);
++		set_bit(IPS_ASSURED_BIT, &ct->status);
+ 		nf_conntrack_event_cache(IPCT_STATUS, skb);
+ 	}
+-	nf_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
++	nf_ct_refresh_acct(ct, ctinfo, skb, timeout);
+ 
+ 	return NF_ACCEPT;
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int tcp_new(struct nf_conn *conntrack,
++static int tcp_new(struct nf_conn *ct,
+ 		   const struct sk_buff *skb,
+ 		   unsigned int dataoff)
+ {
+ 	enum tcp_conntrack new_state;
+-	struct tcphdr *th, _tcph;
+-	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
+-	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
++	const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
++	const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
+ 
+ 	th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+ 	BUG_ON(th == NULL);
+@@ -1002,17 +988,17 @@ static int tcp_new(struct nf_conn *conntrack,
+ 
+ 	if (new_state == TCP_CONNTRACK_SYN_SENT) {
+ 		/* SYN packet */
+-		conntrack->proto.tcp.seen[0].td_end =
++		ct->proto.tcp.seen[0].td_end =
+ 			segment_seq_plus_len(ntohl(th->seq), skb->len,
+ 					     dataoff, th);
+-		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+-		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+-			conntrack->proto.tcp.seen[0].td_maxwin = 1;
+-		conntrack->proto.tcp.seen[0].td_maxend =
+-			conntrack->proto.tcp.seen[0].td_end;
+-
+-		tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
+-		conntrack->proto.tcp.seen[1].flags = 0;
++		ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
++		if (ct->proto.tcp.seen[0].td_maxwin == 0)
++			ct->proto.tcp.seen[0].td_maxwin = 1;
++		ct->proto.tcp.seen[0].td_maxend =
++			ct->proto.tcp.seen[0].td_end;
++
++		tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]);
++		ct->proto.tcp.seen[1].flags = 0;
+ 	} else if (nf_ct_tcp_loose == 0) {
+ 		/* Don't try to pick up connections. */
+ 		return 0;
+@@ -1022,32 +1008,32 @@ static int tcp_new(struct nf_conn *conntrack,
+ 		 * its history is lost for us.
+ 		 * Let's try to use the data from the packet.
+ 		 */
+-		conntrack->proto.tcp.seen[0].td_end =
++		ct->proto.tcp.seen[0].td_end =
+ 			segment_seq_plus_len(ntohl(th->seq), skb->len,
+ 					     dataoff, th);
+-		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+-		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+-			conntrack->proto.tcp.seen[0].td_maxwin = 1;
+-		conntrack->proto.tcp.seen[0].td_maxend =
+-			conntrack->proto.tcp.seen[0].td_end +
+-			conntrack->proto.tcp.seen[0].td_maxwin;
+-		conntrack->proto.tcp.seen[0].td_scale = 0;
++		ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
++		if (ct->proto.tcp.seen[0].td_maxwin == 0)
++			ct->proto.tcp.seen[0].td_maxwin = 1;
++		ct->proto.tcp.seen[0].td_maxend =
++			ct->proto.tcp.seen[0].td_end +
++			ct->proto.tcp.seen[0].td_maxwin;
++		ct->proto.tcp.seen[0].td_scale = 0;
+ 
+ 		/* We assume SACK and liberal window checking to handle
+ 		 * window scaling */
+-		conntrack->proto.tcp.seen[0].flags =
+-		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+-						     IP_CT_TCP_FLAG_BE_LIBERAL;
++		ct->proto.tcp.seen[0].flags =
++		ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
++					      IP_CT_TCP_FLAG_BE_LIBERAL;
+ 	}
+ 
+-	conntrack->proto.tcp.seen[1].td_end = 0;
+-	conntrack->proto.tcp.seen[1].td_maxend = 0;
+-	conntrack->proto.tcp.seen[1].td_maxwin = 1;
+-	conntrack->proto.tcp.seen[1].td_scale = 0;
++	ct->proto.tcp.seen[1].td_end = 0;
++	ct->proto.tcp.seen[1].td_maxend = 0;
++	ct->proto.tcp.seen[1].td_maxwin = 1;
++	ct->proto.tcp.seen[1].td_scale = 0;
+ 
+ 	/* tcp_packet will set them */
+-	conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
+-	conntrack->proto.tcp.last_index = TCP_NONE_SET;
++	ct->proto.tcp.state = TCP_CONNTRACK_NONE;
++	ct->proto.tcp.last_index = TCP_NONE_SET;
+ 
+ 	pr_debug("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
+ 		 "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+@@ -1074,14 +1060,13 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
  	if (!nest_parms)
  		goto nla_put_failure;
  
@@ -900002,7 +965450,27 @@
  
  	tmp.flags = ct->proto.tcp.seen[0].flags;
  	NLA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
-@@ -1128,8 +1115,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
+@@ -1111,16 +1096,16 @@ static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = {
+ 
+ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
+ {
+-	struct nlattr *attr = cda[CTA_PROTOINFO_TCP];
++	struct nlattr *pattr = cda[CTA_PROTOINFO_TCP];
+ 	struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
+ 	int err;
+ 
+ 	/* updates could not contain anything about the private
+ 	 * protocol info, in that case skip the parsing */
+-	if (!attr)
++	if (!pattr)
+ 		return 0;
+ 
+-	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, tcp_nla_policy);
++	err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr, tcp_nla_policy);
+ 	if (err < 0)
+ 		return err;
+ 
+@@ -1128,8 +1113,7 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
  		return -EINVAL;
  
  	write_lock_bh(&tcp_lock);
@@ -900012,7 +965480,7 @@
  
  	if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) {
  		struct nf_ct_tcp_flags *attr =
-@@ -1149,10 +1135,10 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
+@@ -1149,10 +1133,10 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
  	    tb[CTA_PROTOINFO_TCP_WSCALE_REPLY] &&
  	    ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
  	    ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_WINDOW_SCALE) {
@@ -900027,7 +965495,7 @@
  	}
  	write_unlock_bh(&tcp_lock);
  
-@@ -1166,56 +1152,56 @@ static struct ctl_table_header *tcp_sysctl_header;
+@@ -1166,56 +1150,56 @@ static struct ctl_table_header *tcp_sysctl_header;
  static struct ctl_table tcp_sysctl_table[] = {
  	{
  		.procname	= "nf_conntrack_tcp_timeout_syn_sent",
@@ -900092,7 +965560,7 @@
  		.maxlen		= sizeof(unsigned int),
  		.mode		= 0644,
  		.proc_handler	= &proc_dointvec_jiffies,
-@@ -1260,56 +1246,56 @@ static struct ctl_table tcp_sysctl_table[] = {
+@@ -1260,56 +1244,56 @@ static struct ctl_table tcp_sysctl_table[] = {
  static struct ctl_table tcp_compat_sysctl_table[] = {
  	{
  		.procname	= "ip_conntrack_tcp_timeout_syn_sent",
@@ -900158,7 +965626,7 @@
  		.mode		= 0644,
  		.proc_handler	= &proc_dointvec_jiffies,
 diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
-index b3e7ecb..3848754 100644
+index b3e7ecb..b8a35cc 100644
 --- a/net/netfilter/nf_conntrack_proto_udp.c
 +++ b/net/netfilter/nf_conntrack_proto_udp.c
 @@ -21,6 +21,7 @@
@@ -900169,7 +965637,17 @@
  
  static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
  static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
-@@ -59,13 +60,6 @@ static int udp_print_tuple(struct seq_file *s,
+@@ -29,7 +30,8 @@ static int udp_pkt_to_tuple(const struct sk_buff *skb,
+ 			     unsigned int dataoff,
+ 			     struct nf_conntrack_tuple *tuple)
+ {
+-	struct udphdr _hdr, *hp;
++	const struct udphdr *hp;
++	struct udphdr _hdr;
+ 
+ 	/* Actually only need first 8 bytes. */
+ 	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+@@ -59,15 +61,8 @@ static int udp_print_tuple(struct seq_file *s,
  			  ntohs(tuple->dst.u.udp.port));
  }
  
@@ -900181,9 +965659,48 @@
 -}
 -
  /* Returns verdict for packet, and may modify conntracktype */
- static int udp_packet(struct nf_conn *conntrack,
+-static int udp_packet(struct nf_conn *conntrack,
++static int udp_packet(struct nf_conn *ct,
  		      const struct sk_buff *skb,
-@@ -128,9 +122,7 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
+ 		      unsigned int dataoff,
+ 		      enum ip_conntrack_info ctinfo,
+@@ -76,20 +71,19 @@ static int udp_packet(struct nf_conn *conntrack,
+ {
+ 	/* If we've seen traffic both ways, this is some kind of UDP
+ 	   stream.  Extend timeout. */
+-	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+-		nf_ct_refresh_acct(conntrack, ctinfo, skb,
+-				   nf_ct_udp_timeout_stream);
++	if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
++		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream);
+ 		/* Also, more likely to be important, and not a probe */
+-		if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
++		if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
+ 			nf_conntrack_event_cache(IPCT_STATUS, skb);
+ 	} else
+-		nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout);
++		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout);
+ 
+ 	return NF_ACCEPT;
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
++static int udp_new(struct nf_conn *ct, const struct sk_buff *skb,
+ 		   unsigned int dataoff)
+ {
+ 	return 1;
+@@ -101,7 +95,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
+ 		     unsigned int hooknum)
+ {
+ 	unsigned int udplen = skb->len - dataoff;
+-	struct udphdr _hdr, *hdr;
++	const struct udphdr *hdr;
++	struct udphdr _hdr;
+ 
+ 	/* Header is too small? */
+ 	hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+@@ -128,9 +123,7 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
  	 * We skip checking packets on the outgoing path
  	 * because the checksum is assumed to be correct.
  	 * FIXME: Source route IP option packets --RR */
@@ -900194,7 +965711,7 @@
  	    nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
  		if (LOG_INVALID(IPPROTO_UDP))
  			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
-@@ -194,7 +186,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
+@@ -194,7 +187,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
  	.pkt_to_tuple		= udp_pkt_to_tuple,
  	.invert_tuple		= udp_invert_tuple,
  	.print_tuple		= udp_print_tuple,
@@ -900202,7 +965719,7 @@
  	.packet			= udp_packet,
  	.new			= udp_new,
  	.error			= udp_error,
-@@ -222,7 +213,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
+@@ -222,7 +214,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
  	.pkt_to_tuple		= udp_pkt_to_tuple,
  	.invert_tuple		= udp_invert_tuple,
  	.print_tuple		= udp_print_tuple,
@@ -900211,7 +965728,7 @@
  	.new			= udp_new,
  	.error			= udp_error,
 diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
-index b8981dd..070056d 100644
+index b8981dd..9dd03c7 100644
 --- a/net/netfilter/nf_conntrack_proto_udplite.c
 +++ b/net/netfilter/nf_conntrack_proto_udplite.c
 @@ -22,6 +22,7 @@
@@ -900222,7 +965739,17 @@
  
  static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ;
  static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ;
-@@ -58,13 +59,6 @@ static int udplite_print_tuple(struct seq_file *s,
+@@ -30,7 +31,8 @@ static int udplite_pkt_to_tuple(const struct sk_buff *skb,
+ 				unsigned int dataoff,
+ 				struct nf_conntrack_tuple *tuple)
+ {
+-	struct udphdr _hdr, *hp;
++	const struct udphdr *hp;
++	struct udphdr _hdr;
+ 
+ 	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ 	if (hp == NULL)
+@@ -58,15 +60,8 @@ static int udplite_print_tuple(struct seq_file *s,
  			  ntohs(tuple->dst.u.udp.port));
  }
  
@@ -900234,9 +965761,49 @@
 -}
 -
  /* Returns verdict for packet, and may modify conntracktype */
- static int udplite_packet(struct nf_conn *conntrack,
+-static int udplite_packet(struct nf_conn *conntrack,
++static int udplite_packet(struct nf_conn *ct,
  			  const struct sk_buff *skb,
-@@ -133,8 +127,7 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
+ 			  unsigned int dataoff,
+ 			  enum ip_conntrack_info ctinfo,
+@@ -75,21 +70,20 @@ static int udplite_packet(struct nf_conn *conntrack,
+ {
+ 	/* If we've seen traffic both ways, this is some kind of UDP
+ 	   stream.  Extend timeout. */
+-	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+-		nf_ct_refresh_acct(conntrack, ctinfo, skb,
++	if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
++		nf_ct_refresh_acct(ct, ctinfo, skb,
+ 				   nf_ct_udplite_timeout_stream);
+ 		/* Also, more likely to be important, and not a probe */
+-		if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
++		if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
+ 			nf_conntrack_event_cache(IPCT_STATUS, skb);
+ 	} else
+-		nf_ct_refresh_acct(conntrack, ctinfo, skb,
+-				   nf_ct_udplite_timeout);
++		nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout);
+ 
+ 	return NF_ACCEPT;
+ }
+ 
+ /* Called when a new connection for this protocol found. */
+-static int udplite_new(struct nf_conn *conntrack, const struct sk_buff *skb,
++static int udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
+ 		       unsigned int dataoff)
+ {
+ 	return 1;
+@@ -101,7 +95,8 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
+ 			 unsigned int hooknum)
+ {
+ 	unsigned int udplen = skb->len - dataoff;
+-	struct udphdr _hdr, *hdr;
++	const struct udphdr *hdr;
++	struct udphdr _hdr;
+ 	unsigned int cscov;
+ 
+ 	/* Header is too small? */
+@@ -133,8 +128,7 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
  
  	/* Checksum invalid? Ignore. */
  	if (nf_conntrack_checksum && !skb_csum_unnecessary(skb) &&
@@ -900246,7 +965813,7 @@
  		if (pf == PF_INET) {
  			struct iphdr *iph = ip_hdr(skb);
  
-@@ -198,7 +191,6 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
+@@ -198,7 +192,6 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
  	.pkt_to_tuple		= udplite_pkt_to_tuple,
  	.invert_tuple		= udplite_invert_tuple,
  	.print_tuple		= udplite_print_tuple,
@@ -900254,7 +965821,7 @@
  	.packet			= udplite_packet,
  	.new			= udplite_new,
  	.error			= udplite_error,
-@@ -222,7 +214,6 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
+@@ -222,7 +215,6 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
  	.pkt_to_tuple		= udplite_pkt_to_tuple,
  	.invert_tuple		= udplite_invert_tuple,
  	.print_tuple		= udplite_print_tuple,
@@ -900262,21 +965829,113 @@
  	.packet			= udplite_packet,
  	.new			= udplite_new,
  	.error			= udplite_error,
+diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
+index b5a16c6..a70051d 100644
+--- a/net/netfilter/nf_conntrack_sane.c
++++ b/net/netfilter/nf_conntrack_sane.c
+@@ -62,8 +62,9 @@ static int help(struct sk_buff *skb,
+ 		enum ip_conntrack_info ctinfo)
+ {
+ 	unsigned int dataoff, datalen;
+-	struct tcphdr _tcph, *th;
+-	char *sb_ptr;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
++	void *sb_ptr;
+ 	int ret = NF_ACCEPT;
+ 	int dir = CTINFO2DIR(ctinfo);
+ 	struct nf_ct_sane_master *ct_sane_info;
+@@ -99,7 +100,7 @@ static int help(struct sk_buff *skb,
+ 		if (datalen != sizeof(struct sane_request))
+ 			goto out;
+ 
+-		req = (struct sane_request *)sb_ptr;
++		req = sb_ptr;
+ 		if (req->RPC_code != htonl(SANE_NET_START)) {
+ 			/* Not an interesting command */
+ 			ct_sane_info->state = SANE_STATE_NORMAL;
+@@ -123,7 +124,7 @@ static int help(struct sk_buff *skb,
+ 		goto out;
+ 	}
+ 
+-	reply = (struct sane_reply_net_start *)sb_ptr;
++	reply = sb_ptr;
+ 	if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
+ 		/* saned refused the command */
+ 		pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
 diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
-index 515abff..47d8947 100644
+index 515abff..c521c89 100644
 --- a/net/netfilter/nf_conntrack_sip.c
 +++ b/net/netfilter/nf_conntrack_sip.c
-@@ -247,7 +247,7 @@ static int skp_digits_len(struct nf_conn *ct, const char *dptr,
+@@ -28,7 +28,7 @@ MODULE_ALIAS("ip_conntrack_sip");
+ 
+ #define MAX_PORTS	8
+ static unsigned short ports[MAX_PORTS];
+-static int ports_c;
++static unsigned int ports_c;
+ module_param_array(ports, ushort, &ports_c, 0400);
+ MODULE_PARM_DESC(ports, "port numbers of SIP servers");
+ 
+@@ -48,10 +48,10 @@ unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
+ 				const char *dptr) __read_mostly;
+ EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
+ 
+-static int digits_len(struct nf_conn *, const char *, const char *, int *);
+-static int epaddr_len(struct nf_conn *, const char *, const char *, int *);
+-static int skp_digits_len(struct nf_conn *, const char *, const char *, int *);
+-static int skp_epaddr_len(struct nf_conn *, const char *, const char *, int *);
++static int digits_len(const struct nf_conn *, const char *, const char *, int *);
++static int epaddr_len(const struct nf_conn *, const char *, const char *, int *);
++static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *);
++static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *);
+ 
+ struct sip_header_nfo {
+ 	const char	*lname;
+@@ -61,7 +61,7 @@ struct sip_header_nfo {
+ 	size_t		snlen;
+ 	size_t		ln_strlen;
+ 	int		case_sensitive;
+-	int		(*match_len)(struct nf_conn *, const char *,
++	int		(*match_len)(const struct nf_conn *, const char *,
+ 				     const char *, int *);
+ };
+ 
+@@ -225,7 +225,7 @@ const char *ct_sip_search(const char *needle, const char *haystack,
+ }
+ EXPORT_SYMBOL_GPL(ct_sip_search);
+ 
+-static int digits_len(struct nf_conn *ct, const char *dptr,
++static int digits_len(const struct nf_conn *ct, const char *dptr,
+ 		      const char *limit, int *shift)
+ {
+ 	int len = 0;
+@@ -237,7 +237,7 @@ static int digits_len(struct nf_conn *ct, const char *dptr,
  }
  
- static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
+ /* get digits length, skipping blank spaces. */
+-static int skp_digits_len(struct nf_conn *ct, const char *dptr,
++static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
+ 			  const char *limit, int *shift)
+ {
+ 	for (; dptr <= limit && *dptr == ' '; dptr++)
+@@ -246,8 +246,9 @@ static int skp_digits_len(struct nf_conn *ct, const char *dptr,
+ 	return digits_len(ct, dptr, limit, shift);
+ }
+ 
+-static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
 -		      union nf_conntrack_address *addr, const char *limit)
-+		      union nf_inet_addr *addr, const char *limit)
++static int parse_addr(const struct nf_conn *ct, const char *cp,
++                      const char **endp, union nf_inet_addr *addr,
++                      const char *limit)
  {
  	const char *end;
  	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
-@@ -275,7 +275,7 @@ static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
- static int epaddr_len(struct nf_conn *ct, const char *dptr,
+@@ -272,10 +273,10 @@ static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
+ }
+ 
+ /* skip ip address. returns its length. */
+-static int epaddr_len(struct nf_conn *ct, const char *dptr,
++static int epaddr_len(const struct nf_conn *ct, const char *dptr,
  		      const char *limit, int *shift)
  {
 -	union nf_conntrack_address addr;
@@ -900284,7 +965943,25 @@
  	const char *aux = dptr;
  
  	if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
-@@ -366,7 +366,7 @@ EXPORT_SYMBOL_GPL(ct_sip_get_info);
+@@ -292,7 +293,7 @@ static int epaddr_len(struct nf_conn *ct, const char *dptr,
+ }
+ 
+ /* get address length, skiping user info. */
+-static int skp_epaddr_len(struct nf_conn *ct, const char *dptr,
++static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
+ 			  const char *limit, int *shift)
+ {
+ 	const char *start = dptr;
+@@ -319,7 +320,7 @@ static int skp_epaddr_len(struct nf_conn *ct, const char *dptr,
+ }
+ 
+ /* Returns 0 if not found, -1 error parsing. */
+-int ct_sip_get_info(struct nf_conn *ct,
++int ct_sip_get_info(const struct nf_conn *ct,
+ 		    const char *dptr, size_t dlen,
+ 		    unsigned int *matchoff,
+ 		    unsigned int *matchlen,
+@@ -366,7 +367,7 @@ EXPORT_SYMBOL_GPL(ct_sip_get_info);
  static int set_expected_rtp(struct sk_buff *skb,
  			    struct nf_conn *ct,
  			    enum ip_conntrack_info ctinfo,
@@ -900293,7 +965970,7 @@
  			    __be16 port,
  			    const char *dptr)
  {
-@@ -403,7 +403,7 @@ static int sip_help(struct sk_buff *skb,
+@@ -403,11 +404,11 @@ static int sip_help(struct sk_buff *skb,
  		    enum ip_conntrack_info ctinfo)
  {
  	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
@@ -900302,23 +965979,184 @@
  	unsigned int dataoff, datalen;
  	const char *dptr;
  	int ret = NF_ACCEPT;
+-	int matchoff, matchlen;
++	unsigned int matchoff, matchlen;
+ 	u_int16_t port;
+ 	enum sip_header_pos pos;
+ 	typeof(nf_nat_sip_hook) nf_nat_sip;
 diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
-index 9efdd37..696074a 100644
+index 9efdd37..e88e96a 100644
 --- a/net/netfilter/nf_conntrack_standalone.c
 +++ b/net/netfilter/nf_conntrack_standalone.c
-@@ -142,10 +142,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
- 		       ? (long)(conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
+@@ -31,8 +31,8 @@ MODULE_LICENSE("GPL");
+ #ifdef CONFIG_PROC_FS
+ int
+ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
+-	    struct nf_conntrack_l3proto *l3proto,
+-	    struct nf_conntrack_l4proto *l4proto)
++            const struct nf_conntrack_l3proto *l3proto,
++            const struct nf_conntrack_l4proto *l4proto)
+ {
+ 	return l3proto->print_tuple(s, tuple) || l4proto->print_tuple(s, tuple);
+ }
+@@ -58,12 +58,14 @@ struct ct_iter_state {
+ static struct hlist_node *ct_get_first(struct seq_file *seq)
+ {
+ 	struct ct_iter_state *st = seq->private;
++	struct hlist_node *n;
+ 
+ 	for (st->bucket = 0;
+ 	     st->bucket < nf_conntrack_htable_size;
+ 	     st->bucket++) {
+-		if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
+-			return nf_conntrack_hash[st->bucket].first;
++		n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
++		if (n)
++			return n;
+ 	}
+ 	return NULL;
+ }
+@@ -73,11 +75,11 @@ static struct hlist_node *ct_get_next(struct seq_file *seq,
+ {
+ 	struct ct_iter_state *st = seq->private;
+ 
+-	head = head->next;
++	head = rcu_dereference(head->next);
+ 	while (head == NULL) {
+ 		if (++st->bucket >= nf_conntrack_htable_size)
+ 			return NULL;
+-		head = nf_conntrack_hash[st->bucket].first;
++		head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+ 	}
+ 	return head;
+ }
+@@ -93,8 +95,9 @@ static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
+ }
+ 
+ static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(RCU)
+ {
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 	return ct_get_idx(seq, *pos);
+ }
+ 
+@@ -105,82 +108,80 @@ static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
+ 
+ static void ct_seq_stop(struct seq_file *s, void *v)
++	__releases(RCU)
+ {
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ }
+ 
+ /* return 0 on success, 1 in case of error */
+ static int ct_seq_show(struct seq_file *s, void *v)
+ {
+ 	const struct nf_conntrack_tuple_hash *hash = v;
+-	const struct nf_conn *conntrack = nf_ct_tuplehash_to_ctrack(hash);
+-	struct nf_conntrack_l3proto *l3proto;
+-	struct nf_conntrack_l4proto *l4proto;
++	const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
++	const struct nf_conntrack_l3proto *l3proto;
++	const struct nf_conntrack_l4proto *l4proto;
+ 
+-	NF_CT_ASSERT(conntrack);
++	NF_CT_ASSERT(ct);
+ 
+ 	/* we only want to print DIR_ORIGINAL */
+ 	if (NF_CT_DIRECTION(hash))
+ 		return 0;
+ 
+-	l3proto = __nf_ct_l3proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++	l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
+ 				       .tuple.src.l3num);
+ 
+ 	NF_CT_ASSERT(l3proto);
+-	l4proto = __nf_ct_l4proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++	l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
+ 				   .tuple.src.l3num,
+-				   conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++				   ct->tuplehash[IP_CT_DIR_ORIGINAL]
+ 				   .tuple.dst.protonum);
+ 	NF_CT_ASSERT(l4proto);
+ 
+ 	if (seq_printf(s, "%-8s %u %-8s %u %ld ",
+ 		       l3proto->name,
+-		       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num,
++		       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num,
+ 		       l4proto->name,
+-		       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+-		       timer_pending(&conntrack->timeout)
+-		       ? (long)(conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
++		       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
++		       timer_pending(&ct->timeout)
++		       ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
  		return -ENOSPC;
  
 -	if (l3proto->print_conntrack(s, conntrack))
++	if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
+ 		return -ENOSPC;
+ 
+-	if (l4proto->print_conntrack(s, conntrack))
 -		return -ENOSPC;
 -
--	if (l4proto->print_conntrack(s, conntrack))
-+	if (l4proto->print_conntrack && l4proto->print_conntrack(s, conntrack))
+-	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
++	if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+ 			l3proto, l4proto))
+ 		return -ENOSPC;
+ 
+-	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
++	if (seq_print_counters(s, &ct->counters[IP_CT_DIR_ORIGINAL]))
+ 		return -ENOSPC;
+ 
+-	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
++	if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
+ 		if (seq_printf(s, "[UNREPLIED] "))
+ 			return -ENOSPC;
+ 
+-	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
++	if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
+ 			l3proto, l4proto))
  		return -ENOSPC;
  
- 	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
-@@ -383,15 +380,11 @@ static ctl_table nf_ct_netfilter_table[] = {
+-	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
++	if (seq_print_counters(s, &ct->counters[IP_CT_DIR_REPLY]))
+ 		return -ENOSPC;
+ 
+-	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
++	if (test_bit(IPS_ASSURED_BIT, &ct->status))
+ 		if (seq_printf(s, "[ASSURED] "))
+ 			return -ENOSPC;
+ 
+ #if defined(CONFIG_NF_CONNTRACK_MARK)
+-	if (seq_printf(s, "mark=%u ", conntrack->mark))
++	if (seq_printf(s, "mark=%u ", ct->mark))
+ 		return -ENOSPC;
+ #endif
+ 
+ #ifdef CONFIG_NF_CONNTRACK_SECMARK
+-	if (seq_printf(s, "secmark=%u ", conntrack->secmark))
++	if (seq_printf(s, "secmark=%u ", ct->secmark))
+ 		return -ENOSPC;
+ #endif
+ 
+-	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
++	if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
+ 		return -ENOSPC;
+ 
+ 	return 0;
+@@ -245,7 +246,7 @@ static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
+ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
+ {
+ 	unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+-	struct ip_conntrack_stat *st = v;
++	const struct ip_conntrack_stat *st = v;
+ 
+ 	if (v == SEQ_START_TOKEN) {
+ 		seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
+@@ -383,15 +384,11 @@ static ctl_table nf_ct_netfilter_table[] = {
  	{ .ctl_name = 0 }
  };
  
@@ -900330,7 +966168,7 @@
 -		.child		= nf_ct_netfilter_table,
 -	},
 -	{ .ctl_name = 0 }
-+struct ctl_path nf_ct_path[] = {
++static struct ctl_path nf_ct_path[] = {
 +	{ .procname = "net", .ctl_name = CTL_NET, },
 +	{ }
  };
@@ -900338,7 +966176,7 @@
  EXPORT_SYMBOL_GPL(nf_ct_log_invalid);
  #endif /* CONFIG_SYSCTL */
  
-@@ -418,7 +411,8 @@ static int __init nf_conntrack_standalone_init(void)
+@@ -418,7 +415,8 @@ static int __init nf_conntrack_standalone_init(void)
  	proc_stat->owner = THIS_MODULE;
  #endif
  #ifdef CONFIG_SYSCTL
@@ -900348,8 +966186,31 @@
  	if (nf_ct_sysctl_header == NULL) {
  		printk("nf_conntrack: can't register to sysctl.\n");
  		ret = -ENOMEM;
+diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
+index e894aa1..bd2e800 100644
+--- a/net/netfilter/nf_conntrack_tftp.c
++++ b/net/netfilter/nf_conntrack_tftp.c
+@@ -25,7 +25,7 @@ MODULE_ALIAS("ip_conntrack_tftp");
+ 
+ #define MAX_PORTS 8
+ static unsigned short ports[MAX_PORTS];
+-static int ports_c;
++static unsigned int ports_c;
+ module_param_array(ports, ushort, &ports_c, 0400);
+ MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
+ 
+@@ -39,7 +39,8 @@ static int tftp_help(struct sk_buff *skb,
+ 		     struct nf_conn *ct,
+ 		     enum ip_conntrack_info ctinfo)
+ {
+-	struct tftphdr _tftph, *tfh;
++	const struct tftphdr *tfh;
++	struct tftphdr _tftph;
+ 	struct nf_conntrack_expect *exp;
+ 	struct nf_conntrack_tuple *tuple;
+ 	unsigned int ret = NF_ACCEPT;
 diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
-index d67c4fb..4f5f288 100644
+index d67c4fb..cec9976 100644
 --- a/net/netfilter/nf_log.c
 +++ b/net/netfilter/nf_log.c
 @@ -6,6 +6,7 @@
@@ -900407,6 +966268,22 @@
  		logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
  	} else if (net_ratelimit()) {
  		printk(KERN_WARNING "nf_log_packet: can\'t log since "
+@@ -103,6 +103,7 @@ EXPORT_SYMBOL(nf_log_packet);
+ 
+ #ifdef CONFIG_PROC_FS
+ static void *seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(RCU)
+ {
+ 	rcu_read_lock();
+ 
+@@ -123,6 +124,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
+ 
+ static void seq_stop(struct seq_file *s, void *v)
++	__releases(RCU)
+ {
+ 	rcu_read_unlock();
+ }
 diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
 index 0cef143..bfc2928 100644
 --- a/net/netfilter/nf_queue.c
@@ -900869,7 +966746,7 @@
  }
  
 diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
-index 2c7bd2e..5013cb9 100644
+index 2c7bd2e..7efa40d 100644
 --- a/net/netfilter/nfnetlink_log.c
 +++ b/net/netfilter/nfnetlink_log.c
 @@ -29,6 +29,7 @@
@@ -901108,7 +966985,7 @@
  		read_lock_bh(&skb->sk->sk_callback_lock);
  		if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
  			__be32 uid = htonl(skb->sk->sk_socket->file->f_uid);
-+			__be32 gid = htons(skb->sk->sk_socket->file->f_gid);
++			__be32 gid = htonl(skb->sk->sk_socket->file->f_gid);
  			/* need to unlock here since NLA_PUT may goto */
  			read_unlock_bh(&skb->sk->sk_callback_lock);
 -			NLA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid);
@@ -901346,8 +967223,24 @@
  		nfulnl_set_flags(inst, ntohs(flags));
  	}
  
+@@ -915,6 +866,7 @@ static struct hlist_node *get_idx(struct iter_state *st, loff_t pos)
+ }
+ 
+ static void *seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(instances_lock)
+ {
+ 	read_lock_bh(&instances_lock);
+ 	return get_idx(seq->private, *pos);
+@@ -927,6 +879,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
+ 
+ static void seq_stop(struct seq_file *s, void *v)
++	__releases(instances_lock)
+ {
+ 	read_unlock_bh(&instances_lock);
+ }
 diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
-index 3ceeffc..51476f8 100644
+index 3ceeffc..a48b20f 100644
 --- a/net/netfilter/nfnetlink_queue.c
 +++ b/net/netfilter/nfnetlink_queue.c
 @@ -3,6 +3,7 @@
@@ -901896,6 +967789,24 @@
  
  	if (indev && entskb->dev) {
  		struct nfqnl_msg_packet_hw phw;
+@@ -504,7 +360,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
+ 
+ 	if (data_len) {
+ 		struct nlattr *nla;
+-		int size = nla_attr_size(data_len);
++		int sz = nla_attr_size(data_len);
+ 
+ 		if (skb_tailroom(skb) < nla_total_size(data_len)) {
+ 			printk(KERN_WARNING "nf_queue: no tailroom!\n");
+@@ -513,7 +369,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
+ 
+ 		nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
+ 		nla->nla_type = NFQA_PAYLOAD;
+-		nla->nla_len = size;
++		nla->nla_len = sz;
+ 
+ 		if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
+ 			BUG();
 @@ -526,51 +382,29 @@ nlmsg_failure:
  nla_put_failure:
  	if (skb)
@@ -902334,25 +968245,29 @@
  	return ret;
  }
  
-@@ -1008,7 +846,7 @@ static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+@@ -1007,8 +845,9 @@ static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+ }
  
  static void *seq_start(struct seq_file *seq, loff_t *pos)
++	__acquires(instances_lock)
  {
 -	read_lock_bh(&instances_lock);
 +	spin_lock(&instances_lock);
  	return get_idx(seq, *pos);
  }
  
-@@ -1020,7 +858,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+@@ -1019,8 +858,9 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
  
  static void seq_stop(struct seq_file *s, void *v)
++	__releases(instances_lock)
  {
 -	read_unlock_bh(&instances_lock);
 +	spin_unlock(&instances_lock);
  }
  
  static int seq_show(struct seq_file *s, void *v)
-@@ -1032,8 +870,7 @@ static int seq_show(struct seq_file *s, void *v)
+@@ -1032,8 +872,7 @@ static int seq_show(struct seq_file *s, void *v)
  			  inst->peer_pid, inst->queue_total,
  			  inst->copy_mode, inst->copy_range,
  			  inst->queue_dropped, inst->queue_user_dropped,
@@ -902363,10 +968278,10 @@
  
  static const struct seq_operations nfqnl_seq_ops = {
 diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
-index b6160e4..8d4fca9 100644
+index b6160e4..a679208 100644
 --- a/net/netfilter/x_tables.c
 +++ b/net/netfilter/x_tables.c
-@@ -34,12 +34,21 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
+@@ -34,12 +34,20 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
  
  #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
  
@@ -902380,7 +968295,7 @@
  	struct mutex mutex;
  	struct list_head match;
  	struct list_head target;
- 	struct list_head tables;
+-	struct list_head tables;
 +#ifdef CONFIG_COMPAT
  	struct mutex compat_mutex;
 +	struct compat_delta *compat_offsets;
@@ -902388,7 +968303,20 @@
  };
  
  static struct xt_af *xt;
-@@ -335,6 +344,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
+@@ -50,12 +58,6 @@ static struct xt_af *xt;
+ #define duprintf(format, args...)
+ #endif
+ 
+-enum {
+-	TABLE,
+-	TARGET,
+-	MATCH,
+-};
+-
+ static const char *xt_prefix[NPROTO] = {
+ 	[AF_INET]	= "ip",
+ 	[AF_INET6]	= "ip6",
+@@ -335,6 +337,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
  EXPORT_SYMBOL_GPL(xt_check_match);
  
  #ifdef CONFIG_COMPAT
@@ -902400,78 +968328,553 @@
 +	if (!tmp)
 +		return -ENOMEM;
 +
-+	tmp->offset = offset;
-+	tmp->delta = delta;
++	tmp->offset = offset;
++	tmp->delta = delta;
++
++	if (xt[af].compat_offsets) {
++		tmp->next = xt[af].compat_offsets->next;
++		xt[af].compat_offsets->next = tmp;
++	} else {
++		xt[af].compat_offsets = tmp;
++		tmp->next = NULL;
++	}
++	return 0;
++}
++EXPORT_SYMBOL_GPL(xt_compat_add_offset);
++
++void xt_compat_flush_offsets(int af)
++{
++	struct compat_delta *tmp, *next;
++
++	if (xt[af].compat_offsets) {
++		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
++			next = tmp->next;
++			kfree(tmp);
++		}
++		xt[af].compat_offsets = NULL;
++	}
++}
++EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
++
++short xt_compat_calc_jump(int af, unsigned int offset)
++{
++	struct compat_delta *tmp;
++	short delta;
++
++	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
++		if (tmp->offset < offset)
++			delta += tmp->delta;
++	return delta;
++}
++EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
++
+ int xt_compat_match_offset(struct xt_match *match)
+ {
+ 	u_int16_t csize = match->compatsize ? : match->matchsize;
+@@ -342,8 +392,8 @@ int xt_compat_match_offset(struct xt_match *match)
+ }
+ EXPORT_SYMBOL_GPL(xt_compat_match_offset);
+ 
+-void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
+-			       int *size)
++int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
++			      unsigned int *size)
+ {
+ 	struct xt_match *match = m->u.kernel.match;
+ 	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
+@@ -365,11 +415,12 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
+ 
+ 	*size += off;
+ 	*dstptr += msize;
++	return 0;
+ }
+ EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
+ 
+ int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
+-			    int *size)
++			    unsigned int *size)
+ {
+ 	struct xt_match *match = m->u.kernel.match;
+ 	struct compat_xt_entry_match __user *cm = *dstptr;
+@@ -436,7 +487,7 @@ int xt_compat_target_offset(struct xt_target *target)
+ EXPORT_SYMBOL_GPL(xt_compat_target_offset);
+ 
+ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
+-				int *size)
++				unsigned int *size)
+ {
+ 	struct xt_target *target = t->u.kernel.target;
+ 	struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
+@@ -462,7 +513,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
+ EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
+ 
+ int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
+-			     int *size)
++			     unsigned int *size)
+ {
+ 	struct xt_target *target = t->u.kernel.target;
+ 	struct compat_xt_entry_target __user *ct = *dstptr;
+@@ -499,7 +550,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
+ 	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
+ 		return NULL;
+ 
+-	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
++	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
+ 	if (!newinfo)
+ 		return NULL;
+ 
+@@ -539,14 +590,14 @@ void xt_free_table_info(struct xt_table_info *info)
+ EXPORT_SYMBOL(xt_free_table_info);
+ 
+ /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
+-struct xt_table *xt_find_table_lock(int af, const char *name)
++struct xt_table *xt_find_table_lock(struct net *net, int af, const char *name)
+ {
+ 	struct xt_table *t;
+ 
+ 	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
+ 		return ERR_PTR(-EINTR);
+ 
+-	list_for_each_entry(t, &xt[af].tables, list)
++	list_for_each_entry(t, &net->xt.tables[af], list)
+ 		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
+ 			return t;
+ 	mutex_unlock(&xt[af].mutex);
+@@ -602,20 +653,27 @@ xt_replace_table(struct xt_table *table,
+ }
+ EXPORT_SYMBOL_GPL(xt_replace_table);
+ 
+-int xt_register_table(struct xt_table *table,
+-		      struct xt_table_info *bootstrap,
+-		      struct xt_table_info *newinfo)
++struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
++				   struct xt_table_info *bootstrap,
++				   struct xt_table_info *newinfo)
+ {
+ 	int ret;
+ 	struct xt_table_info *private;
+ 	struct xt_table *t;
+ 
++	/* Don't add one object to multiple lists. */
++	table = kmemdup(table, sizeof(struct xt_table), GFP_KERNEL);
++	if (!table) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
+ 	ret = mutex_lock_interruptible(&xt[table->af].mutex);
+ 	if (ret != 0)
+-		return ret;
++		goto out_free;
+ 
+ 	/* Don't autoload: we'd eat our tail... */
+-	list_for_each_entry(t, &xt[table->af].tables, list) {
++	list_for_each_entry(t, &net->xt.tables[table->af], list) {
+ 		if (strcmp(t->name, table->name) == 0) {
+ 			ret = -EEXIST;
+ 			goto unlock;
+@@ -634,12 +692,16 @@ int xt_register_table(struct xt_table *table,
+ 	/* save number of initial entries */
+ 	private->initial_entries = private->number;
+ 
+-	list_add(&table->list, &xt[table->af].tables);
++	list_add(&table->list, &net->xt.tables[table->af]);
++	mutex_unlock(&xt[table->af].mutex);
++	return table;
+ 
+-	ret = 0;
+  unlock:
+ 	mutex_unlock(&xt[table->af].mutex);
+-	return ret;
++out_free:
++	kfree(table);
++out:
++	return ERR_PTR(ret);
+ }
+ EXPORT_SYMBOL_GPL(xt_register_table);
+ 
+@@ -651,130 +713,204 @@ void *xt_unregister_table(struct xt_table *table)
+ 	private = table->private;
+ 	list_del(&table->list);
+ 	mutex_unlock(&xt[table->af].mutex);
++	kfree(table);
+ 
+ 	return private;
+ }
+ EXPORT_SYMBOL_GPL(xt_unregister_table);
+ 
+ #ifdef CONFIG_PROC_FS
+-static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
++struct xt_names_priv {
++	struct seq_net_private p;
++	int af;
++};
++static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+-	struct list_head *head = list->next;
++	struct xt_names_priv *priv = seq->private;
++	struct net *net = priv->p.net;
++	int af = priv->af;
+ 
+-	if (!head || list_empty(list))
+-		return NULL;
++	mutex_lock(&xt[af].mutex);
++	return seq_list_start(&net->xt.tables[af], *pos);
++}
+ 
+-	while (pos && (head = head->next)) {
+-		if (head == list)
+-			return NULL;
+-		pos--;
+-	}
+-	return pos ? NULL : head;
+-}
+-
+-static struct list_head *type2list(u_int16_t af, u_int16_t type)
+-{
+-	struct list_head *list;
+-
+-	switch (type) {
+-	case TARGET:
+-		list = &xt[af].target;
+-		break;
+-	case MATCH:
+-		list = &xt[af].match;
+-		break;
+-	case TABLE:
+-		list = &xt[af].tables;
+-		break;
+-	default:
+-		list = NULL;
+-		break;
+-	}
++static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++{
++	struct xt_names_priv *priv = seq->private;
++	struct net *net = priv->p.net;
++	int af = priv->af;
+ 
+-	return list;
++	return seq_list_next(v, &net->xt.tables[af], pos);
+ }
+ 
+-static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
++static void xt_table_seq_stop(struct seq_file *seq, void *v)
+ {
+-	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
+-	u_int16_t af = (unsigned long)pde->data & 0xffff;
+-	u_int16_t type = (unsigned long)pde->data >> 16;
+-	struct list_head *list;
++	struct xt_names_priv *priv = seq->private;
++	int af = priv->af;
+ 
+-	if (af >= NPROTO)
+-		return NULL;
++	mutex_unlock(&xt[af].mutex);
++}
+ 
+-	list = type2list(af, type);
+-	if (!list)
+-		return NULL;
++static int xt_table_seq_show(struct seq_file *seq, void *v)
++{
++	struct xt_table *table = list_entry(v, struct xt_table, list);
+ 
+-	if (mutex_lock_interruptible(&xt[af].mutex) != 0)
+-		return NULL;
++	if (strlen(table->name))
++		return seq_printf(seq, "%s\n", table->name);
++	else
++		return 0;
++}
+ 
+-	return xt_get_idx(list, seq, *pos);
++static const struct seq_operations xt_table_seq_ops = {
++	.start	= xt_table_seq_start,
++	.next	= xt_table_seq_next,
++	.stop	= xt_table_seq_stop,
++	.show	= xt_table_seq_show,
++};
++
++static int xt_table_open(struct inode *inode, struct file *file)
++{
++	int ret;
++	struct xt_names_priv *priv;
++
++	ret = seq_open_net(inode, file, &xt_table_seq_ops,
++			   sizeof(struct xt_names_priv));
++	if (!ret) {
++		priv = ((struct seq_file *)file->private_data)->private;
++		priv->af = (unsigned long)PDE(inode)->data;
++	}
++	return ret;
+ }
+ 
+-static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++static const struct file_operations xt_table_ops = {
++	.owner	 = THIS_MODULE,
++	.open	 = xt_table_open,
++	.read	 = seq_read,
++	.llseek	 = seq_lseek,
++	.release = seq_release,
++};
++
++static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+-	struct proc_dir_entry *pde = seq->private;
+-	u_int16_t af = (unsigned long)pde->data & 0xffff;
+-	u_int16_t type = (unsigned long)pde->data >> 16;
+-	struct list_head *list;
++	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
++	u_int16_t af = (unsigned long)pde->data;
+ 
+-	if (af >= NPROTO)
+-		return NULL;
++	mutex_lock(&xt[af].mutex);
++	return seq_list_start(&xt[af].match, *pos);
++}
+ 
+-	list = type2list(af, type);
+-	if (!list)
+-		return NULL;
++static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++{
++	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
++	u_int16_t af = (unsigned long)pde->data;
+ 
+-	(*pos)++;
+-	return xt_get_idx(list, seq, *pos);
++	return seq_list_next(v, &xt[af].match, pos);
+ }
+ 
+-static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
++static void xt_match_seq_stop(struct seq_file *seq, void *v)
+ {
+ 	struct proc_dir_entry *pde = seq->private;
+-	u_int16_t af = (unsigned long)pde->data & 0xffff;
++	u_int16_t af = (unsigned long)pde->data;
+ 
+ 	mutex_unlock(&xt[af].mutex);
+ }
+ 
+-static int xt_name_seq_show(struct seq_file *seq, void *v)
++static int xt_match_seq_show(struct seq_file *seq, void *v)
+ {
+-	char *name = (char *)v + sizeof(struct list_head);
++	struct xt_match *match = list_entry(v, struct xt_match, list);
+ 
+-	if (strlen(name))
+-		return seq_printf(seq, "%s\n", name);
++	if (strlen(match->name))
++		return seq_printf(seq, "%s\n", match->name);
+ 	else
+ 		return 0;
+ }
+ 
+-static const struct seq_operations xt_tgt_seq_ops = {
+-	.start	= xt_tgt_seq_start,
+-	.next	= xt_tgt_seq_next,
+-	.stop	= xt_tgt_seq_stop,
+-	.show	= xt_name_seq_show,
++static const struct seq_operations xt_match_seq_ops = {
++	.start	= xt_match_seq_start,
++	.next	= xt_match_seq_next,
++	.stop	= xt_match_seq_stop,
++	.show	= xt_match_seq_show,
+ };
+ 
+-static int xt_tgt_open(struct inode *inode, struct file *file)
++static int xt_match_open(struct inode *inode, struct file *file)
+ {
+ 	int ret;
+ 
+-	ret = seq_open(file, &xt_tgt_seq_ops);
++	ret = seq_open(file, &xt_match_seq_ops);
+ 	if (!ret) {
+ 		struct seq_file *seq = file->private_data;
+-		struct proc_dir_entry *pde = PDE(inode);
+ 
+-		seq->private = pde;
++		seq->private = PDE(inode);
+ 	}
++	return ret;
++}
++
++static const struct file_operations xt_match_ops = {
++	.owner	 = THIS_MODULE,
++	.open	 = xt_match_open,
++	.read	 = seq_read,
++	.llseek	 = seq_lseek,
++	.release = seq_release,
++};
++
++static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
++{
++	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
++	u_int16_t af = (unsigned long)pde->data;
++
++	mutex_lock(&xt[af].mutex);
++	return seq_list_start(&xt[af].target, *pos);
++}
++
++static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++{
++	struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
++	u_int16_t af = (unsigned long)pde->data;
++
++	return seq_list_next(v, &xt[af].target, pos);
++}
+ 
++static void xt_target_seq_stop(struct seq_file *seq, void *v)
++{
++	struct proc_dir_entry *pde = seq->private;
++	u_int16_t af = (unsigned long)pde->data;
 +
-+	if (xt[af].compat_offsets) {
-+		tmp->next = xt[af].compat_offsets->next;
-+		xt[af].compat_offsets->next = tmp;
-+	} else {
-+		xt[af].compat_offsets = tmp;
-+		tmp->next = NULL;
-+	}
-+	return 0;
++	mutex_unlock(&xt[af].mutex);
 +}
-+EXPORT_SYMBOL_GPL(xt_compat_add_offset);
 +
-+void xt_compat_flush_offsets(int af)
++static int xt_target_seq_show(struct seq_file *seq, void *v)
 +{
-+	struct compat_delta *tmp, *next;
++	struct xt_target *target = list_entry(v, struct xt_target, list);
 +
-+	if (xt[af].compat_offsets) {
-+		for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
-+			next = tmp->next;
-+			kfree(tmp);
-+		}
-+		xt[af].compat_offsets = NULL;
-+	}
++	if (strlen(target->name))
++		return seq_printf(seq, "%s\n", target->name);
++	else
++		return 0;
 +}
-+EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
 +
-+short xt_compat_calc_jump(int af, unsigned int offset)
++static const struct seq_operations xt_target_seq_ops = {
++	.start	= xt_target_seq_start,
++	.next	= xt_target_seq_next,
++	.stop	= xt_target_seq_stop,
++	.show	= xt_target_seq_show,
++};
++
++static int xt_target_open(struct inode *inode, struct file *file)
 +{
-+	struct compat_delta *tmp;
-+	short delta;
++	int ret;
 +
-+	for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
-+		if (tmp->offset < offset)
-+			delta += tmp->delta;
-+	return delta;
-+}
-+EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
++	ret = seq_open(file, &xt_target_seq_ops);
++	if (!ret) {
++		struct seq_file *seq = file->private_data;
 +
- int xt_compat_match_offset(struct xt_match *match)
++		seq->private = PDE(inode);
++	}
+ 	return ret;
+ }
+ 
+-static const struct file_operations xt_file_ops = {
++static const struct file_operations xt_target_ops = {
+ 	.owner	 = THIS_MODULE,
+-	.open	 = xt_tgt_open,
++	.open	 = xt_target_open,
+ 	.read	 = seq_read,
+ 	.llseek	 = seq_lseek,
+ 	.release = seq_release,
+@@ -786,7 +922,7 @@ static const struct file_operations xt_file_ops = {
+ 
+ #endif /* CONFIG_PROC_FS */
+ 
+-int xt_proto_init(int af)
++int xt_proto_init(struct net *net, int af)
  {
- 	u_int16_t csize = match->compatsize ? : match->matchsize;
-@@ -342,8 +399,8 @@ int xt_compat_match_offset(struct xt_match *match)
+ #ifdef CONFIG_PROC_FS
+ 	char buf[XT_FUNCTION_MAXNAMELEN];
+@@ -800,25 +936,25 @@ int xt_proto_init(int af)
+ #ifdef CONFIG_PROC_FS
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+-	proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
++	proc = proc_net_fops_create(net, buf, 0440, &xt_table_ops);
+ 	if (!proc)
+ 		goto out;
+-	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
++	proc->data = (void *)(unsigned long)af;
+ 
+ 
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+-	proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
++	proc = proc_net_fops_create(net, buf, 0440, &xt_match_ops);
+ 	if (!proc)
+ 		goto out_remove_tables;
+-	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
++	proc->data = (void *)(unsigned long)af;
+ 
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+-	proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
++	proc = proc_net_fops_create(net, buf, 0440, &xt_target_ops);
+ 	if (!proc)
+ 		goto out_remove_matches;
+-	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
++	proc->data = (void *)(unsigned long)af;
+ #endif
+ 
+ 	return 0;
+@@ -827,42 +963,54 @@ int xt_proto_init(int af)
+ out_remove_matches:
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+-	proc_net_remove(&init_net, buf);
++	proc_net_remove(net, buf);
+ 
+ out_remove_tables:
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+-	proc_net_remove(&init_net, buf);
++	proc_net_remove(net, buf);
+ out:
+ 	return -1;
+ #endif
  }
- EXPORT_SYMBOL_GPL(xt_compat_match_offset);
+ EXPORT_SYMBOL_GPL(xt_proto_init);
  
--void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
--			       int *size)
-+int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
-+			      int *size)
+-void xt_proto_fini(int af)
++void xt_proto_fini(struct net *net, int af)
  {
- 	struct xt_match *match = m->u.kernel.match;
- 	struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
-@@ -365,6 +422,7 @@ void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
+ #ifdef CONFIG_PROC_FS
+ 	char buf[XT_FUNCTION_MAXNAMELEN];
  
- 	*size += off;
- 	*dstptr += msize;
-+	return 0;
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+-	proc_net_remove(&init_net, buf);
++	proc_net_remove(net, buf);
+ 
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+-	proc_net_remove(&init_net, buf);
++	proc_net_remove(net, buf);
+ 
+ 	strlcpy(buf, xt_prefix[af], sizeof(buf));
+ 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+-	proc_net_remove(&init_net, buf);
++	proc_net_remove(net, buf);
+ #endif /*CONFIG_PROC_FS*/
  }
- EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
+ EXPORT_SYMBOL_GPL(xt_proto_fini);
  
-@@ -499,7 +557,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
- 	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
- 		return NULL;
++static int __net_init xt_net_init(struct net *net)
++{
++	int i;
++
++	for (i = 0; i < NPROTO; i++)
++		INIT_LIST_HEAD(&net->xt.tables[i]);
++	return 0;
++}
++
++static struct pernet_operations xt_net_ops = {
++	.init = xt_net_init,
++};
  
--	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
-+	newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL);
- 	if (!newinfo)
- 		return NULL;
+ static int __init xt_init(void)
+ {
+-	int i;
++	int i, rv;
  
-@@ -872,6 +930,7 @@ static int __init xt_init(void)
+ 	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
+ 	if (!xt)
+@@ -872,16 +1020,20 @@ static int __init xt_init(void)
  		mutex_init(&xt[i].mutex);
  #ifdef CONFIG_COMPAT
  		mutex_init(&xt[i].compat_mutex);
@@ -902479,6 +968882,21 @@
  #endif
  		INIT_LIST_HEAD(&xt[i].target);
  		INIT_LIST_HEAD(&xt[i].match);
+-		INIT_LIST_HEAD(&xt[i].tables);
+ 	}
+-	return 0;
++	rv = register_pernet_subsys(&xt_net_ops);
++	if (rv < 0)
++		kfree(xt);
++	return rv;
+ }
+ 
+ static void __exit xt_fini(void)
+ {
++	unregister_pernet_subsys(&xt_net_ops);
+ 	kfree(xt);
+ }
+ 
 diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
 index 77eeae6..77a52bf 100644
 --- a/net/netfilter/xt_CLASSIFY.c
@@ -903972,10 +970390,21 @@
 +module_init(secmark_tg_init);
 +module_exit(secmark_tg_exit);
 diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
-index 8e76d1f..60e3767 100644
+index 8e76d1f..217e2b6 100644
 --- a/net/netfilter/xt_TCPMSS.c
 +++ b/net/netfilter/xt_TCPMSS.c
-@@ -24,7 +24,7 @@
+@@ -13,7 +13,10 @@
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
+ #include <linux/tcp.h>
++#include <net/dst.h>
++#include <net/flow.h>
+ #include <net/ipv6.h>
++#include <net/route.h>
+ #include <net/tcp.h>
+ 
+ #include <linux/netfilter_ipv4/ip_tables.h>
+@@ -24,7 +27,7 @@
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Marc Boucher <marc at mbsi.ca>");
@@ -903984,7 +970413,30 @@
  MODULE_ALIAS("ipt_TCPMSS");
  MODULE_ALIAS("ip6t_TCPMSS");
  
-@@ -88,15 +88,19 @@ tcpmss_mangle_packet(struct sk_buff *skb,
+@@ -41,6 +44,7 @@ optlen(const u_int8_t *opt, unsigned int offset)
+ static int
+ tcpmss_mangle_packet(struct sk_buff *skb,
+ 		     const struct xt_tcpmss_info *info,
++		     unsigned int in_mtu,
+ 		     unsigned int tcphoff,
+ 		     unsigned int minlen)
+ {
+@@ -76,7 +80,13 @@ tcpmss_mangle_packet(struct sk_buff *skb,
+ 				       dst_mtu(skb->dst));
+ 			return -1;
+ 		}
+-		newmss = dst_mtu(skb->dst) - minlen;
++		if (in_mtu <= minlen) {
++			if (net_ratelimit())
++				printk(KERN_ERR "xt_TCPMSS: unknown or "
++				       "invalid path-MTU (%u)\n", in_mtu);
++			return -1;
++		}
++		newmss = min(dst_mtu(skb->dst), in_mtu) - minlen;
+ 	} else
+ 		newmss = info->mss;
+ 
+@@ -88,15 +98,19 @@ tcpmss_mangle_packet(struct sk_buff *skb,
  
  			oldmss = (opt[i+2] << 8) | opt[i+3];
  
@@ -904008,7 +970460,7 @@
  			return 0;
  		}
  	}
-@@ -117,29 +121,26 @@ tcpmss_mangle_packet(struct sk_buff *skb,
+@@ -117,55 +131,94 @@ tcpmss_mangle_packet(struct sk_buff *skb,
  	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
  	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
  
@@ -904033,6 +970485,28 @@
  	return TCPOLEN_MSS;
  }
  
++static u_int32_t tcpmss_reverse_mtu4(const struct iphdr *iph)
++{
++	struct flowi fl = {
++		.fl4_dst = iph->saddr,
++	};
++	const struct nf_afinfo *ai;
++	struct rtable *rt = NULL;
++	u_int32_t mtu     = ~0U;
++
++	rcu_read_lock();
++	ai = nf_get_afinfo(AF_INET);
++	if (ai != NULL)
++		ai->route((struct dst_entry **)&rt, &fl);
++	rcu_read_unlock();
++
++	if (rt != NULL) {
++		mtu = dst_mtu(&rt->u.dst);
++		dst_release(&rt->u.dst);
++	}
++	return mtu;
++}
++
  static unsigned int
 -xt_tcpmss_target4(struct sk_buff *skb,
 -		  const struct net_device *in,
@@ -904046,7 +970520,14 @@
  {
  	struct iphdr *iph = ip_hdr(skb);
  	__be16 newlen;
-@@ -152,7 +153,7 @@ xt_tcpmss_target4(struct sk_buff *skb,
+ 	int ret;
+ 
+-	ret = tcpmss_mangle_packet(skb, targinfo, iph->ihl * 4,
++	ret = tcpmss_mangle_packet(skb, targinfo, tcpmss_reverse_mtu4(iph),
++				   iph->ihl * 4,
+ 				   sizeof(*iph) + sizeof(struct tcphdr));
+ 	if (ret < 0)
+ 		return NF_DROP;
  	if (ret > 0) {
  		iph = ip_hdr(skb);
  		newlen = htons(ntohs(iph->tot_len) + ret);
@@ -904055,9 +970536,31 @@
  		iph->tot_len = newlen;
  	}
  	return XT_CONTINUE;
-@@ -160,12 +161,9 @@ xt_tcpmss_target4(struct sk_buff *skb,
+ }
  
  #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
++static u_int32_t tcpmss_reverse_mtu6(const struct ipv6hdr *iph)
++{
++	struct flowi fl = {
++		.fl6_dst = iph->saddr,
++	};
++	const struct nf_afinfo *ai;
++	struct rtable *rt = NULL;
++	u_int32_t mtu     = ~0U;
++
++	rcu_read_lock();
++	ai = nf_get_afinfo(AF_INET6);
++	if (ai != NULL)
++		ai->route((struct dst_entry **)&rt, &fl);
++	rcu_read_unlock();
++
++	if (rt != NULL) {
++		mtu = dst_mtu(&rt->u.dst);
++		dst_release(&rt->u.dst);
++	}
++	return mtu;
++}
++
  static unsigned int
 -xt_tcpmss_target6(struct sk_buff *skb,
 -		  const struct net_device *in,
@@ -904071,7 +970574,17 @@
  {
  	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
  	u8 nexthdr;
-@@ -204,19 +202,17 @@ static inline bool find_syn_match(const struct xt_entry_match *m)
+@@ -176,7 +229,8 @@ xt_tcpmss_target6(struct sk_buff *skb,
+ 	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
+ 	if (tcphoff < 0)
+ 		return NF_DROP;
+-	ret = tcpmss_mangle_packet(skb, targinfo, tcphoff,
++	ret = tcpmss_mangle_packet(skb, targinfo, tcpmss_reverse_mtu6(ipv6h),
++				   tcphoff,
+ 				   sizeof(*ipv6h) + sizeof(struct tcphdr));
+ 	if (ret < 0)
+ 		return NF_DROP;
+@@ -204,19 +258,17 @@ static inline bool find_syn_match(const struct xt_entry_match *m)
  }
  
  static bool
@@ -904097,7 +970610,7 @@
  		printk("xt_TCPMSS: path-MTU clamping only supported in "
  		       "FORWARD, OUTPUT and POSTROUTING hooks\n");
  		return false;
-@@ -229,19 +225,17 @@ xt_tcpmss_checkentry4(const char *tablename,
+@@ -229,19 +281,17 @@ xt_tcpmss_checkentry4(const char *tablename,
  
  #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
  static bool
@@ -904123,7 +970636,7 @@
  		printk("xt_TCPMSS: path-MTU clamping only supported in "
  		       "FORWARD, OUTPUT and POSTROUTING hooks\n");
  		return false;
-@@ -253,12 +247,12 @@ xt_tcpmss_checkentry6(const char *tablename,
+@@ -253,12 +303,12 @@ xt_tcpmss_checkentry6(const char *tablename,
  }
  #endif
  
@@ -904139,7 +970652,7 @@
  		.targetsize	= sizeof(struct xt_tcpmss_info),
  		.proto		= IPPROTO_TCP,
  		.me		= THIS_MODULE,
-@@ -267,8 +261,8 @@ static struct xt_target xt_tcpmss_reg[] __read_mostly = {
+@@ -267,8 +317,8 @@ static struct xt_target xt_tcpmss_reg[] __read_mostly = {
  	{
  		.family		= AF_INET6,
  		.name		= "TCPMSS",
@@ -904150,7 +970663,7 @@
  		.targetsize	= sizeof(struct xt_tcpmss_info),
  		.proto		= IPPROTO_TCP,
  		.me		= THIS_MODULE,
-@@ -276,15 +270,15 @@ static struct xt_target xt_tcpmss_reg[] __read_mostly = {
+@@ -276,15 +326,15 @@ static struct xt_target xt_tcpmss_reg[] __read_mostly = {
  #endif
  };
  
@@ -904577,7 +971090,7 @@
 +module_init(connbytes_mt_init);
 +module_exit(connbytes_mt_exit);
 diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
-index d7becf0..e00ecd9 100644
+index d7becf0..3b01119 100644
 --- a/net/netfilter/xt_connlimit.c
 +++ b/net/netfilter/xt_connlimit.c
 @@ -53,10 +53,10 @@ static inline unsigned int connlimit_iphash(__be32 addr)
@@ -904624,6 +971137,29 @@
  		      const struct xt_match *match)
  {
  	struct nf_conntrack_tuple_hash *found;
+@@ -120,11 +120,11 @@ static int count_them(struct xt_connlimit_data *data,
+ 	else
+ 		hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
+ 
+-	read_lock_bh(&nf_conntrack_lock);
++	rcu_read_lock();
+ 
+ 	/* check the saved connections */
+ 	list_for_each_entry_safe(conn, tmp, hash, list) {
+-		found    = __nf_conntrack_find(&conn->tuple, NULL);
++		found    = __nf_conntrack_find(&conn->tuple);
+ 		found_ct = NULL;
+ 
+ 		if (found != NULL)
+@@ -163,7 +163,7 @@ static int count_them(struct xt_connlimit_data *data,
+ 			++matches;
+ 	}
+ 
+-	read_unlock_bh(&nf_conntrack_lock);
++	rcu_read_unlock();
+ 
+ 	if (addit) {
+ 		/* save the new connection in our list */
 @@ -178,15 +178,14 @@ static int count_them(struct xt_connlimit_data *data,
  	return matches;
  }
@@ -904957,7 +971493,7 @@
 +module_init(connmark_mt_init);
 +module_exit(connmark_mt_exit);
 diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
-index ca4b69f..e92190e 100644
+index ca4b69f..8533085 100644
 --- a/net/netfilter/xt_conntrack.c
 +++ b/net/netfilter/xt_conntrack.c
 @@ -1,33 +1,34 @@
@@ -904970,7 +971506,6 @@
 - * (C) 2001  Marc Boucher (marc at mbsi.ca).
 + *	(C) 2001  Marc Boucher (marc at mbsi.ca).
 + *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
-+ *	Jan Engelhardt <jengelh at computergmbh.de>
   *
 - * This program is free software; you can redistribute it and/or modify
 - * it under the terms of the GNU General Public License version 2 as
@@ -904990,6 +971525,7 @@
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Marc Boucher <marc at mbsi.ca>");
 -MODULE_DESCRIPTION("iptables connection tracking match module");
++MODULE_AUTHOR("Jan Engelhardt <jengelh at computergmbh.de>");
 +MODULE_DESCRIPTION("Xtables: connection tracking state match");
  MODULE_ALIAS("ipt_conntrack");
 +MODULE_ALIAS("ip6t_conntrack");
@@ -905019,7 +971555,7 @@
  
  	if (ct == &nf_conntrack_untracked)
  		statebit = XT_CONNTRACK_STATE_UNTRACKED;
-@@ -112,24 +113,152 @@ match(const struct sk_buff *skb,
+@@ -112,24 +113,192 @@ match(const struct sk_buff *skb,
  			return false;
  	}
  	return true;
@@ -905081,6 +971617,44 @@
 +	       &info->repldst_addr, &info->repldst_mask, family);
 +}
 +
++static inline bool
++ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
++                    const struct nf_conn *ct)
++{
++	const struct nf_conntrack_tuple *tuple;
++
++	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++	if ((info->match_flags & XT_CONNTRACK_PROTO) &&
++	    (tuple->dst.protonum == info->l4proto) ^
++	    !(info->invert_flags & XT_CONNTRACK_PROTO))
++		return false;
++
++	/* Shortcut to match all recognized protocols by using ->src.all. */
++	if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
++	    (tuple->src.u.all == info->origsrc_port) ^
++	    !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
++		return false;
++
++	if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
++	    (tuple->dst.u.all == info->origdst_port) ^
++	    !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
++		return false;
++
++	tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
++
++	if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
++	    (tuple->src.u.all == info->replsrc_port) ^
++	    !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
++		return false;
++
++	if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
++	    (tuple->dst.u.all == info->repldst_port) ^
++	    !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
++		return false;
++
++	return true;
++}
++
 +static bool
 +conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
 +             const struct net_device *out, const struct xt_match *match,
@@ -905115,10 +971689,9 @@
 +
 +	if (ct == NULL)
 +		return info->match_flags & XT_CONNTRACK_STATE;
-+
-+	if ((info->match_flags & XT_CONNTRACK_PROTO) &&
-+	    ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
-+	    info->l4proto) ^ !(info->invert_flags & XT_CONNTRACK_PROTO)))
++	if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
++	    (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
++	    !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
 +		return false;
 +
 +	if (info->match_flags & XT_CONNTRACK_ORIGSRC)
@@ -905141,6 +971714,9 @@
 +		    !(info->invert_flags & XT_CONNTRACK_REPLDST))
 +			return false;
 +
++	if (!ct_proto_port_check(info, ct))
++		return false;
++
 +	if ((info->match_flags & XT_CONNTRACK_STATUS) &&
 +	    (!!(info->status_mask & ct->status) ^
 +	    !(info->invert_flags & XT_CONNTRACK_STATUS)))
@@ -905179,7 +971755,7 @@
  {
  	nf_ct_l3proto_module_put(match->family);
  }
-@@ -148,7 +277,7 @@ struct compat_xt_conntrack_info
+@@ -148,7 +317,7 @@ struct compat_xt_conntrack_info
  	u_int8_t			invflags;
  };
  
@@ -905188,7 +971764,7 @@
  {
  	const struct compat_xt_conntrack_info *cm = src;
  	struct xt_conntrack_info m = {
-@@ -165,7 +294,7 @@ static void compat_from_user(void *dst, void *src)
+@@ -165,7 +334,7 @@ static void compat_from_user(void *dst, void *src)
  	memcpy(dst, &m, sizeof(m));
  }
  
@@ -905197,7 +971773,7 @@
  {
  	const struct xt_conntrack_info *m = src;
  	struct compat_xt_conntrack_info cm = {
-@@ -183,30 +312,54 @@ static int compat_to_user(void __user *dst, void *src)
+@@ -183,30 +352,54 @@ static int compat_to_user(void __user *dst, void *src)
  }
  #endif
  
@@ -905638,9 +972214,24 @@
 +module_init(esp_mt_init);
 +module_exit(esp_mt_exit);
 diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
-index 2ef44d8..d479ca9 100644
+index 2ef44d8..744c7f2 100644
 --- a/net/netfilter/xt_hashlimit.c
 +++ b/net/netfilter/xt_hashlimit.c
+@@ -1,9 +1,9 @@
+-/* iptables match extension to limit the number of packets per second
+- * seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
++/*
++ *	xt_hashlimit - Netfilter module to limit the number of packets per time
++ *	seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
+  *
+- * (C) 2003-2004 by Harald Welte <laforge at netfilter.org>
+- *
+- * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge at netfilter.org $
++ *	(C) 2003-2004 by Harald Welte <laforge at netfilter.org>
++ *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
+  *
+  * Development of this code was funded by Astaro AG, http://www.astaro.com/
+  */
 @@ -20,7 +20,11 @@
  #include <linux/mm.h>
  #include <linux/in.h>
@@ -905653,16 +972244,17 @@
  #include <net/net_namespace.h>
  
  #include <linux/netfilter/x_tables.h>
-@@ -31,7 +35,7 @@
+@@ -31,7 +35,8 @@
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
 -MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
++MODULE_AUTHOR("Jan Engelhardt <jengelh at computergmbh.de>");
 +MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match");
  MODULE_ALIAS("ipt_hashlimit");
  MODULE_ALIAS("ip6t_hashlimit");
  
-@@ -47,10 +51,12 @@ struct dsthash_dst {
+@@ -47,11 +52,13 @@ struct dsthash_dst {
  			__be32 src;
  			__be32 dst;
  		} ip;
@@ -905671,11 +972263,22 @@
  			__be32 src[4];
  			__be32 dst[4];
  		} ip6;
+-	} addr;
 +#endif
- 	} addr;
++	};
  	__be16 src_port;
  	__be16 dst_port;
-@@ -104,7 +110,16 @@ static inline bool dst_cmp(const struct dsthash_ent *ent,
+ };
+@@ -75,7 +82,7 @@ struct xt_hashlimit_htable {
+ 	atomic_t use;
+ 	int family;
+ 
+-	struct hashlimit_cfg cfg;	/* config */
++	struct hashlimit_cfg1 cfg;	/* config */
+ 
+ 	/* used internally */
+ 	spinlock_t lock;		/* lock for list_head */
+@@ -104,7 +111,16 @@ static inline bool dst_cmp(const struct dsthash_ent *ent,
  static u_int32_t
  hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst)
  {
@@ -905693,7 +972296,155 @@
  }
  
  static struct dsthash_ent *
-@@ -379,7 +394,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+@@ -169,7 +185,7 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
+ }
+ static void htable_gc(unsigned long htlong);
+ 
+-static int htable_create(struct xt_hashlimit_info *minfo, int family)
++static int htable_create_v0(struct xt_hashlimit_info *minfo, int family)
+ {
+ 	struct xt_hashlimit_htable *hinfo;
+ 	unsigned int size;
+@@ -195,7 +211,18 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family)
+ 	minfo->hinfo = hinfo;
+ 
+ 	/* copy match config into hashtable config */
+-	memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
++	hinfo->cfg.mode        = minfo->cfg.mode;
++	hinfo->cfg.avg         = minfo->cfg.avg;
++	hinfo->cfg.burst       = minfo->cfg.burst;
++	hinfo->cfg.max         = minfo->cfg.max;
++	hinfo->cfg.gc_interval = minfo->cfg.gc_interval;
++	hinfo->cfg.expire      = minfo->cfg.expire;
++
++	if (family == AF_INET)
++		hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32;
++	else
++		hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128;
++
+ 	hinfo->cfg.size = size;
+ 	if (!hinfo->cfg.max)
+ 		hinfo->cfg.max = 8 * hinfo->cfg.size;
+@@ -231,6 +258,70 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family)
+ 	return 0;
+ }
+ 
++static int htable_create(struct xt_hashlimit_mtinfo1 *minfo,
++                         unsigned int family)
++{
++	struct xt_hashlimit_htable *hinfo;
++	unsigned int size;
++	unsigned int i;
++
++	if (minfo->cfg.size) {
++		size = minfo->cfg.size;
++	} else {
++		size = (num_physpages << PAGE_SHIFT) / 16384 /
++		       sizeof(struct list_head);
++		if (num_physpages > 1024 * 1024 * 1024 / PAGE_SIZE)
++			size = 8192;
++		if (size < 16)
++			size = 16;
++	}
++	/* FIXME: don't use vmalloc() here or anywhere else -HW */
++	hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
++	                sizeof(struct list_head) * size);
++	if (hinfo == NULL) {
++		printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n");
++		return -1;
++	}
++	minfo->hinfo = hinfo;
++
++	/* copy match config into hashtable config */
++	memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
++	hinfo->cfg.size = size;
++	if (hinfo->cfg.max == 0)
++		hinfo->cfg.max = 8 * hinfo->cfg.size;
++	else if (hinfo->cfg.max < hinfo->cfg.size)
++		hinfo->cfg.max = hinfo->cfg.size;
++
++	for (i = 0; i < hinfo->cfg.size; i++)
++		INIT_HLIST_HEAD(&hinfo->hash[i]);
++
++	atomic_set(&hinfo->use, 1);
++	hinfo->count = 0;
++	hinfo->family = family;
++	hinfo->rnd_initialized = 0;
++	spin_lock_init(&hinfo->lock);
++
++	hinfo->pde = create_proc_entry(minfo->name, 0,
++				       family == AF_INET ? hashlimit_procdir4 :
++							   hashlimit_procdir6);
++	if (hinfo->pde == NULL) {
++		vfree(hinfo);
++		return -1;
++	}
++	hinfo->pde->proc_fops = &dl_file_ops;
++	hinfo->pde->data = hinfo;
++
++	setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo);
++	hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
++	add_timer(&hinfo->timer);
++
++	spin_lock_bh(&hashlimit_lock);
++	hlist_add_head(&hinfo->node, &hashlimit_htables);
++	spin_unlock_bh(&hashlimit_lock);
++
++	return 0;
++}
++
+ static bool select_all(const struct xt_hashlimit_htable *ht,
+ 		       const struct dsthash_ent *he)
+ {
+@@ -373,22 +464,66 @@ static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
+ 	dh->rateinfo.prev = now;
+ }
+ 
++static inline __be32 maskl(__be32 a, unsigned int l)
++{
++	return htonl(ntohl(a) & ~(~(u_int32_t)0 >> l));
++}
++
++#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
++static void hashlimit_ipv6_mask(__be32 *i, unsigned int p)
++{
++	switch (p) {
++	case 0:
++		i[0] = i[1] = 0;
++		i[2] = i[3] = 0;
++		break;
++	case 1 ... 31:
++		i[0] = maskl(i[0], p);
++		i[1] = i[2] = i[3] = 0;
++		break;
++	case 32:
++		i[1] = i[2] = i[3] = 0;
++		break;
++	case 33 ... 63:
++		i[1] = maskl(i[1], p - 32);
++		i[2] = i[3] = 0;
++		break;
++	case 64:
++		i[2] = i[3] = 0;
++		break;
++	case 65 ... 95:
++		i[2] = maskl(i[2], p - 64);
++		i[3] = 0;
++	case 96:
++		i[3] = 0;
++		break;
++	case 97 ... 127:
++		i[3] = maskl(i[3], p - 96);
++		break;
++	case 128:
++		break;
++	}
++}
++#endif
++
+ static int
+ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+ 		   struct dsthash_dst *dst,
  		   const struct sk_buff *skb, unsigned int protoff)
  {
  	__be16 _ports[2], *ports;
@@ -905702,7 +972453,40 @@
  
  	memset(dst, 0, sizeof(*dst));
  
-@@ -407,8 +422,9 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+ 	switch (hinfo->family) {
+ 	case AF_INET:
+ 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
+-			dst->addr.ip.dst = ip_hdr(skb)->daddr;
++			dst->ip.dst = maskl(ip_hdr(skb)->daddr,
++			              hinfo->cfg.dstmask);
+ 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
+-			dst->addr.ip.src = ip_hdr(skb)->saddr;
++			dst->ip.src = maskl(ip_hdr(skb)->saddr,
++			              hinfo->cfg.srcmask);
+ 
+ 		if (!(hinfo->cfg.mode &
+ 		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
+@@ -397,18 +532,23 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+ 		break;
+ #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+ 	case AF_INET6:
+-		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
+-			memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr,
+-			       sizeof(dst->addr.ip6.dst));
+-		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
+-			memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr,
+-			       sizeof(dst->addr.ip6.src));
++		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) {
++			memcpy(&dst->ip6.dst, &ipv6_hdr(skb)->daddr,
++			       sizeof(dst->ip6.dst));
++			hashlimit_ipv6_mask(dst->ip6.dst, hinfo->cfg.dstmask);
++		}
++		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) {
++			memcpy(&dst->ip6.src, &ipv6_hdr(skb)->saddr,
++			       sizeof(dst->ip6.src));
++			hashlimit_ipv6_mask(dst->ip6.src, hinfo->cfg.srcmask);
++		}
+ 
  		if (!(hinfo->cfg.mode &
  		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
  			return 0;
@@ -905714,7 +972498,7 @@
  			return -1;
  		break;
  #endif
-@@ -441,14 +457,10 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+@@ -441,14 +581,10 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
  }
  
  static bool
@@ -905726,14 +972510,14 @@
 -		int offset,
 -		unsigned int protoff,
 -		bool *hotdrop)
-+hashlimit_mt(const struct sk_buff *skb, const struct net_device *in,
-+             const struct net_device *out, const struct xt_match *match,
-+             const void *matchinfo, int offset, unsigned int protoff,
-+             bool *hotdrop)
++hashlimit_mt_v0(const struct sk_buff *skb, const struct net_device *in,
++                const struct net_device *out, const struct xt_match *match,
++                const void *matchinfo, int offset, unsigned int protoff,
++                bool *hotdrop)
  {
  	const struct xt_hashlimit_info *r =
  		((const struct xt_hashlimit_info *)matchinfo)->u.master;
-@@ -500,11 +512,9 @@ hotdrop:
+@@ -500,11 +636,62 @@ hotdrop:
  }
  
  static bool
@@ -905742,22 +972526,145 @@
 -		     const struct xt_match *match,
 -		     void *matchinfo,
 -		     unsigned int hook_mask)
-+hashlimit_mt_check(const char *tablename, const void *inf,
-+                   const struct xt_match *match, void *matchinfo,
-+                   unsigned int hook_mask)
++hashlimit_mt(const struct sk_buff *skb, const struct net_device *in,
++             const struct net_device *out, const struct xt_match *match,
++             const void *matchinfo, int offset, unsigned int protoff,
++             bool *hotdrop)
++{
++	const struct xt_hashlimit_mtinfo1 *info = matchinfo;
++	struct xt_hashlimit_htable *hinfo = info->hinfo;
++	unsigned long now = jiffies;
++	struct dsthash_ent *dh;
++	struct dsthash_dst dst;
++
++	if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)
++		goto hotdrop;
++
++	spin_lock_bh(&hinfo->lock);
++	dh = dsthash_find(hinfo, &dst);
++	if (dh == NULL) {
++		dh = dsthash_alloc_init(hinfo, &dst);
++		if (dh == NULL) {
++			spin_unlock_bh(&hinfo->lock);
++			goto hotdrop;
++		}
++
++		dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
++		dh->rateinfo.prev = jiffies;
++		dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
++		                      hinfo->cfg.burst);
++		dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
++		                          hinfo->cfg.burst);
++		dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
++	} else {
++		/* update expiration timeout */
++		dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
++		rateinfo_recalc(dh, now);
++	}
++
++	if (dh->rateinfo.credit >= dh->rateinfo.cost) {
++		/* below the limit */
++		dh->rateinfo.credit -= dh->rateinfo.cost;
++		spin_unlock_bh(&hinfo->lock);
++		return !(info->cfg.mode & XT_HASHLIMIT_INVERT);
++	}
++
++	spin_unlock_bh(&hinfo->lock);
++	/* default match is underlimit - so over the limit, we need to invert */
++	return info->cfg.mode & XT_HASHLIMIT_INVERT;
++
++ hotdrop:
++	*hotdrop = true;
++	return false;
++}
++
++static bool
++hashlimit_mt_check_v0(const char *tablename, const void *inf,
++                      const struct xt_match *match, void *matchinfo,
++                      unsigned int hook_mask)
  {
  	struct xt_hashlimit_info *r = matchinfo;
  
-@@ -548,7 +558,7 @@ hashlimit_checkentry(const char *tablename,
+@@ -536,7 +723,7 @@ hashlimit_checkentry(const char *tablename,
+ 	 * create duplicate proc files. -HW */
+ 	mutex_lock(&hlimit_mutex);
+ 	r->hinfo = htable_find_get(r->name, match->family);
+-	if (!r->hinfo && htable_create(r, match->family) != 0) {
++	if (!r->hinfo && htable_create_v0(r, match->family) != 0) {
+ 		mutex_unlock(&hlimit_mutex);
+ 		return false;
+ 	}
+@@ -547,14 +734,68 @@ hashlimit_checkentry(const char *tablename,
+ 	return true;
  }
  
++static bool
++hashlimit_mt_check(const char *tablename, const void *inf,
++                   const struct xt_match *match, void *matchinfo,
++                   unsigned int hook_mask)
++{
++	struct xt_hashlimit_mtinfo1 *info = matchinfo;
++
++	/* Check for overflow. */
++	if (info->cfg.burst == 0 ||
++	    user2credits(info->cfg.avg * info->cfg.burst) <
++	    user2credits(info->cfg.avg)) {
++		printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
++		       info->cfg.avg, info->cfg.burst);
++		return false;
++	}
++	if (info->cfg.gc_interval == 0 || info->cfg.expire == 0)
++		return false;
++	if (info->name[sizeof(info->name)-1] != '\0')
++		return false;
++	if (match->family == AF_INET) {
++		if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32)
++			return false;
++	} else {
++		if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128)
++			return false;
++	}
++
++	/* This is the best we've got: We cannot release and re-grab lock,
++	 * since checkentry() is called before x_tables.c grabs xt_mutex.
++	 * We also cannot grab the hashtable spinlock, since htable_create will
++	 * 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 */
++	mutex_lock(&hlimit_mutex);
++	info->hinfo = htable_find_get(info->name, match->family);
++	if (!info->hinfo && htable_create(info, match->family) != 0) {
++		mutex_unlock(&hlimit_mutex);
++		return false;
++	}
++	mutex_unlock(&hlimit_mutex);
++
++	/* Ugly hack: For SMP, we only want to use one set */
++	info->master = info;
++	return true;
++}
++
  static void
 -hashlimit_destroy(const struct xt_match *match, void *matchinfo)
-+hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
++hashlimit_mt_destroy_v0(const struct xt_match *match, void *matchinfo)
  {
  	const struct xt_hashlimit_info *r = matchinfo;
  
-@@ -563,7 +573,7 @@ struct compat_xt_hashlimit_info {
+ 	htable_put(r->hinfo);
+ }
+ 
++static void
++hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
++{
++	const struct xt_hashlimit_mtinfo1 *info = matchinfo;
++
++	htable_put(info->hinfo);
++}
++
+ #ifdef CONFIG_COMPAT
+ struct compat_xt_hashlimit_info {
+ 	char name[IFNAMSIZ];
+@@ -563,7 +804,7 @@ struct compat_xt_hashlimit_info {
  	compat_uptr_t master;
  };
  
@@ -905766,7 +972673,7 @@
  {
  	int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
  
-@@ -571,7 +581,7 @@ static void compat_from_user(void *dst, void *src)
+@@ -571,7 +812,7 @@ static void compat_from_user(void *dst, void *src)
  	memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);
  }
  
@@ -905775,7 +972682,7 @@
  {
  	int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
  
-@@ -579,35 +589,37 @@ static int compat_to_user(void __user *dst, void *src)
+@@ -579,39 +820,63 @@ static int compat_to_user(void __user *dst, void *src)
  }
  #endif
  
@@ -905783,9 +972690,10 @@
 +static struct xt_match hashlimit_mt_reg[] __read_mostly = {
  	{
  		.name		= "hashlimit",
++		.revision	= 0,
  		.family		= AF_INET,
 -		.match		= hashlimit_match,
-+		.match		= hashlimit_mt,
++		.match		= hashlimit_mt_v0,
  		.matchsize	= sizeof(struct xt_hashlimit_info),
  #ifdef CONFIG_COMPAT
  		.compatsize	= sizeof(struct compat_xt_hashlimit_info),
@@ -905796,16 +972704,26 @@
  #endif
 -		.checkentry	= hashlimit_checkentry,
 -		.destroy	= hashlimit_destroy,
-+		.checkentry	= hashlimit_mt_check,
-+		.destroy	= hashlimit_mt_destroy,
++		.checkentry	= hashlimit_mt_check_v0,
++		.destroy	= hashlimit_mt_destroy_v0,
  		.me		= THIS_MODULE
  	},
-+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
  	{
++		.name           = "hashlimit",
++		.revision       = 1,
++		.family         = AF_INET,
++		.match          = hashlimit_mt,
++		.matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
++		.checkentry     = hashlimit_mt_check,
++		.destroy        = hashlimit_mt_destroy,
++		.me             = THIS_MODULE,
++	},
++#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
++	{
  		.name		= "hashlimit",
  		.family		= AF_INET6,
 -		.match		= hashlimit_match,
-+		.match		= hashlimit_mt,
++		.match		= hashlimit_mt_v0,
  		.matchsize	= sizeof(struct xt_hashlimit_info),
  #ifdef CONFIG_COMPAT
  		.compatsize	= sizeof(struct compat_xt_hashlimit_info),
@@ -905816,15 +972734,46 @@
  #endif
 -		.checkentry	= hashlimit_checkentry,
 -		.destroy	= hashlimit_destroy,
-+		.checkentry	= hashlimit_mt_check,
-+		.destroy	= hashlimit_mt_destroy,
++		.checkentry	= hashlimit_mt_check_v0,
++		.destroy	= hashlimit_mt_destroy_v0,
  		.me		= THIS_MODULE
  	},
++	{
++		.name           = "hashlimit",
++		.revision       = 1,
++		.family         = AF_INET6,
++		.match          = hashlimit_mt,
++		.matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
++		.checkentry     = hashlimit_mt_check,
++		.destroy        = hashlimit_mt_destroy,
++		.me             = THIS_MODULE,
++	},
 +#endif
  };
  
  /* PROC stuff */
-@@ -670,6 +682,7 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family,
+ static void *dl_seq_start(struct seq_file *s, loff_t *pos)
++	__acquires(htable->lock)
+ {
+ 	struct proc_dir_entry *pde = s->private;
+ 	struct xt_hashlimit_htable *htable = pde->data;
+@@ -644,6 +909,7 @@ static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
+ }
+ 
+ static void dl_seq_stop(struct seq_file *s, void *v)
++	__releases(htable->lock)
+ {
+ 	struct proc_dir_entry *pde = s->private;
+ 	struct xt_hashlimit_htable *htable = pde->data;
+@@ -664,22 +930,24 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family,
+ 		return seq_printf(s, "%ld %u.%u.%u.%u:%u->"
+ 				     "%u.%u.%u.%u:%u %u %u %u\n",
+ 				 (long)(ent->expires - jiffies)/HZ,
+-				 NIPQUAD(ent->dst.addr.ip.src),
++				 NIPQUAD(ent->dst.ip.src),
+ 				 ntohs(ent->dst.src_port),
+-				 NIPQUAD(ent->dst.addr.ip.dst),
++				 NIPQUAD(ent->dst.ip.dst),
  				 ntohs(ent->dst.dst_port),
  				 ent->rateinfo.credit, ent->rateinfo.credit_cap,
  				 ent->rateinfo.cost);
@@ -905832,7 +972781,12 @@
  	case AF_INET6:
  		return seq_printf(s, "%ld " NIP6_FMT ":%u->"
  				     NIP6_FMT ":%u %u %u %u\n",
-@@ -680,6 +693,7 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family,
+ 				 (long)(ent->expires - jiffies)/HZ,
+-				 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src),
++				 NIP6(*(struct in6_addr *)&ent->dst.ip6.src),
+ 				 ntohs(ent->dst.src_port),
+-				 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst),
++				 NIP6(*(struct in6_addr *)&ent->dst.ip6.dst),
  				 ntohs(ent->dst.dst_port),
  				 ent->rateinfo.credit, ent->rateinfo.credit_cap,
  				 ent->rateinfo.cost);
@@ -905840,7 +972794,7 @@
  	default:
  		BUG();
  		return 0;
-@@ -728,11 +742,12 @@ static const struct file_operations dl_file_ops = {
+@@ -728,11 +996,12 @@ static const struct file_operations dl_file_ops = {
  	.release = seq_release
  };
  
@@ -905855,7 +972809,7 @@
  	if (err < 0)
  		goto err1;
  
-@@ -750,31 +765,36 @@ static int __init xt_hashlimit_init(void)
+@@ -750,31 +1019,36 @@ static int __init xt_hashlimit_init(void)
  				"entry\n");
  		goto err3;
  	}
@@ -906013,7 +972967,7 @@
 +module_exit(helper_mt_exit);
 diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c
 new file mode 100644
-index 0000000..dbea0e0
+index 0000000..01035fc
 --- /dev/null
 +++ b/net/netfilter/xt_iprange.c
 @@ -0,0 +1,180 @@
@@ -906120,7 +973074,7 @@
 +	int r;
 +
 +	for (i = 0; i < 4; ++i) {
-+		r = a->s6_addr32[i] - b->s6_addr32[i];
++		r = (__force u32)a->s6_addr32[i] - (__force u32)b->s6_addr32[i];
 +		if (r != 0)
 +			return r;
 +	}
@@ -906867,18 +973821,18 @@
 +module_exit(multiport_mt_exit);
 diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
 new file mode 100644
-index 0000000..d382f9c
+index 0000000..9059c16
 --- /dev/null
 +++ b/net/netfilter/xt_owner.c
-@@ -0,0 +1,211 @@
+@@ -0,0 +1,213 @@
 +/*
 + * Kernel module to match various things tied to sockets associated with
 + * locally generated outgoing packets.
 + *
 + * (C) 2000 Marc Boucher <marc at mbsi.ca>
 + *
-+ * Copyright © CC Computer Consultants GmbH, 2007
-+ * Contact: <jengelh at computergmbh.de>
++ * Copyright © CC Computer Consultants GmbH, 2007 - 2008
++ * <jengelh at computergmbh.de>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License version 2 as
@@ -906975,13 +973929,15 @@
 +		       (XT_OWNER_UID | XT_OWNER_GID)) == 0;
 +
 +	if (info->match & XT_OWNER_UID)
-+		if ((filp->f_uid != info->uid) ^
-+		    !!(info->invert & XT_OWNER_UID))
++		if ((filp->f_uid >= info->uid_min &&
++		    filp->f_uid <= info->uid_max) ^
++		    !(info->invert & XT_OWNER_UID))
 +			return false;
 +
 +	if (info->match & XT_OWNER_GID)
-+		if ((filp->f_gid != info->gid) ^
-+		    !!(info->invert & XT_OWNER_GID))
++		if ((filp->f_gid >= info->gid_min &&
++		    filp->f_gid <= info->gid_max) ^
++		    !(info->invert & XT_OWNER_GID))
 +			return false;
 +
 +	return true;
@@ -910784,7 +977740,7 @@
  /* Set the default configuration to allow Unlabeled packets */
  int netlbl_unlabel_defconf(void);
 diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
-index de3988b..6b178e1 100644
+index de3988b..1ab0da2 100644
 --- a/net/netlink/af_netlink.c
 +++ b/net/netlink/af_netlink.c
 @@ -156,7 +156,7 @@ static void netlink_sock_destruct(struct sock *sk)
@@ -911001,7 +977957,7 @@
  	u32 dst_pid;
  	u32 dst_group;
  	struct sk_buff *skb;
-@@ -1221,7 +1233,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
+@@ -1221,12 +1233,12 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
  		goto out;
  	err = -ENOBUFS;
  	skb = alloc_skb(len, GFP_KERNEL);
@@ -911010,6 +977966,12 @@
  		goto out;
  
  	NETLINK_CB(skb).pid	= nlk->pid;
+ 	NETLINK_CB(skb).dst_group = dst_group;
+-	NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
++	NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
+ 	selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
+ 	memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
+ 
 @@ -1237,7 +1249,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
  	 */
  
@@ -911039,7 +978001,30 @@
  		addr->nl_family = AF_NETLINK;
  		addr->nl_pad    = 0;
  		addr->nl_pid	= NETLINK_CB(skb).pid;
-@@ -1344,7 +1356,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
+@@ -1332,6 +1344,22 @@ static void netlink_data_ready(struct sock *sk, int len)
+  *	queueing.
+  */
+ 
++static void __netlink_release(struct sock *sk)
++{
++	/*
++	 * Last sock_put should drop referrence to sk->sk_net. It has already
++	 * been dropped in netlink_kernel_create. Taking referrence to stopping
++	 * namespace is not an option.
++	 * Take referrence to a socket to remove it from netlink lookup table
++	 * _alive_ and after that destroy it in the context of init_net.
++	 */
++
++	sock_hold(sk);
++	sock_release(sk->sk_socket);
++	sk->sk_net = get_net(&init_net);
++	sock_put(sk);
++}
++
+ struct sock *
+ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
+ 		      void (*input)(struct sk_buff *skb),
+@@ -1344,14 +1372,24 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
  
  	BUG_ON(!nl_table);
  
@@ -911048,21 +978033,49 @@
  		return NULL;
  
  	if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
-@@ -1380,9 +1392,13 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
+ 		return NULL;
+ 
+-	if (__netlink_create(net, sock, cb_mutex, unit) < 0)
+-		goto out_sock_release;
++	/*
++	 * We have to just have a reference on the net from sk, but don't
++	 * get_net it. Besides, we cannot get and then put the net here.
++	 * So we create one inside init_net and the move it to net.
++	 */
++
++	if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0)
++		goto out_sock_release_nosk;
++
++	sk = sock->sk;
++	put_net(sk->sk_net);
++	sk->sk_net = net;
+ 
+ 	if (groups < 32)
+ 		groups = 32;
+@@ -1360,7 +1398,6 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
+ 	if (!listeners)
+ 		goto out_sock_release;
+ 
+-	sk = sock->sk;
+ 	sk->sk_data_ready = netlink_data_ready;
+ 	if (input)
+ 		nlk_sk(sk)->netlink_rcv = input;
+@@ -1380,16 +1417,33 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
  		nl_table[unit].registered = 1;
  	} else {
  		kfree(listeners);
 +		nl_table[unit].registered++;
  	}
  	netlink_table_ungrab();
- 
-+	/* Do not hold an extra referrence to a namespace as this socket is
-+	 * internal to a namespace and does not prevent it to stop. */
-+	put_net(net);
+-
  	return sk;
  
  out_sock_release:
-@@ -1390,6 +1406,30 @@ out_sock_release:
+ 	kfree(listeners);
++	__netlink_release(sk);
++	return NULL;
++
++out_sock_release_nosk:
  	sock_release(sock);
  	return NULL;
  }
@@ -911075,25 +978088,14 @@
 +	if (sk == NULL || sk->sk_socket == NULL)
 +		return;
 +
-+	/*
-+	 * Last sock_put should drop referrence to sk->sk_net. It has already
-+	 * been dropped in netlink_kernel_create. Taking referrence to stopping
-+	 * namespace is not an option.
-+	 * Take referrence to a socket to remove it from netlink lookup table
-+	 * _alive_ and after that destroy it in the context of init_net.
-+	 */
-+	sock_hold(sk);
-+	sock_release(sk->sk_socket);
-+
-+	sk->sk_net = get_net(&init_net);
-+	sock_put(sk);
++	__netlink_release(sk);
 +}
 +EXPORT_SYMBOL(netlink_kernel_release);
 +
  
  /**
   * netlink_change_ngroups - change number of multicast groups
-@@ -1461,6 +1501,7 @@ void netlink_set_nonroot(int protocol, unsigned int flags)
+@@ -1461,6 +1515,7 @@ void netlink_set_nonroot(int protocol, unsigned int flags)
  	if ((unsigned int)protocol < MAX_LINKS)
  		nl_table[protocol].nl_nonroot = flags;
  }
@@ -911101,7 +978103,7 @@
  
  static void netlink_destroy_callback(struct netlink_callback *cb)
  {
-@@ -1529,8 +1570,9 @@ errout:
+@@ -1529,8 +1584,9 @@ errout:
  
  int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
  		       struct nlmsghdr *nlh,
@@ -911113,7 +978115,7 @@
  {
  	struct netlink_callback *cb;
  	struct sock *sk;
-@@ -1571,6 +1613,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+@@ -1571,6 +1627,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
  	 */
  	return -EINTR;
  }
@@ -911121,7 +978123,7 @@
  
  void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
  {
-@@ -1605,6 +1648,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
+@@ -1605,6 +1662,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
  	memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh));
  	netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
  }
@@ -911129,7 +978131,7 @@
  
  int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
  						     struct nlmsghdr *))
-@@ -1638,7 +1682,7 @@ ack:
+@@ -1638,7 +1696,7 @@ ack:
  			netlink_ack(skb, nlh, err);
  
  skip:
@@ -911138,7 +978140,7 @@
  		if (msglen > skb->len)
  			msglen = skb->len;
  		skb_pull(skb, msglen);
-@@ -1646,6 +1690,7 @@ skip:
+@@ -1646,6 +1704,7 @@ skip:
  
  	return 0;
  }
@@ -911146,7 +978148,7 @@
  
  /**
   * nlmsg_notify - send a notification netlink message
-@@ -1678,10 +1723,11 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
+@@ -1678,10 +1737,11 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
  
  	return err;
  }
@@ -911159,7 +978161,7 @@
  	int link;
  	int hash_idx;
  };
-@@ -1694,12 +1740,12 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
+@@ -1694,12 +1754,12 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
  	struct hlist_node *node;
  	loff_t off = 0;
  
@@ -911174,7 +978176,7 @@
  					continue;
  				if (off == pos) {
  					iter->link = i;
-@@ -1714,6 +1760,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
+@@ -1714,6 +1774,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
  }
  
  static void *netlink_seq_start(struct seq_file *seq, loff_t *pos)
@@ -911182,7 +978184,7 @@
  {
  	read_lock(&nl_table_lock);
  	return *pos ? netlink_seq_socket_idx(seq, *pos - 1) : SEQ_START_TOKEN;
-@@ -1734,7 +1781,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1734,7 +1795,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  	s = v;
  	do {
  		s = sk_next(s);
@@ -911191,7 +978193,7 @@
  	if (s)
  		return s;
  
-@@ -1746,7 +1793,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1746,7 +1807,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  
  		for (; j <= hash->mask; j++) {
  			s = sk_head(&hash->table[j]);
@@ -911200,7 +978202,7 @@
  				s = sk_next(s);
  			if (s) {
  				iter->link = i;
-@@ -1762,6 +1809,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+@@ -1762,6 +1823,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  }
  
  static void netlink_seq_stop(struct seq_file *seq, void *v)
@@ -911208,7 +978210,7 @@
  {
  	read_unlock(&nl_table_lock);
  }
-@@ -1802,27 +1850,8 @@ static const struct seq_operations netlink_seq_ops = {
+@@ -1802,27 +1864,8 @@ static const struct seq_operations netlink_seq_ops = {
  
  static int netlink_seq_open(struct inode *inode, struct file *file)
  {
@@ -911238,7 +978240,7 @@
  }
  
  static const struct file_operations netlink_seq_fops = {
-@@ -1830,7 +1859,7 @@ static const struct file_operations netlink_seq_fops = {
+@@ -1830,7 +1873,7 @@ static const struct file_operations netlink_seq_fops = {
  	.open		= netlink_seq_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
@@ -911247,7 +978249,7 @@
  };
  
  #endif
-@@ -1839,11 +1868,13 @@ int netlink_register_notifier(struct notifier_block *nb)
+@@ -1839,11 +1882,13 @@ int netlink_register_notifier(struct notifier_block *nb)
  {
  	return atomic_notifier_chain_register(&netlink_chain, nb);
  }
@@ -911261,7 +978263,7 @@
  
  static const struct proto_ops netlink_ops = {
  	.family =	PF_NETLINK,
-@@ -1922,7 +1953,7 @@ static int __init netlink_proto_init(void)
+@@ -1922,7 +1967,7 @@ static int __init netlink_proto_init(void)
  	for (i = 0; i < MAX_LINKS; i++) {
  		struct nl_pid_hash *hash = &nl_table[i].hash;
  
@@ -911270,7 +978272,7 @@
  		if (!hash->table) {
  			while (i-- > 0)
  				nl_pid_hash_free(nl_table[i].hash.table,
-@@ -1930,7 +1961,6 @@ static int __init netlink_proto_init(void)
+@@ -1930,7 +1975,6 @@ static int __init netlink_proto_init(void)
  			kfree(nl_table);
  			goto panic;
  		}
@@ -911278,7 +978280,7 @@
  		hash->max_shift = order;
  		hash->shift = 0;
  		hash->mask = 0;
-@@ -1948,14 +1978,3 @@ panic:
+@@ -1948,14 +1992,3 @@ panic:
  }
  
  core_initcall(netlink_proto_init);
@@ -911734,6 +978736,54 @@
  out:
  	return rc;
  }
+diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
+index d1e9d68..e4b051d 100644
+--- a/net/rfkill/rfkill-input.c
++++ b/net/rfkill/rfkill-input.c
+@@ -84,6 +84,7 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
+ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
+ static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
+ static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
++static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
+ 
+ static void rfkill_event(struct input_handle *handle, unsigned int type,
+ 			unsigned int code, int down)
+@@ -99,6 +100,9 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
+ 		case KEY_UWB:
+ 			rfkill_schedule_toggle(&rfkill_uwb);
+ 			break;
++		case KEY_WIMAX:
++			rfkill_schedule_toggle(&rfkill_wimax);
++			break;
+ 		default:
+ 			break;
+ 		}
+@@ -159,6 +163,11 @@ static const struct input_device_id rfkill_ids[] = {
+ 		.evbit = { BIT_MASK(EV_KEY) },
+ 		.keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
+ 	},
++	{
++		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
++		.evbit = { BIT_MASK(EV_KEY) },
++		.keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
++	},
+ 	{ }
+ };
+ 
+diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
+index d06d338..6562f86 100644
+--- a/net/rfkill/rfkill.c
++++ b/net/rfkill/rfkill.c
+@@ -126,6 +126,9 @@ static ssize_t rfkill_type_show(struct device *dev,
+ 	case RFKILL_TYPE_UWB:
+ 		type = "ultrawideband";
+ 		break;
++	case RFKILL_TYPE_WIMAX:
++		type = "wimax";
++		break;
+ 	default:
+ 		BUG();
+ 	}
 diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
 index ed2d65c..4a31a81 100644
 --- a/net/rose/af_rose.c
@@ -911915,6 +978965,19 @@
  	}
  	read_unlock(&sk->sk_callback_lock);
  }
+diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c
+index 3c04b00..d923124 100644
+--- a/net/rxrpc/ar-call.c
++++ b/net/rxrpc/ar-call.c
+@@ -15,7 +15,7 @@
+ #include <net/af_rxrpc.h>
+ #include "ar-internal.h"
+ 
+-const char *rxrpc_call_states[] = {
++const char *const rxrpc_call_states[] = {
+ 	[RXRPC_CALL_CLIENT_SEND_REQUEST]	= "ClSndReq",
+ 	[RXRPC_CALL_CLIENT_AWAIT_REPLY]		= "ClAwtRpl",
+ 	[RXRPC_CALL_CLIENT_RECV_REPLY]		= "ClRcvRpl",
 diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c
 index d6667f7..3869a58 100644
 --- a/net/rxrpc/ar-connection.c
@@ -911972,6 +979035,23 @@
  			_debug("first packet");
  			skb_queue_tail(&local->accept_queue, skb);
  			rxrpc_queue_work(&local->acceptor);
+diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
+index 58aaf89..1aaa2e8 100644
+--- a/net/rxrpc/ar-internal.h
++++ b/net/rxrpc/ar-internal.h
+@@ -565,9 +565,9 @@ extern void __exit rxrpc_destroy_all_peers(void);
+ /*
+  * ar-proc.c
+  */
+-extern const char *rxrpc_call_states[];
+-extern struct file_operations rxrpc_call_seq_fops;
+-extern struct file_operations rxrpc_connection_seq_fops;
++extern const char *const rxrpc_call_states[];
++extern const struct file_operations rxrpc_call_seq_fops;
++extern const struct file_operations rxrpc_connection_seq_fops;
+ 
+ /*
+  * ar-recvmsg.c
 diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
 index 90fa107..2abe208 100644
 --- a/net/rxrpc/ar-peer.c
@@ -911985,6 +979065,37 @@
  	if (ret < 0) {
  		_leave(" [route err %d]", ret);
  		return;
+diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c
+index 2e83ce3..83eda24 100644
+--- a/net/rxrpc/ar-proc.c
++++ b/net/rxrpc/ar-proc.c
+@@ -14,7 +14,7 @@
+ #include <net/af_rxrpc.h>
+ #include "ar-internal.h"
+ 
+-static const char *rxrpc_conn_states[] = {
++static const char *const rxrpc_conn_states[] = {
+ 	[RXRPC_CONN_UNUSED]		= "Unused  ",
+ 	[RXRPC_CONN_CLIENT]		= "Client  ",
+ 	[RXRPC_CONN_SERVER_UNSECURED]	= "SvUnsec ",
+@@ -98,7 +98,7 @@ static int rxrpc_call_seq_open(struct inode *inode, struct file *file)
+ 	return seq_open(file, &rxrpc_call_seq_ops);
+ }
+ 
+-struct file_operations rxrpc_call_seq_fops = {
++const struct file_operations rxrpc_call_seq_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= rxrpc_call_seq_open,
+ 	.read		= seq_read,
+@@ -183,7 +183,7 @@ static int rxrpc_connection_seq_open(struct inode *inode, struct file *file)
+ 	return seq_open(file, &rxrpc_connection_seq_ops);
+ }
+ 
+-struct file_operations rxrpc_connection_seq_fops = {
++const struct file_operations rxrpc_connection_seq_fops = {
+ 	.owner		= THIS_MODULE,
+ 	.open		= rxrpc_connection_seq_open,
+ 	.read		= seq_read,
 diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
 index 8e69d69..f48434a 100644
 --- a/net/rxrpc/rxkad.c
@@ -912008,18 +979119,36 @@
  	tmpbuf.x[1] = x;
  
 diff --git a/net/sched/Kconfig b/net/sched/Kconfig
-index 9c15c48..87af7c9 100644
+index 9c15c48..82adfe6 100644
 --- a/net/sched/Kconfig
 +++ b/net/sched/Kconfig
 @@ -198,6 +198,7 @@ config NET_SCH_NETEM
  
  config NET_SCH_INGRESS
  	tristate "Ingress Qdisc"
-+	depends on NET_CLS_ACT || NETFILTER
++	depends on NET_CLS_ACT
  	---help---
  	  Say Y here if you want to use classifiers for incoming packets.
  	  If unsure, say Y.
-@@ -445,7 +446,6 @@ config NET_ACT_IPT
+@@ -306,6 +307,17 @@ config NET_CLS_RSVP6
+ 	  To compile this code as a module, choose M here: the
+ 	  module will be called cls_rsvp6.
+ 
++config NET_CLS_FLOW
++	tristate "Flow classifier"
++	select NET_CLS
++	---help---
++	  If you say Y here, you will be able to classify packets based on
++	  a configurable combination of packet keys. This is mostly useful
++	  in combination with SFQ.
++
++	  To compile this code as a module, choose M here: the
++	  module will be called cls_flow.
++
+ config NET_EMATCH
+ 	bool "Extended Matches"
+ 	select NET_CLS
+@@ -445,7 +457,6 @@ config NET_ACT_IPT
  config NET_ACT_NAT
          tristate "Stateless NAT"
          depends on NET_CLS_ACT
@@ -912027,7 +979156,7 @@
          ---help---
  	  Say Y here to do stateless NAT on IPv4 packets.  You should use
  	  netfilter for NAT unless you know what you are doing.
-@@ -476,15 +476,6 @@ config NET_ACT_SIMP
+@@ -476,15 +487,6 @@ config NET_ACT_SIMP
  	  To compile this code as a module, choose M here: the
  	  module will be called simple.
  
@@ -912043,6 +979172,18 @@
  config NET_CLS_IND
  	bool "Incoming device classification"
  	depends on NET_CLS_U32 || NET_CLS_FW
+diff --git a/net/sched/Makefile b/net/sched/Makefile
+index 81ecbe8..1d2b0f7 100644
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_NET_CLS_RSVP)	+= cls_rsvp.o
+ obj-$(CONFIG_NET_CLS_TCINDEX)	+= cls_tcindex.o
+ obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o
+ obj-$(CONFIG_NET_CLS_BASIC)	+= cls_basic.o
++obj-$(CONFIG_NET_CLS_FLOW)	+= cls_flow.o
+ obj-$(CONFIG_NET_EMATCH)	+= ematch.o
+ obj-$(CONFIG_NET_EMATCH_CMP)	+= em_cmp.o
+ obj-$(CONFIG_NET_EMATCH_NBYTE)	+= em_nbyte.o
 diff --git a/net/sched/act_api.c b/net/sched/act_api.c
 index 72cdb0f..0b8eb23 100644
 --- a/net/sched/act_api.c
@@ -913482,7 +980623,7 @@
  	return -1;
  }
 diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
-index 0365797..3377ca0 100644
+index 0365797..0fbedca 100644
 --- a/net/sched/cls_api.c
 +++ b/net/sched/cls_api.c
 @@ -23,33 +23,30 @@
@@ -913800,9 +980941,10 @@
 -int
 -tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
 -		  struct rtattr *rate_tlv, struct tcf_exts *exts,
+-		  struct tcf_ext_map *map)
 +int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
 +		  struct nlattr *rate_tlv, struct tcf_exts *exts,
- 		  struct tcf_ext_map *map)
++		  const struct tcf_ext_map *map)
  {
  	memset(exts, 0, sizeof(*exts));
  
@@ -913859,7 +981001,7 @@
  {
  #ifdef CONFIG_NET_CLS_ACT
  	if (src->action) {
-@@ -515,9 +532,9 @@ tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
+@@ -515,10 +532,10 @@ tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
  	}
  #endif
  }
@@ -913867,10 +981009,12 @@
  
 -int
 -tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
+-	      struct tcf_ext_map *map)
 +int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
- 	      struct tcf_ext_map *map)
++		  const struct tcf_ext_map *map)
  {
  #ifdef CONFIG_NET_CLS_ACT
+ 	if (map->action && exts->action) {
 @@ -527,39 +544,45 @@ tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
  		 * to work with both old and new modes of entering
  		 * tc data even if iproute2  was newer - jhs
@@ -913913,7 +981057,7 @@
 -		    struct tcf_ext_map *map)
 +
 +int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
-+			struct tcf_ext_map *map)
++			const struct tcf_ext_map *map)
  {
  #ifdef CONFIG_NET_CLS_ACT
  	if (exts->action)
@@ -913943,9 +981087,18 @@
 -EXPORT_SYMBOL(tcf_exts_dump);
 -EXPORT_SYMBOL(tcf_exts_dump_stats);
 diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
-index 8dbcf27..bfb4342 100644
+index 8dbcf27..956915c 100644
 --- a/net/sched/cls_basic.c
 +++ b/net/sched/cls_basic.c
+@@ -35,7 +35,7 @@ struct basic_filter
+ 	struct list_head	link;
+ };
+ 
+-static struct tcf_ext_map basic_ext_map = {
++static const struct tcf_ext_map basic_ext_map = {
+ 	.action = TCA_BASIC_ACT,
+ 	.police = TCA_BASIC_POLICE
+ };
 @@ -129,28 +129,29 @@ static int basic_delete(struct tcf_proto *tp, unsigned long arg)
  	return -ENOENT;
  }
@@ -914071,10 +981224,685 @@
  	.kind		=	"basic",
  	.classify	=	basic_classify,
  	.init		=	basic_init,
+diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
+new file mode 100644
+index 0000000..5a7f6a3
+--- /dev/null
++++ b/net/sched/cls_flow.c
+@@ -0,0 +1,660 @@
++/*
++ * net/sched/cls_flow.c		Generic flow classifier
++ *
++ * Copyright (c) 2007, 2008 Patrick McHardy <kaber at trash.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/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/jhash.h>
++#include <linux/random.h>
++#include <linux/pkt_cls.h>
++#include <linux/skbuff.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++
++#include <net/pkt_cls.h>
++#include <net/ip.h>
++#include <net/route.h>
++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
++#include <net/netfilter/nf_conntrack.h>
++#endif
++
++struct flow_head {
++	struct list_head	filters;
++};
++
++struct flow_filter {
++	struct list_head	list;
++	struct tcf_exts		exts;
++	struct tcf_ematch_tree	ematches;
++	u32			handle;
++
++	u32			nkeys;
++	u32			keymask;
++	u32			mode;
++	u32			mask;
++	u32			xor;
++	u32			rshift;
++	u32			addend;
++	u32			divisor;
++	u32			baseclass;
++};
++
++static u32 flow_hashrnd __read_mostly;
++static int flow_hashrnd_initted __read_mostly;
++
++static const struct tcf_ext_map flow_ext_map = {
++	.action	= TCA_FLOW_ACT,
++	.police	= TCA_FLOW_POLICE,
++};
++
++static inline u32 addr_fold(void *addr)
++{
++	unsigned long a = (unsigned long)addr;
++
++	return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
++}
++
++static u32 flow_get_src(const struct sk_buff *skb)
++{
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP):
++		return ntohl(ip_hdr(skb)->saddr);
++	case __constant_htons(ETH_P_IPV6):
++		return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
++	default:
++		return addr_fold(skb->sk);
++	}
++}
++
++static u32 flow_get_dst(const struct sk_buff *skb)
++{
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP):
++		return ntohl(ip_hdr(skb)->daddr);
++	case __constant_htons(ETH_P_IPV6):
++		return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
++	default:
++		return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
++	}
++}
++
++static u32 flow_get_proto(const struct sk_buff *skb)
++{
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP):
++		return ip_hdr(skb)->protocol;
++	case __constant_htons(ETH_P_IPV6):
++		return ipv6_hdr(skb)->nexthdr;
++	default:
++		return 0;
++	}
++}
++
++static int has_ports(u8 protocol)
++{
++	switch (protocol) {
++	case IPPROTO_TCP:
++	case IPPROTO_UDP:
++	case IPPROTO_UDPLITE:
++	case IPPROTO_SCTP:
++	case IPPROTO_DCCP:
++	case IPPROTO_ESP:
++		return 1;
++	default:
++		return 0;
++	}
++}
++
++static u32 flow_get_proto_src(const struct sk_buff *skb)
++{
++	u32 res = 0;
++
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP): {
++		struct iphdr *iph = ip_hdr(skb);
++
++		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
++		    has_ports(iph->protocol))
++			res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
++		break;
++	}
++	case __constant_htons(ETH_P_IPV6): {
++		struct ipv6hdr *iph = ipv6_hdr(skb);
++
++		if (has_ports(iph->nexthdr))
++			res = ntohs(*(__be16 *)&iph[1]);
++		break;
++	}
++	default:
++		res = addr_fold(skb->sk);
++	}
++
++	return res;
++}
++
++static u32 flow_get_proto_dst(const struct sk_buff *skb)
++{
++	u32 res = 0;
++
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP): {
++		struct iphdr *iph = ip_hdr(skb);
++
++		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
++		    has_ports(iph->protocol))
++			res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
++		break;
++	}
++	case __constant_htons(ETH_P_IPV6): {
++		struct ipv6hdr *iph = ipv6_hdr(skb);
++
++		if (has_ports(iph->nexthdr))
++			res = ntohs(*(__be16 *)((void *)&iph[1] + 2));
++		break;
++	}
++	default:
++		res = addr_fold(skb->dst) ^ (__force u16)skb->protocol;
++	}
++
++	return res;
++}
++
++static u32 flow_get_iif(const struct sk_buff *skb)
++{
++	return skb->iif;
++}
++
++static u32 flow_get_priority(const struct sk_buff *skb)
++{
++	return skb->priority;
++}
++
++static u32 flow_get_mark(const struct sk_buff *skb)
++{
++	return skb->mark;
++}
++
++static u32 flow_get_nfct(const struct sk_buff *skb)
++{
++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
++	return addr_fold(skb->nfct);
++#else
++	return 0;
++#endif
++}
++
++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
++#define CTTUPLE(skb, member)						\
++({									\
++	enum ip_conntrack_info ctinfo;					\
++	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);			\
++	if (ct == NULL)							\
++		goto fallback;						\
++	ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member;			\
++})
++#else
++#define CTTUPLE(skb, member)						\
++({									\
++	goto fallback;							\
++	0;								\
++})
++#endif
++
++static u32 flow_get_nfct_src(const struct sk_buff *skb)
++{
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP):
++		return ntohl(CTTUPLE(skb, src.u3.ip));
++	case __constant_htons(ETH_P_IPV6):
++		return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
++	}
++fallback:
++	return flow_get_src(skb);
++}
++
++static u32 flow_get_nfct_dst(const struct sk_buff *skb)
++{
++	switch (skb->protocol) {
++	case __constant_htons(ETH_P_IP):
++		return ntohl(CTTUPLE(skb, dst.u3.ip));
++	case __constant_htons(ETH_P_IPV6):
++		return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
++	}
++fallback:
++	return flow_get_dst(skb);
++}
++
++static u32 flow_get_nfct_proto_src(const struct sk_buff *skb)
++{
++	return ntohs(CTTUPLE(skb, src.u.all));
++fallback:
++	return flow_get_proto_src(skb);
++}
++
++static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb)
++{
++	return ntohs(CTTUPLE(skb, dst.u.all));
++fallback:
++	return flow_get_proto_dst(skb);
++}
++
++static u32 flow_get_rtclassid(const struct sk_buff *skb)
++{
++#ifdef CONFIG_NET_CLS_ROUTE
++	if (skb->dst)
++		return skb->dst->tclassid;
++#endif
++	return 0;
++}
++
++static u32 flow_get_skuid(const struct sk_buff *skb)
++{
++	if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
++		return skb->sk->sk_socket->file->f_uid;
++	return 0;
++}
++
++static u32 flow_get_skgid(const struct sk_buff *skb)
++{
++	if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
++		return skb->sk->sk_socket->file->f_gid;
++	return 0;
++}
++
++static u32 flow_key_get(const struct sk_buff *skb, int key)
++{
++	switch (key) {
++	case FLOW_KEY_SRC:
++		return flow_get_src(skb);
++	case FLOW_KEY_DST:
++		return flow_get_dst(skb);
++	case FLOW_KEY_PROTO:
++		return flow_get_proto(skb);
++	case FLOW_KEY_PROTO_SRC:
++		return flow_get_proto_src(skb);
++	case FLOW_KEY_PROTO_DST:
++		return flow_get_proto_dst(skb);
++	case FLOW_KEY_IIF:
++		return flow_get_iif(skb);
++	case FLOW_KEY_PRIORITY:
++		return flow_get_priority(skb);
++	case FLOW_KEY_MARK:
++		return flow_get_mark(skb);
++	case FLOW_KEY_NFCT:
++		return flow_get_nfct(skb);
++	case FLOW_KEY_NFCT_SRC:
++		return flow_get_nfct_src(skb);
++	case FLOW_KEY_NFCT_DST:
++		return flow_get_nfct_dst(skb);
++	case FLOW_KEY_NFCT_PROTO_SRC:
++		return flow_get_nfct_proto_src(skb);
++	case FLOW_KEY_NFCT_PROTO_DST:
++		return flow_get_nfct_proto_dst(skb);
++	case FLOW_KEY_RTCLASSID:
++		return flow_get_rtclassid(skb);
++	case FLOW_KEY_SKUID:
++		return flow_get_skuid(skb);
++	case FLOW_KEY_SKGID:
++		return flow_get_skgid(skb);
++	default:
++		WARN_ON(1);
++		return 0;
++	}
++}
++
++static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
++			 struct tcf_result *res)
++{
++	struct flow_head *head = tp->root;
++	struct flow_filter *f;
++	u32 keymask;
++	u32 classid;
++	unsigned int n, key;
++	int r;
++
++	list_for_each_entry(f, &head->filters, list) {
++		u32 keys[f->nkeys];
++
++		if (!tcf_em_tree_match(skb, &f->ematches, NULL))
++			continue;
++
++		keymask = f->keymask;
++
++		for (n = 0; n < f->nkeys; n++) {
++			key = ffs(keymask) - 1;
++			keymask &= ~(1 << key);
++			keys[n] = flow_key_get(skb, key);
++		}
++
++		if (f->mode == FLOW_MODE_HASH)
++			classid = jhash2(keys, f->nkeys, flow_hashrnd);
++		else {
++			classid = keys[0];
++			classid = (classid & f->mask) ^ f->xor;
++			classid = (classid >> f->rshift) + f->addend;
++		}
++
++		if (f->divisor)
++			classid %= f->divisor;
++
++		res->class   = 0;
++		res->classid = TC_H_MAKE(f->baseclass, f->baseclass + classid);
++
++		r = tcf_exts_exec(skb, &f->exts, res);
++		if (r < 0)
++			continue;
++		return r;
++	}
++	return -1;
++}
++
++static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
++	[TCA_FLOW_KEYS]		= { .type = NLA_U32 },
++	[TCA_FLOW_MODE]		= { .type = NLA_U32 },
++	[TCA_FLOW_BASECLASS]	= { .type = NLA_U32 },
++	[TCA_FLOW_RSHIFT]	= { .type = NLA_U32 },
++	[TCA_FLOW_ADDEND]	= { .type = NLA_U32 },
++	[TCA_FLOW_MASK]		= { .type = NLA_U32 },
++	[TCA_FLOW_XOR]		= { .type = NLA_U32 },
++	[TCA_FLOW_DIVISOR]	= { .type = NLA_U32 },
++	[TCA_FLOW_ACT]		= { .type = NLA_NESTED },
++	[TCA_FLOW_POLICE]	= { .type = NLA_NESTED },
++	[TCA_FLOW_EMATCHES]	= { .type = NLA_NESTED },
++};
++
++static int flow_change(struct tcf_proto *tp, unsigned long base,
++		       u32 handle, struct nlattr **tca,
++		       unsigned long *arg)
++{
++	struct flow_head *head = tp->root;
++	struct flow_filter *f;
++	struct nlattr *opt = tca[TCA_OPTIONS];
++	struct nlattr *tb[TCA_FLOW_MAX + 1];
++	struct tcf_exts e;
++	struct tcf_ematch_tree t;
++	unsigned int nkeys = 0;
++	u32 baseclass = 0;
++	u32 keymask = 0;
++	u32 mode;
++	int err;
++
++	if (opt == NULL)
++		return -EINVAL;
++
++	err = nla_parse_nested(tb, TCA_FLOW_MAX, opt, flow_policy);
++	if (err < 0)
++		return err;
++
++	if (tb[TCA_FLOW_BASECLASS]) {
++		baseclass = nla_get_u32(tb[TCA_FLOW_BASECLASS]);
++		if (TC_H_MIN(baseclass) == 0)
++			return -EINVAL;
++	}
++
++	if (tb[TCA_FLOW_KEYS]) {
++		keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
++		if (fls(keymask) - 1 > FLOW_KEY_MAX)
++			return -EOPNOTSUPP;
++
++		nkeys = hweight32(keymask);
++		if (nkeys == 0)
++			return -EINVAL;
++	}
++
++	err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
++	if (err < 0)
++		return err;
++
++	err = tcf_em_tree_validate(tp, tb[TCA_FLOW_EMATCHES], &t);
++	if (err < 0)
++		goto err1;
++
++	f = (struct flow_filter *)*arg;
++	if (f != NULL) {
++		err = -EINVAL;
++		if (f->handle != handle && handle)
++			goto err2;
++
++		mode = f->mode;
++		if (tb[TCA_FLOW_MODE])
++			mode = nla_get_u32(tb[TCA_FLOW_MODE]);
++		if (mode != FLOW_MODE_HASH && nkeys > 1)
++			goto err2;
++	} else {
++		err = -EINVAL;
++		if (!handle)
++			goto err2;
++		if (!tb[TCA_FLOW_KEYS])
++			goto err2;
++
++		mode = FLOW_MODE_MAP;
++		if (tb[TCA_FLOW_MODE])
++			mode = nla_get_u32(tb[TCA_FLOW_MODE]);
++		if (mode != FLOW_MODE_HASH && nkeys > 1)
++			goto err2;
++
++		if (TC_H_MAJ(baseclass) == 0)
++			baseclass = TC_H_MAKE(tp->q->handle, baseclass);
++		if (TC_H_MIN(baseclass) == 0)
++			baseclass = TC_H_MAKE(baseclass, 1);
++
++		err = -ENOBUFS;
++		f = kzalloc(sizeof(*f), GFP_KERNEL);
++		if (f == NULL)
++			goto err2;
++
++		f->handle = handle;
++		f->mask	  = ~0U;
++	}
++
++	tcf_exts_change(tp, &f->exts, &e);
++	tcf_em_tree_change(tp, &f->ematches, &t);
++
++	tcf_tree_lock(tp);
++
++	if (tb[TCA_FLOW_KEYS]) {
++		f->keymask = keymask;
++		f->nkeys   = nkeys;
++	}
++
++	f->mode = mode;
++
++	if (tb[TCA_FLOW_MASK])
++		f->mask = nla_get_u32(tb[TCA_FLOW_MASK]);
++	if (tb[TCA_FLOW_XOR])
++		f->xor = nla_get_u32(tb[TCA_FLOW_XOR]);
++	if (tb[TCA_FLOW_RSHIFT])
++		f->rshift = nla_get_u32(tb[TCA_FLOW_RSHIFT]);
++	if (tb[TCA_FLOW_ADDEND])
++		f->addend = nla_get_u32(tb[TCA_FLOW_ADDEND]);
++
++	if (tb[TCA_FLOW_DIVISOR])
++		f->divisor = nla_get_u32(tb[TCA_FLOW_DIVISOR]);
++	if (baseclass)
++		f->baseclass = baseclass;
++
++	if (*arg == 0)
++		list_add_tail(&f->list, &head->filters);
++
++	tcf_tree_unlock(tp);
++
++	*arg = (unsigned long)f;
++	return 0;
++
++err2:
++	tcf_em_tree_destroy(tp, &t);
++err1:
++	tcf_exts_destroy(tp, &e);
++	return err;
++}
++
++static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f)
++{
++	tcf_exts_destroy(tp, &f->exts);
++	tcf_em_tree_destroy(tp, &f->ematches);
++	kfree(f);
++}
++
++static int flow_delete(struct tcf_proto *tp, unsigned long arg)
++{
++	struct flow_filter *f = (struct flow_filter *)arg;
++
++	tcf_tree_lock(tp);
++	list_del(&f->list);
++	tcf_tree_unlock(tp);
++	flow_destroy_filter(tp, f);
++	return 0;
++}
++
++static int flow_init(struct tcf_proto *tp)
++{
++	struct flow_head *head;
++
++	if (!flow_hashrnd_initted) {
++		get_random_bytes(&flow_hashrnd, 4);
++		flow_hashrnd_initted = 1;
++	}
++
++	head = kzalloc(sizeof(*head), GFP_KERNEL);
++	if (head == NULL)
++		return -ENOBUFS;
++	INIT_LIST_HEAD(&head->filters);
++	tp->root = head;
++	return 0;
++}
++
++static void flow_destroy(struct tcf_proto *tp)
++{
++	struct flow_head *head = tp->root;
++	struct flow_filter *f, *next;
++
++	list_for_each_entry_safe(f, next, &head->filters, list) {
++		list_del(&f->list);
++		flow_destroy_filter(tp, f);
++	}
++	kfree(head);
++}
++
++static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
++{
++	struct flow_head *head = tp->root;
++	struct flow_filter *f;
++
++	list_for_each_entry(f, &head->filters, list)
++		if (f->handle == handle)
++			return (unsigned long)f;
++	return 0;
++}
++
++static void flow_put(struct tcf_proto *tp, unsigned long f)
++{
++	return;
++}
++
++static int flow_dump(struct tcf_proto *tp, unsigned long fh,
++		     struct sk_buff *skb, struct tcmsg *t)
++{
++	struct flow_filter *f = (struct flow_filter *)fh;
++	struct nlattr *nest;
++
++	if (f == NULL)
++		return skb->len;
++
++	t->tcm_handle = f->handle;
++
++	nest = nla_nest_start(skb, TCA_OPTIONS);
++	if (nest == NULL)
++		goto nla_put_failure;
++
++	NLA_PUT_U32(skb, TCA_FLOW_KEYS, f->keymask);
++	NLA_PUT_U32(skb, TCA_FLOW_MODE, f->mode);
++
++	if (f->mask != ~0 || f->xor != 0) {
++		NLA_PUT_U32(skb, TCA_FLOW_MASK, f->mask);
++		NLA_PUT_U32(skb, TCA_FLOW_XOR, f->xor);
++	}
++	if (f->rshift)
++		NLA_PUT_U32(skb, TCA_FLOW_RSHIFT, f->rshift);
++	if (f->addend)
++		NLA_PUT_U32(skb, TCA_FLOW_ADDEND, f->addend);
++
++	if (f->divisor)
++		NLA_PUT_U32(skb, TCA_FLOW_DIVISOR, f->divisor);
++	if (f->baseclass)
++		NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
++
++	if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
++		goto nla_put_failure;
++
++	if (f->ematches.hdr.nmatches &&
++	    tcf_em_tree_dump(skb, &f->ematches, TCA_FLOW_EMATCHES) < 0)
++		goto nla_put_failure;
++
++	nla_nest_end(skb, nest);
++
++	if (tcf_exts_dump_stats(skb, &f->exts, &flow_ext_map) < 0)
++		goto nla_put_failure;
++
++	return skb->len;
++
++nla_put_failure:
++	nlmsg_trim(skb, nest);
++	return -1;
++}
++
++static void flow_walk(struct tcf_proto *tp, struct tcf_walker *arg)
++{
++	struct flow_head *head = tp->root;
++	struct flow_filter *f;
++
++	list_for_each_entry(f, &head->filters, list) {
++		if (arg->count < arg->skip)
++			goto skip;
++		if (arg->fn(tp, (unsigned long)f, arg) < 0) {
++			arg->stop = 1;
++			break;
++		}
++skip:
++		arg->count++;
++	}
++}
++
++static struct tcf_proto_ops cls_flow_ops __read_mostly = {
++	.kind		= "flow",
++	.classify	= flow_classify,
++	.init		= flow_init,
++	.destroy	= flow_destroy,
++	.change		= flow_change,
++	.delete		= flow_delete,
++	.get		= flow_get,
++	.put		= flow_put,
++	.dump		= flow_dump,
++	.walk		= flow_walk,
++	.owner		= THIS_MODULE,
++};
++
++static int __init cls_flow_init(void)
++{
++	return register_tcf_proto_ops(&cls_flow_ops);
++}
++
++static void __exit cls_flow_exit(void)
++{
++	unregister_tcf_proto_ops(&cls_flow_ops);
++}
++
++module_init(cls_flow_init);
++module_exit(cls_flow_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Patrick McHardy <kaber at trash.net>");
++MODULE_DESCRIPTION("TC flow classifier");
 diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
-index 8adbd6a..436a6e7 100644
+index 8adbd6a..b0f90e5 100644
 --- a/net/sched/cls_fw.c
 +++ b/net/sched/cls_fw.c
+@@ -47,7 +47,7 @@ struct fw_filter
+ 	struct tcf_exts		exts;
+ };
+ 
+-static struct tcf_ext_map fw_ext_map = {
++static const struct tcf_ext_map fw_ext_map = {
+ 	.action = TCA_FW_ACT,
+ 	.police = TCA_FW_POLICE
+ };
 @@ -186,39 +186,41 @@ out:
  	return -EINVAL;
  }
@@ -914227,9 +982055,18 @@
  	.classify	=	fw_classify,
  	.init		=	fw_init,
 diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
-index 0a8409c..f7e7d39 100644
+index 0a8409c..784dcb8 100644
 --- a/net/sched/cls_route.c
 +++ b/net/sched/cls_route.c
+@@ -62,7 +62,7 @@ struct route4_filter
+ 
+ #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
+ 
+-static struct tcf_ext_map route_ext_map = {
++static const struct tcf_ext_map route_ext_map = {
+ 	.police = TCA_ROUTE4_POLICE,
+ 	.action = TCA_ROUTE4_ACT
+ };
 @@ -323,9 +323,16 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg)
  	return 0;
  }
@@ -914573,7 +982410,7 @@
  	return -1;
  }
 diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
-index 2314820..ee60b2d 100644
+index 2314820..7a7bff5 100644
 --- a/net/sched/cls_tcindex.c
 +++ b/net/sched/cls_tcindex.c
 @@ -29,19 +29,6 @@
@@ -914596,6 +982433,15 @@
  #define	PRIV(tp)	((struct tcindex_data *) (tp)->root)
  
  
+@@ -68,7 +55,7 @@ struct tcindex_data {
+ 	int fall_through;	/* 0: only classify if explicit match */
+ };
+ 
+-static struct tcf_ext_map tcindex_ext_map = {
++static const struct tcf_ext_map tcindex_ext_map = {
+ 	.police = TCA_TCINDEX_POLICE,
+ 	.action = TCA_TCINDEX_ACT
+ };
 @@ -104,7 +91,8 @@ static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp,
  	struct tcindex_filter_result *f;
  	int key = (skb->tc_index & p->mask) >> p->shift;
@@ -914876,9 +982722,18 @@
  	.classify	=	tcindex_classify,
  	.init		=	tcindex_init,
 diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
-index c390082..e8a7756 100644
+index c390082..b18fa95 100644
 --- a/net/sched/cls_u32.c
 +++ b/net/sched/cls_u32.c
+@@ -82,7 +82,7 @@ struct tc_u_common
+ 	u32			hgenerator;
+ };
+ 
+-static struct tcf_ext_map u32_ext_map = {
++static const struct tcf_ext_map u32_ext_map = {
+ 	.action = TCA_U32_ACT,
+ 	.police = TCA_U32_POLICE
+ };
 @@ -460,10 +460,20 @@ static u32 gen_new_kid(struct tc_u_hnode *ht, u32 handle)
  	return handle|(i>0xFFF ? 0xFFF : i);
  }
@@ -918298,10 +986153,17 @@
  	.cl_ops		=	&htb_class_ops,
  	.id		=	"htb",
 diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
-index 3f8335e..3f72d52 100644
+index 3f8335e..274b1dd 100644
 --- a/net/sched/sch_ingress.c
 +++ b/net/sched/sch_ingress.c
-@@ -19,127 +19,71 @@
+@@ -12,387 +12,148 @@
+ #include <linux/list.h>
+ #include <linux/skbuff.h>
+ #include <linux/rtnetlink.h>
+-#include <linux/netfilter_ipv4.h>
+-#include <linux/netfilter_ipv6.h>
+-#include <linux/netfilter.h>
+ #include <net/netlink.h>
  #include <net/pkt_sched.h>
  
  
@@ -918327,12 +986189,10 @@
 -*/
 -#ifndef CONFIG_NET_CLS_ACT
 -#ifdef CONFIG_NETFILTER
-+/* Thanks to Doron Oz for this hack */
-+#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
- static int nf_registered;
- #endif
+-static int nf_registered;
 -#endif
- 
+-#endif
+-
  struct ingress_qdisc_data {
 -	struct Qdisc		*q;
  	struct tcf_proto	*filter_list;
@@ -918440,11 +986300,12 @@
 -	D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
  	result = tc_classify(skb, p->filter_list, &res);
 -	D2PRINTK("result %d class 0x%04x\n", result, res.classid);
+-	/*
+-	 * Unlike normal "enqueue" functions, ingress_enqueue returns a
+-	 * firewall FW_* code.
+-	 */
+-#ifdef CONFIG_NET_CLS_ACT
 +
- 	/*
- 	 * Unlike normal "enqueue" functions, ingress_enqueue returns a
- 	 * firewall FW_* code.
-@@ -148,23 +92,22 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch)
  	sch->bstats.packets++;
  	sch->bstats.bytes += skb->len;
  	switch (result) {
@@ -918477,12 +986338,13 @@
 +		result = TC_ACT_OK;
 +		break;
  	}
- #else
+-#else
 -	D2PRINTK("Overriding result to ACCEPT\n");
- 	result = NF_ACCEPT;
- 	sch->bstats.packets++;
- 	sch->bstats.bytes += skb->len;
-@@ -173,39 +116,8 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch)
+-	result = NF_ACCEPT;
+-	sch->bstats.packets++;
+-	sch->bstats.bytes += skb->len;
+-#endif
+ 
  	return result;
  }
  
@@ -918519,29 +986381,31 @@
 -#ifdef CONFIG_NETFILTER
 -static unsigned int
 -ing_hook(unsigned int hook, struct sk_buff *skb,
-+#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-+static unsigned int ing_hook(unsigned int hook, struct sk_buff *skb,
- 			     const struct net_device *indev,
- 			     const struct net_device *outdev,
- 			     int (*okfn)(struct sk_buff *))
-@@ -213,12 +125,7 @@ ing_hook(unsigned int hook, struct sk_buff *skb,
- 
- 	struct Qdisc *q;
- 	struct net_device *dev = skb->dev;
+-			     const struct net_device *indev,
+-			     const struct net_device *outdev,
+-			     int (*okfn)(struct sk_buff *))
+-{
+-
+-	struct Qdisc *q;
+-	struct net_device *dev = skb->dev;
 -	int fwres=NF_ACCEPT;
 -
 -	DPRINTK("ing_hook: skb %s dev=%s len=%u\n",
 -		skb->sk ? "(owned)" : "(unowned)",
 -		skb->dev ? skb->dev->name : "(no dev)",
 -		skb->len);
-+	int fwres = NF_ACCEPT;
- 
- 	if (dev->qdisc_ingress) {
- 		spin_lock(&dev->ingress_lock);
-@@ -231,168 +138,101 @@ ing_hook(unsigned int hook, struct sk_buff *skb,
- }
- 
- /* after ipt_filter */
+-
+-	if (dev->qdisc_ingress) {
+-		spin_lock(&dev->ingress_lock);
+-		if ((q = dev->qdisc_ingress) != NULL)
+-			fwres = q->enqueue(skb, q);
+-		spin_unlock(&dev->ingress_lock);
+-	}
+-
+-	return fwres;
+-}
+-
+-/* after ipt_filter */
 -static struct nf_hook_ops ing_ops = {
 -	.hook           = ing_hook,
 -	.owner		= THIS_MODULE,
@@ -918556,29 +986420,13 @@
 -	.pf             = PF_INET6,
 -	.hooknum        = NF_IP6_PRE_ROUTING,
 -	.priority       = NF_IP6_PRI_FILTER + 1,
-+static struct nf_hook_ops ing_ops[] __read_mostly = {
-+	{
-+		.hook           = ing_hook,
-+		.owner		= THIS_MODULE,
-+		.pf             = PF_INET,
-+		.hooknum        = NF_INET_PRE_ROUTING,
-+		.priority       = NF_IP_PRI_FILTER + 1,
-+	},
-+	{
-+		.hook           = ing_hook,
-+		.owner		= THIS_MODULE,
-+		.pf             = PF_INET6,
-+		.hooknum        = NF_INET_PRE_ROUTING,
-+		.priority       = NF_IP6_PRI_FILTER + 1,
-+	},
- };
+-};
 -
 -#endif
- #endif
- 
+-#endif
+-
 -static int ingress_init(struct Qdisc *sch,struct rtattr *opt)
-+static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
- {
+-{
 -	struct ingress_qdisc_data *p = PRIV(sch);
 -
 -/* Make sure either netfilter or preferably CLS_ACT is
@@ -918588,35 +986436,33 @@
 -	printk("You MUST compile classifier actions into the kernel\n");
 -	return -EINVAL;
 -#else
-+#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
- 	printk("Ingress scheduler: Classifier actions prefered over netfilter\n");
+-	printk("Ingress scheduler: Classifier actions prefered over netfilter\n");
 -#endif
 -#endif
- 
+-
 -#ifndef CONFIG_NET_CLS_ACT
 -#ifdef CONFIG_NETFILTER
- 	if (!nf_registered) {
+-	if (!nf_registered) {
 -		if (nf_register_hook(&ing_ops) < 0) {
-+		if (nf_register_hooks(ing_ops, ARRAY_SIZE(ing_ops)) < 0) {
- 			printk("ingress qdisc registration error \n");
- 			return -EINVAL;
- 		}
- 		nf_registered++;
+-			printk("ingress qdisc registration error \n");
+-			return -EINVAL;
+-		}
+-		nf_registered++;
 -
 -		if (nf_register_hook(&ing6_ops) < 0) {
 -			printk("IPv6 ingress qdisc registration error, " \
 -			    "disabling IPv6 support.\n");
 -		} else
 -			nf_registered++;
- 	}
- #endif
+-	}
+-#endif
 -#endif
 -
 -	DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
 -	p->q = &noop_qdisc;
- 	return 0;
- }
- 
+-	return 0;
+-}
+-
 -
 -static void ingress_reset(struct Qdisc *sch)
 -{
@@ -918700,7 +986546,7 @@
 -	.dequeue	=	ingress_dequeue,
 -	.requeue	=	ingress_requeue,
 -	.drop		=	ingress_drop,
- 	.init		=	ingress_init,
+-	.init		=	ingress_init,
 -	.reset		=	ingress_reset,
  	.destroy	=	ingress_destroy,
 -	.change		=	NULL,
@@ -918732,10 +986578,7 @@
 -			nf_unregister_hook(&ing6_ops);
 -	}
 -#endif
-+#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-+	if (nf_registered)
-+		nf_unregister_hooks(ing_ops, ARRAY_SIZE(ing_ops));
- #endif
+-#endif
  }
 +
  module_init(ingress_module_init)
@@ -919303,10 +987146,18 @@
  	.priv_size	=	sizeof(struct red_sched_data),
  	.cl_ops		=	&red_class_ops,
 diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
-index b542c87..91af539 100644
+index b542c87..a20e2ef 100644
 --- a/net/sched/sch_sfq.c
 +++ b/net/sched/sch_sfq.c
-@@ -122,7 +122,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
+@@ -95,6 +95,7 @@ struct sfq_sched_data
+ 	int		limit;
+ 
+ /* Variables */
++	struct tcf_proto *filter_list;
+ 	struct timer_list perturb_timer;
+ 	u32		perturbation;
+ 	sfq_index	tail;		/* Index of current slot in round */
+@@ -122,7 +123,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
  	{
  		const struct iphdr *iph = ip_hdr(skb);
  		h = iph->daddr;
@@ -919315,7 +987166,7 @@
  		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
  		    (iph->protocol == IPPROTO_TCP ||
  		     iph->protocol == IPPROTO_UDP ||
-@@ -137,7 +137,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
+@@ -137,7 +138,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
  	{
  		struct ipv6hdr *iph = ipv6_hdr(skb);
  		h = iph->daddr.s6_addr32[3];
@@ -919324,7 +987175,7 @@
  		if (iph->nexthdr == IPPROTO_TCP ||
  		    iph->nexthdr == IPPROTO_UDP ||
  		    iph->nexthdr == IPPROTO_UDPLITE ||
-@@ -148,9 +148,10 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
+@@ -148,12 +149,46 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
  		break;
  	}
  	default:
@@ -919337,7 +987188,43 @@
  	return sfq_fold_hash(q, h, h2);
  }
  
-@@ -208,7 +209,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
++static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
++				 int *qerr)
++{
++	struct sfq_sched_data *q = qdisc_priv(sch);
++	struct tcf_result res;
++	int result;
++
++	if (TC_H_MAJ(skb->priority) == sch->handle &&
++	    TC_H_MIN(skb->priority) > 0 &&
++	    TC_H_MIN(skb->priority) <= SFQ_HASH_DIVISOR)
++		return TC_H_MIN(skb->priority);
++
++	if (!q->filter_list)
++		return sfq_hash(q, skb) + 1;
++
++	*qerr = NET_XMIT_BYPASS;
++	result = tc_classify(skb, q->filter_list, &res);
++	if (result >= 0) {
++#ifdef CONFIG_NET_CLS_ACT
++		switch (result) {
++		case TC_ACT_STOLEN:
++		case TC_ACT_QUEUED:
++			*qerr = NET_XMIT_SUCCESS;
++		case TC_ACT_SHOT:
++			return 0;
++		}
++#endif
++		if (TC_H_MIN(res.classid) <= SFQ_HASH_DIVISOR)
++			return TC_H_MIN(res.classid);
++	}
++	return 0;
++}
++
+ static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
+ {
+ 	sfq_index p, n;
+@@ -208,7 +243,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
  	   drop a packet from it */
  
  	if (d > 1) {
@@ -919346,7 +987233,7 @@
  		skb = q->qs[x].prev;
  		len = skb->len;
  		__skb_unlink(skb, &q->qs[x]);
-@@ -241,7 +242,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
+@@ -241,17 +276,28 @@ static unsigned int sfq_drop(struct Qdisc *sch)
  }
  
  static int
@@ -919354,8 +987241,22 @@
 +sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
  {
  	struct sfq_sched_data *q = qdisc_priv(sch);
- 	unsigned hash = sfq_hash(q, skb);
-@@ -252,6 +253,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+-	unsigned hash = sfq_hash(q, skb);
++	unsigned int hash;
+ 	sfq_index x;
++	int ret;
++
++	hash = sfq_classify(skb, sch, &ret);
++	if (hash == 0) {
++		if (ret == NET_XMIT_BYPASS)
++			sch->qstats.drops++;
++		kfree_skb(skb);
++		return ret;
++	}
++	hash--;
+ 
+ 	x = q->ht[hash];
+ 	if (x == SFQ_DEPTH) {
  		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
  		q->hash[x] = hash;
  	}
@@ -919363,7 +987264,7 @@
  	/* If selected queue has length q->limit, this means that
  	 * all another queues are empty and that we do simple tail drop,
  	 * i.e. drop _this_ packet.
-@@ -284,7 +286,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+@@ -284,17 +330,28 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
  }
  
  static int
@@ -919371,8 +987272,22 @@
 +sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
  {
  	struct sfq_sched_data *q = qdisc_priv(sch);
- 	unsigned hash = sfq_hash(q, skb);
-@@ -295,6 +297,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
+-	unsigned hash = sfq_hash(q, skb);
++	unsigned int hash;
+ 	sfq_index x;
++	int ret;
++
++	hash = sfq_classify(skb, sch, &ret);
++	if (hash == 0) {
++		if (ret == NET_XMIT_BYPASS)
++			sch->qstats.drops++;
++		kfree_skb(skb);
++		return ret;
++	}
++	hash--;
+ 
+ 	x = q->ht[hash];
+ 	if (x == SFQ_DEPTH) {
  		q->ht[hash] = x = q->dep[SFQ_DEPTH].next;
  		q->hash[x] = hash;
  	}
@@ -919380,7 +987295,7 @@
  	sch->qstats.backlog += skb->len;
  	__skb_queue_head(&q->qs[x], skb);
  	/* If selected queue has length q->limit+1, this means that
-@@ -310,6 +313,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
+@@ -310,6 +367,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
  		kfree_skb(skb);
  		return NET_XMIT_CN;
  	}
@@ -919388,7 +987303,7 @@
  	sfq_inc(q, x);
  	if (q->qs[x].qlen == 1) {		/* The flow is new */
  		if (q->tail == SFQ_DEPTH) {	/* It is the first flow */
-@@ -322,6 +326,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
+@@ -322,6 +380,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
  			q->tail = x;
  		}
  	}
@@ -919396,7 +987311,7 @@
  	if (++sch->q.qlen <= q->limit) {
  		sch->qstats.requeues++;
  		return 0;
-@@ -336,7 +341,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
+@@ -336,7 +395,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
  
  
  static struct sk_buff *
@@ -919405,7 +987320,7 @@
  {
  	struct sfq_sched_data *q = qdisc_priv(sch);
  	struct sk_buff *skb;
-@@ -373,7 +378,7 @@ sfq_dequeue(struct Qdisc* sch)
+@@ -373,7 +432,7 @@ sfq_dequeue(struct Qdisc* sch)
  }
  
  static void
@@ -919414,7 +987329,7 @@
  {
  	struct sk_buff *skb;
  
-@@ -383,27 +388,27 @@ sfq_reset(struct Qdisc* sch)
+@@ -383,27 +442,27 @@ sfq_reset(struct Qdisc* sch)
  
  static void sfq_perturbation(unsigned long arg)
  {
@@ -919448,7 +987363,7 @@
  	if (ctl->limit)
  		q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1);
  
-@@ -415,41 +420,44 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
+@@ -415,41 +474,44 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
  	del_timer(&q->perturb_timer);
  	if (q->perturb_period) {
  		mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
@@ -919503,7 +987418,16 @@
  		sfq_link(q, i);
  	return 0;
  }
-@@ -467,22 +475,22 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
+@@ -457,6 +519,8 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
+ static void sfq_destroy(struct Qdisc *sch)
+ {
+ 	struct sfq_sched_data *q = qdisc_priv(sch);
++
++	tcf_destroy_chain(q->filter_list);
+ 	del_timer(&q->perturb_timer);
+ }
+ 
+@@ -467,24 +531,94 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
  	struct tc_sfq_qopt opt;
  
  	opt.quantum = q->quantum;
@@ -919526,10 +987450,84 @@
  }
  
 -static struct Qdisc_ops sfq_qdisc_ops = {
+-	.next		=	NULL,
+-	.cl_ops		=	NULL,
++static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
++			    struct nlattr **tca, unsigned long *arg)
++{
++	return -EOPNOTSUPP;
++}
++
++static unsigned long sfq_get(struct Qdisc *sch, u32 classid)
++{
++	return 0;
++}
++
++static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl)
++{
++	struct sfq_sched_data *q = qdisc_priv(sch);
++
++	if (cl)
++		return NULL;
++	return &q->filter_list;
++}
++
++static int sfq_dump_class(struct Qdisc *sch, unsigned long cl,
++			  struct sk_buff *skb, struct tcmsg *tcm)
++{
++	tcm->tcm_handle |= TC_H_MIN(cl);
++	return 0;
++}
++
++static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
++				struct gnet_dump *d)
++{
++	struct sfq_sched_data *q = qdisc_priv(sch);
++	sfq_index idx = q->ht[cl-1];
++	struct gnet_stats_queue qs = { .qlen = q->qs[idx].qlen };
++	struct tc_sfq_xstats xstats = { .allot = q->allot[idx] };
++
++	if (gnet_stats_copy_queue(d, &qs) < 0)
++		return -1;
++	return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
++}
++
++static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
++{
++	struct sfq_sched_data *q = qdisc_priv(sch);
++	unsigned int i;
++
++	if (arg->stop)
++		return;
++
++	for (i = 0; i < SFQ_HASH_DIVISOR; i++) {
++		if (q->ht[i] == SFQ_DEPTH ||
++		    arg->count < arg->skip) {
++			arg->count++;
++			continue;
++		}
++		if (arg->fn(sch, i + 1, arg) < 0) {
++			arg->stop = 1;
++			break;
++		}
++		arg->count++;
++	}
++}
++
++static const struct Qdisc_class_ops sfq_class_ops = {
++	.get		=	sfq_get,
++	.change		=	sfq_change_class,
++	.tcf_chain	=	sfq_find_tcf,
++	.dump		=	sfq_dump_class,
++	.dump_stats	=	sfq_dump_class_stats,
++	.walk		=	sfq_walk,
++};
++
 +static struct Qdisc_ops sfq_qdisc_ops __read_mostly = {
- 	.next		=	NULL,
- 	.cl_ops		=	NULL,
++	.cl_ops		=	&sfq_class_ops,
  	.id		=	"sfq",
+ 	.priv_size	=	sizeof(struct sfq_sched_data),
+ 	.enqueue	=	sfq_enqueue,
 diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
 index b0d8109..0b7d78f 100644
 --- a/net/sched/sch_tbf.c
@@ -919685,9 +987683,18 @@
  	.cl_ops		=	&tbf_class_ops,
  	.id		=	"tbf",
 diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
-index c0ed06d..1411c7b 100644
+index c0ed06d..0444fd0 100644
 --- a/net/sched/sch_teql.c
 +++ b/net/sched/sch_teql.c
+@@ -71,7 +71,7 @@ struct teql_sched_data
+ 
+ #define NEXT_SLAVE(q) (((struct teql_sched_data*)qdisc_priv(q))->next)
+ 
+-#define FMASK (IFF_BROADCAST|IFF_POINTOPOINT|IFF_BROADCAST)
++#define FMASK (IFF_BROADCAST|IFF_POINTOPOINT)
+ 
+ /* "teql*" qdisc routines */
+ 
 @@ -168,7 +168,7 @@ teql_destroy(struct Qdisc* sch)
  	}
  }
@@ -920530,7 +988537,7 @@
  	sysctl_sctp_wmem[2] = max(64*1024, max_share);
  
 diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
-index 3cc629d..dd98763 100644
+index 3cc629d..77383e9 100644
 --- a/net/sctp/sm_make_chunk.c
 +++ b/net/sctp/sm_make_chunk.c
 @@ -1275,6 +1275,9 @@ nodata:
@@ -920623,6 +988630,15 @@
  	case SCTP_PARAM_HOST_NAME_ADDRESS:
  		/* Tell the peer, we won't support this param.  */
  		sctp_process_hn_param(asoc, param, chunk, err_chunk);
+@@ -2014,7 +2056,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
+ 		break;
+ 
+ 	case SCTP_PARAM_HMAC_ALGO:
+-		if (!sctp_auth_enable)
++		if (sctp_auth_enable)
+ 			break;
+ 		/* Fall Through */
+ fallthrough:
 @@ -2134,10 +2176,11 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
  					!asoc->peer.peer_hmacs))
  		asoc->peer.auth_capable = 0;
@@ -921410,6 +989426,19 @@
  out:
  	return err;
  }
+diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
+index 5c69a72..92e1dbe 100644
+--- a/net/sunrpc/Makefile
++++ b/net/sunrpc/Makefile
+@@ -11,6 +11,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
+ 	    auth.o auth_null.o auth_unix.o \
+ 	    svc.o svcsock.o svcauth.o svcauth_unix.o \
+ 	    rpcb_clnt.o timer.o xdr.o \
+-	    sunrpc_syms.o cache.o rpc_pipe.o
++	    sunrpc_syms.o cache.o rpc_pipe.o \
++	    svc_xprt.o
+ sunrpc-$(CONFIG_PROC_FS) += stats.o
+ sunrpc-$(CONFIG_SYSCTL) += sysctl.o
 diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
 index 1ea2755..eca941c 100644
 --- a/net/sunrpc/auth.c
@@ -921514,11 +989543,394 @@
  	mlen -= left;
  	msg->copied += mlen;
  	msg->errno = 0;
+diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
+index 73940df..481f984 100644
+--- a/net/sunrpc/auth_gss/svcauth_gss.c
++++ b/net/sunrpc/auth_gss/svcauth_gss.c
+@@ -224,38 +224,34 @@ static int rsi_parse(struct cache_detail *cd,
+ 
+ 	/* major/minor */
+ 	len = qword_get(&mesg, buf, mlen);
+-	if (len < 0)
++	if (len <= 0)
+ 		goto out;
+-	if (len == 0) {
++	rsii.major_status = simple_strtoul(buf, &ep, 10);
++	if (*ep)
++		goto out;
++	len = qword_get(&mesg, buf, mlen);
++	if (len <= 0)
++		goto out;
++	rsii.minor_status = simple_strtoul(buf, &ep, 10);
++	if (*ep)
+ 		goto out;
+-	} else {
+-		rsii.major_status = simple_strtoul(buf, &ep, 10);
+-		if (*ep)
+-			goto out;
+-		len = qword_get(&mesg, buf, mlen);
+-		if (len <= 0)
+-			goto out;
+-		rsii.minor_status = simple_strtoul(buf, &ep, 10);
+-		if (*ep)
+-			goto out;
+ 
+-		/* out_handle */
+-		len = qword_get(&mesg, buf, mlen);
+-		if (len < 0)
+-			goto out;
+-		status = -ENOMEM;
+-		if (dup_to_netobj(&rsii.out_handle, buf, len))
+-			goto out;
++	/* out_handle */
++	len = qword_get(&mesg, buf, mlen);
++	if (len < 0)
++		goto out;
++	status = -ENOMEM;
++	if (dup_to_netobj(&rsii.out_handle, buf, len))
++		goto out;
+ 
+-		/* out_token */
+-		len = qword_get(&mesg, buf, mlen);
+-		status = -EINVAL;
+-		if (len < 0)
+-			goto out;
+-		status = -ENOMEM;
+-		if (dup_to_netobj(&rsii.out_token, buf, len))
+-			goto out;
+-	}
++	/* out_token */
++	len = qword_get(&mesg, buf, mlen);
++	status = -EINVAL;
++	if (len < 0)
++		goto out;
++	status = -ENOMEM;
++	if (dup_to_netobj(&rsii.out_token, buf, len))
++		goto out;
+ 	rsii.h.expiry_time = expiry;
+ 	rsip = rsi_update(&rsii, rsip);
+ 	status = 0;
+@@ -975,6 +971,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
+ 	struct kvec *resv = &rqstp->rq_res.head[0];
+ 	struct xdr_netobj tmpobj;
+ 	struct rsi *rsip, rsikey;
++	int ret;
+ 
+ 	/* Read the verifier; should be NULL: */
+ 	*authp = rpc_autherr_badverf;
+@@ -1014,23 +1011,27 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
+ 		/* No upcall result: */
+ 		return SVC_DROP;
+ 	case 0:
++		ret = SVC_DROP;
+ 		/* Got an answer to the upcall; use it: */
+ 		if (gss_write_init_verf(rqstp, rsip))
+-			return SVC_DROP;
++			goto out;
+ 		if (resv->iov_len + 4 > PAGE_SIZE)
+-			return SVC_DROP;
++			goto out;
+ 		svc_putnl(resv, RPC_SUCCESS);
+ 		if (svc_safe_putnetobj(resv, &rsip->out_handle))
+-			return SVC_DROP;
++			goto out;
+ 		if (resv->iov_len + 3 * 4 > PAGE_SIZE)
+-			return SVC_DROP;
++			goto out;
+ 		svc_putnl(resv, rsip->major_status);
+ 		svc_putnl(resv, rsip->minor_status);
+ 		svc_putnl(resv, GSS_SEQ_WIN);
+ 		if (svc_safe_putnetobj(resv, &rsip->out_token))
+-			return SVC_DROP;
++			goto out;
+ 	}
+-	return SVC_COMPLETE;
++	ret = SVC_COMPLETE;
++out:
++	cache_put(&rsip->h, &rsi_cache);
++	return ret;
+ }
+ 
+ /*
+@@ -1125,6 +1126,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
+ 	case RPC_GSS_PROC_DESTROY:
+ 		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+ 			goto auth_err;
++		rsci->h.expiry_time = get_seconds();
+ 		set_bit(CACHE_NEGATIVE, &rsci->h.flags);
+ 		if (resv->iov_len + 4 > PAGE_SIZE)
+ 			goto drop;
+@@ -1386,19 +1388,26 @@ int
+ gss_svc_init(void)
+ {
+ 	int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
+-	if (rv == 0) {
+-		cache_register(&rsc_cache);
+-		cache_register(&rsi_cache);
+-	}
++	if (rv)
++		return rv;
++	rv = cache_register(&rsc_cache);
++	if (rv)
++		goto out1;
++	rv = cache_register(&rsi_cache);
++	if (rv)
++		goto out2;
++	return 0;
++out2:
++	cache_unregister(&rsc_cache);
++out1:
++	svc_auth_unregister(RPC_AUTH_GSS);
+ 	return rv;
+ }
+ 
+ void
+ gss_svc_shutdown(void)
+ {
+-	if (cache_unregister(&rsc_cache))
+-		printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
+-	if (cache_unregister(&rsi_cache))
+-		printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
++	cache_unregister(&rsc_cache);
++	cache_unregister(&rsi_cache);
+ 	svc_auth_unregister(RPC_AUTH_GSS);
+ }
 diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
-index 8e05557..73f053d 100644
+index 8e05557..636c8e0 100644
 --- a/net/sunrpc/cache.c
 +++ b/net/sunrpc/cache.c
-@@ -1127,6 +1127,7 @@ struct handle {
+@@ -245,6 +245,7 @@ int cache_check(struct cache_detail *detail,
+ 		cache_put(h, detail);
+ 	return rv;
+ }
++EXPORT_SYMBOL(cache_check);
+ 
+ /*
+  * caches need to be periodically cleaned.
+@@ -290,44 +291,78 @@ static const struct file_operations cache_flush_operations;
+ static void do_cache_clean(struct work_struct *work);
+ static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
+ 
+-void cache_register(struct cache_detail *cd)
++static void remove_cache_proc_entries(struct cache_detail *cd)
+ {
+-	cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+-	if (cd->proc_ent) {
+-		struct proc_dir_entry *p;
+-		cd->proc_ent->owner = cd->owner;
+-		cd->channel_ent = cd->content_ent = NULL;
++	if (cd->proc_ent == NULL)
++		return;
++	if (cd->flush_ent)
++		remove_proc_entry("flush", cd->proc_ent);
++	if (cd->channel_ent)
++		remove_proc_entry("channel", cd->proc_ent);
++	if (cd->content_ent)
++		remove_proc_entry("content", cd->proc_ent);
++	cd->proc_ent = NULL;
++	remove_proc_entry(cd->name, proc_net_rpc);
++}
+ 
+-		p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
+-				      cd->proc_ent);
+-		cd->flush_ent =  p;
+-		if (p) {
+-			p->proc_fops = &cache_flush_operations;
+-			p->owner = cd->owner;
+-			p->data = cd;
+-		}
++#ifdef CONFIG_PROC_FS
++static int create_cache_proc_entries(struct cache_detail *cd)
++{
++	struct proc_dir_entry *p;
+ 
+-		if (cd->cache_request || cd->cache_parse) {
+-			p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
+-					      cd->proc_ent);
+-			cd->channel_ent = p;
+-			if (p) {
+-				p->proc_fops = &cache_file_operations;
+-				p->owner = cd->owner;
+-				p->data = cd;
+-			}
+-		}
+-		if (cd->cache_show) {
+-			p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
+-					      cd->proc_ent);
+-			cd->content_ent = p;
+-			if (p) {
+-				p->proc_fops = &content_file_operations;
+-				p->owner = cd->owner;
+-				p->data = cd;
+-			}
+-		}
++	cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
++	if (cd->proc_ent == NULL)
++		goto out_nomem;
++	cd->proc_ent->owner = cd->owner;
++	cd->channel_ent = cd->content_ent = NULL;
++
++	p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, cd->proc_ent);
++	cd->flush_ent = p;
++	if (p == NULL)
++		goto out_nomem;
++	p->proc_fops = &cache_flush_operations;
++	p->owner = cd->owner;
++	p->data = cd;
++
++	if (cd->cache_request || cd->cache_parse) {
++		p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
++				      cd->proc_ent);
++		cd->channel_ent = p;
++		if (p == NULL)
++			goto out_nomem;
++		p->proc_fops = &cache_file_operations;
++		p->owner = cd->owner;
++		p->data = cd;
+ 	}
++	if (cd->cache_show) {
++		p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
++				      cd->proc_ent);
++		cd->content_ent = p;
++		if (p == NULL)
++			goto out_nomem;
++		p->proc_fops = &content_file_operations;
++		p->owner = cd->owner;
++		p->data = cd;
++	}
++	return 0;
++out_nomem:
++	remove_cache_proc_entries(cd);
++	return -ENOMEM;
++}
++#else /* CONFIG_PROC_FS */
++static int create_cache_proc_entries(struct cache_detail *cd)
++{
++	return 0;
++}
++#endif
++
++int cache_register(struct cache_detail *cd)
++{
++	int ret;
++
++	ret = create_cache_proc_entries(cd);
++	if (ret)
++		return ret;
+ 	rwlock_init(&cd->hash_lock);
+ 	INIT_LIST_HEAD(&cd->queue);
+ 	spin_lock(&cache_list_lock);
+@@ -341,9 +376,11 @@ void cache_register(struct cache_detail *cd)
+ 
+ 	/* start the cleaning process */
+ 	schedule_delayed_work(&cache_cleaner, 0);
++	return 0;
+ }
++EXPORT_SYMBOL(cache_register);
+ 
+-int cache_unregister(struct cache_detail *cd)
++void cache_unregister(struct cache_detail *cd)
+ {
+ 	cache_purge(cd);
+ 	spin_lock(&cache_list_lock);
+@@ -351,30 +388,23 @@ int cache_unregister(struct cache_detail *cd)
+ 	if (cd->entries || atomic_read(&cd->inuse)) {
+ 		write_unlock(&cd->hash_lock);
+ 		spin_unlock(&cache_list_lock);
+-		return -EBUSY;
++		goto out;
+ 	}
+ 	if (current_detail == cd)
+ 		current_detail = NULL;
+ 	list_del_init(&cd->others);
+ 	write_unlock(&cd->hash_lock);
+ 	spin_unlock(&cache_list_lock);
+-	if (cd->proc_ent) {
+-		if (cd->flush_ent)
+-			remove_proc_entry("flush", cd->proc_ent);
+-		if (cd->channel_ent)
+-			remove_proc_entry("channel", cd->proc_ent);
+-		if (cd->content_ent)
+-			remove_proc_entry("content", cd->proc_ent);
+-
+-		cd->proc_ent = NULL;
+-		remove_proc_entry(cd->name, proc_net_rpc);
+-	}
++	remove_cache_proc_entries(cd);
+ 	if (list_empty(&cache_list)) {
+ 		/* module must be being unloaded so its safe to kill the worker */
+ 		cancel_delayed_work_sync(&cache_cleaner);
+ 	}
+-	return 0;
++	return;
++out:
++	printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
+ }
++EXPORT_SYMBOL(cache_unregister);
+ 
+ /* clean cache tries to find something to clean
+  * and cleans it.
+@@ -489,6 +519,7 @@ void cache_flush(void)
+ 	while (cache_clean() != -1)
+ 		cond_resched();
+ }
++EXPORT_SYMBOL(cache_flush);
+ 
+ void cache_purge(struct cache_detail *detail)
+ {
+@@ -497,7 +528,7 @@ void cache_purge(struct cache_detail *detail)
+ 	cache_flush();
+ 	detail->flush_time = 1;
+ }
+-
++EXPORT_SYMBOL(cache_purge);
+ 
+ 
+ /*
+@@ -634,13 +665,13 @@ void cache_clean_deferred(void *owner)
+ /*
+  * communicate with user-space
+  *
+- * We have a magic /proc file - /proc/sunrpc/cache
+- * On read, you get a full request, or block
+- * On write, an update request is processed
+- * Poll works if anything to read, and always allows write
++ * We have a magic /proc file - /proc/sunrpc/<cachename>/channel.
++ * On read, you get a full request, or block.
++ * On write, an update request is processed.
++ * Poll works if anything to read, and always allows write.
+  *
+  * Implemented by linked list of requests.  Each open file has
+- * a ->private that also exists in this list.  New request are added
++ * a ->private that also exists in this list.  New requests are added
+  * to the end and may wakeup and preceding readers.
+  * New readers are added to the head.  If, on read, an item is found with
+  * CACHE_UPCALLING clear, we free it from the list.
+@@ -963,6 +994,7 @@ void qword_add(char **bpp, int *lp, char *str)
+ 	*bpp = bp;
+ 	*lp = len;
+ }
++EXPORT_SYMBOL(qword_add);
+ 
+ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
+ {
+@@ -991,6 +1023,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
+ 	*bpp = bp;
+ 	*lp = len;
+ }
++EXPORT_SYMBOL(qword_addhex);
+ 
+ static void warn_no_listener(struct cache_detail *detail)
+ {
+@@ -1113,6 +1146,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
+ 	*dest = '\0';
+ 	return len;
+ }
++EXPORT_SYMBOL(qword_get);
+ 
+ 
+ /*
+@@ -1127,6 +1161,7 @@ struct handle {
  };
  
  static void *c_start(struct seq_file *m, loff_t *pos)
@@ -921526,7 +989938,7 @@
  {
  	loff_t n = *pos;
  	unsigned hash, entry;
-@@ -1183,6 +1184,7 @@ static void *c_next(struct seq_file *m, void *p, loff_t *pos)
+@@ -1183,6 +1218,7 @@ static void *c_next(struct seq_file *m, void *p, loff_t *pos)
  }
  
  static void c_stop(struct seq_file *m, void *p)
@@ -921534,6 +989946,30 @@
  {
  	struct cache_detail *cd = ((struct handle*)m->private)->cd;
  	read_unlock(&cd->hash_lock);
+@@ -1242,18 +1278,18 @@ static ssize_t read_flush(struct file *file, char __user *buf,
+ 	struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
+ 	char tbuf[20];
+ 	unsigned long p = *ppos;
+-	int len;
++	size_t len;
+ 
+ 	sprintf(tbuf, "%lu\n", cd->flush_time);
+ 	len = strlen(tbuf);
+ 	if (p >= len)
+ 		return 0;
+ 	len -= p;
+-	if (len > count) len = count;
++	if (len > count)
++		len = count;
+ 	if (copy_to_user(buf, (void*)(tbuf+p), len))
+-		len = -EFAULT;
+-	else
+-		*ppos += len;
++		return -EFAULT;
++	*ppos += len;
+ 	return len;
+ }
+ 
 diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
 index 76be83e..0998e6d 100644
 --- a/net/sunrpc/clnt.c
@@ -922229,630 +990665,3998 @@
  	if (IS_ERR(rpcb_clnt))
  		return PTR_ERR(rpcb_clnt);
  
-@@ -252,13 +199,15 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
-  * @vers: RPC version number to bind
-  * @prot: transport protocol to use to make this request
-  *
-+ * Return value is the requested advertised port number,
-+ * or a negative errno value.
-+ *
-  * Called from outside the RPC client in a synchronous task context.
-  * Uses default timeout parameters specified by underlying transport.
-  *
-- * XXX: Needs to support IPv6, and rpcbind versions 3 and 4
-+ * XXX: Needs to support IPv6
-  */
--int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
--		      __u32 vers, int prot)
-+int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
+@@ -252,13 +199,15 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+  * @vers: RPC version number to bind
+  * @prot: transport protocol to use to make this request
+  *
++ * Return value is the requested advertised port number,
++ * or a negative errno value.
++ *
+  * Called from outside the RPC client in a synchronous task context.
+  * Uses default timeout parameters specified by underlying transport.
+  *
+- * XXX: Needs to support IPv6, and rpcbind versions 3 and 4
++ * XXX: Needs to support IPv6
+  */
+-int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
+-		      __u32 vers, int prot)
++int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
+ {
+ 	struct rpcbind_args map = {
+ 		.r_prog		= prog,
+@@ -272,14 +221,13 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
+ 		.rpc_resp	= &map.r_port,
+ 	};
+ 	struct rpc_clnt	*rpcb_clnt;
+-	char hostname[40];
+ 	int status;
+ 
+ 	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
+ 		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+ 
+-	sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+-	rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
++	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
++				sizeof(*sin), prot, 2, 0);
+ 	if (IS_ERR(rpcb_clnt))
+ 		return PTR_ERR(rpcb_clnt);
+ 
+@@ -295,6 +243,24 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
+ }
+ EXPORT_SYMBOL_GPL(rpcb_getport_sync);
+ 
++static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version)
++{
++	struct rpc_message msg = {
++		.rpc_proc = rpcb_next_version[version].rpc_proc,
++		.rpc_argp = map,
++		.rpc_resp = &map->r_port,
++	};
++	struct rpc_task_setup task_setup_data = {
++		.rpc_client = rpcb_clnt,
++		.rpc_message = &msg,
++		.callback_ops = &rpcb_getport_ops,
++		.callback_data = map,
++		.flags = RPC_TASK_ASYNC,
++	};
++
++	return rpc_run_task(&task_setup_data);
++}
++
+ /**
+  * rpcb_getport_async - obtain the port for a given RPC service on a given host
+  * @task: task that is waiting for portmapper request
+@@ -305,12 +271,14 @@ EXPORT_SYMBOL_GPL(rpcb_getport_sync);
+ void rpcb_getport_async(struct rpc_task *task)
+ {
+ 	struct rpc_clnt *clnt = task->tk_client;
+-	int bind_version;
++	u32 bind_version;
+ 	struct rpc_xprt *xprt = task->tk_xprt;
+ 	struct rpc_clnt	*rpcb_clnt;
+ 	static struct rpcbind_args *map;
+ 	struct rpc_task	*child;
+-	struct sockaddr addr;
++	struct sockaddr_storage addr;
++	struct sockaddr *sap = (struct sockaddr *)&addr;
++	size_t salen;
+ 	int status;
+ 	struct rpcb_info *info;
+ 
+@@ -340,10 +308,10 @@ void rpcb_getport_async(struct rpc_task *task)
+ 		goto bailout_nofree;
+ 	}
+ 
+-	rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
++	salen = rpc_peeraddr(clnt, sap, sizeof(addr));
+ 
+ 	/* Don't ever use rpcbind v2 for AF_INET6 requests */
+-	switch (addr.sa_family) {
++	switch (sap->sa_family) {
+ 	case AF_INET:
+ 		info = rpcb_next_version;
+ 		break;
+@@ -368,7 +336,7 @@ void rpcb_getport_async(struct rpc_task *task)
+ 	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
+ 		task->tk_pid, __FUNCTION__, bind_version);
+ 
+-	rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
++	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
+ 				bind_version, 0);
+ 	if (IS_ERR(rpcb_clnt)) {
+ 		status = PTR_ERR(rpcb_clnt);
+@@ -390,12 +358,10 @@ void rpcb_getport_async(struct rpc_task *task)
+ 	map->r_port = 0;
+ 	map->r_xprt = xprt_get(xprt);
+ 	map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
+-	memcpy(map->r_addr,
+-	       rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
+-	       sizeof(map->r_addr));
++	map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
+ 	map->r_owner = RPCB_OWNER_STRING;	/* ignored for GETADDR */
+ 
+-	child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
++	child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index);
+ 	rpc_release_client(rpcb_clnt);
+ 	if (IS_ERR(child)) {
+ 		status = -EIO;
+@@ -518,7 +484,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
+ 	 * Simple sanity check.  The smallest possible universal
+ 	 * address is an IPv4 address string containing 11 bytes.
+ 	 */
+-	if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN)
++	if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN)
+ 		goto out_err;
+ 
+ 	/*
+@@ -569,7 +535,7 @@ out_err:
+ #define RPCB_boolean_sz		(1u)
+ 
+ #define RPCB_netid_sz		(1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
+-#define RPCB_addr_sz		(1+XDR_QUADLEN(RPCB_MAXADDRLEN))
++#define RPCB_addr_sz		(1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
+ #define RPCB_ownerstring_sz	(1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
+ 
+ #define RPCB_mappingargs_sz	RPCB_program_sz+RPCB_version_sz+	\
+diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
+index c98873f..4c66912 100644
+--- a/net/sunrpc/sched.c
++++ b/net/sunrpc/sched.c
+@@ -45,7 +45,7 @@ static void			 rpc_release_task(struct rpc_task *task);
+ /*
+  * RPC tasks sit here while waiting for conditions to improve.
+  */
+-static RPC_WAITQ(delay_queue, "delayq");
++static struct rpc_wait_queue delay_queue;
+ 
+ /*
+  * rpciod-related stuff
+@@ -135,7 +135,7 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct r
+ 	if (unlikely(task->tk_priority > queue->maxpriority))
+ 		q = &queue->tasks[queue->maxpriority];
+ 	list_for_each_entry(t, q, u.tk_wait.list) {
+-		if (t->tk_cookie == task->tk_cookie) {
++		if (t->tk_owner == task->tk_owner) {
+ 			list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
+ 			return;
+ 		}
+@@ -208,26 +208,26 @@ static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int
+ 	queue->count = 1 << (priority * 2);
+ }
+ 
+-static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie)
++static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
+ {
+-	queue->cookie = cookie;
++	queue->owner = pid;
+ 	queue->nr = RPC_BATCH_COUNT;
+ }
+ 
+ static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
+ {
+ 	rpc_set_waitqueue_priority(queue, queue->maxpriority);
+-	rpc_set_waitqueue_cookie(queue, 0);
++	rpc_set_waitqueue_owner(queue, 0);
+ }
+ 
+-static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio)
++static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
+ {
+ 	int i;
+ 
+ 	spin_lock_init(&queue->lock);
+ 	for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
+ 		INIT_LIST_HEAD(&queue->tasks[i]);
+-	queue->maxpriority = maxprio;
++	queue->maxpriority = nr_queues - 1;
+ 	rpc_reset_waitqueue_priority(queue);
+ #ifdef RPC_DEBUG
+ 	queue->name = qname;
+@@ -236,18 +236,18 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
+ 
+ void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+ {
+-	__rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH);
++	__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
+ }
+ 
+ void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+ {
+-	__rpc_init_priority_wait_queue(queue, qname, 0);
++	__rpc_init_priority_wait_queue(queue, qname, 1);
+ }
+-EXPORT_SYMBOL(rpc_init_wait_queue);
++EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
+ 
+-static int rpc_wait_bit_interruptible(void *word)
++static int rpc_wait_bit_killable(void *word)
+ {
+-	if (signal_pending(current))
++	if (fatal_signal_pending(current))
+ 		return -ERESTARTSYS;
+ 	schedule();
+ 	return 0;
+@@ -299,11 +299,11 @@ static void rpc_mark_complete_task(struct rpc_task *task)
+ int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
+ {
+ 	if (action == NULL)
+-		action = rpc_wait_bit_interruptible;
++		action = rpc_wait_bit_killable;
+ 	return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
+-			action, TASK_INTERRUPTIBLE);
++			action, TASK_KILLABLE);
+ }
+-EXPORT_SYMBOL(__rpc_wait_for_completion_task);
++EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
+ 
+ /*
+  * Make an RPC task runnable.
+@@ -373,6 +373,7 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
+ 	__rpc_sleep_on(q, task, action, timer);
+ 	spin_unlock_bh(&q->lock);
+ }
++EXPORT_SYMBOL_GPL(rpc_sleep_on);
+ 
+ /**
+  * __rpc_do_wake_up_task - wake up a single rpc_task
+@@ -444,6 +445,7 @@ void rpc_wake_up_task(struct rpc_task *task)
+ 	}
+ 	rcu_read_unlock_bh();
+ }
++EXPORT_SYMBOL_GPL(rpc_wake_up_task);
+ 
+ /*
+  * Wake up the next task on a priority queue.
+@@ -454,12 +456,12 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
+ 	struct rpc_task *task;
+ 
+ 	/*
+-	 * Service a batch of tasks from a single cookie.
++	 * Service a batch of tasks from a single owner.
+ 	 */
+ 	q = &queue->tasks[queue->priority];
+ 	if (!list_empty(q)) {
+ 		task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
+-		if (queue->cookie == task->tk_cookie) {
++		if (queue->owner == task->tk_owner) {
+ 			if (--queue->nr)
+ 				goto out;
+ 			list_move_tail(&task->u.tk_wait.list, q);
+@@ -468,7 +470,7 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
+ 		 * Check if we need to switch queues.
+ 		 */
+ 		if (--queue->count)
+-			goto new_cookie;
++			goto new_owner;
+ 	}
+ 
+ 	/*
+@@ -490,8 +492,8 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
+ 
+ new_queue:
+ 	rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
+-new_cookie:
+-	rpc_set_waitqueue_cookie(queue, task->tk_cookie);
++new_owner:
++	rpc_set_waitqueue_owner(queue, task->tk_owner);
+ out:
+ 	__rpc_wake_up_task(task);
+ 	return task;
+@@ -519,6 +521,7 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
+ 
+ 	return task;
+ }
++EXPORT_SYMBOL_GPL(rpc_wake_up_next);
+ 
+ /**
+  * rpc_wake_up - wake up all rpc_tasks
+@@ -544,6 +547,7 @@ void rpc_wake_up(struct rpc_wait_queue *queue)
+ 	spin_unlock(&queue->lock);
+ 	rcu_read_unlock_bh();
+ }
++EXPORT_SYMBOL_GPL(rpc_wake_up);
+ 
+ /**
+  * rpc_wake_up_status - wake up all rpc_tasks and set their status value.
+@@ -572,6 +576,7 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
+ 	spin_unlock(&queue->lock);
+ 	rcu_read_unlock_bh();
+ }
++EXPORT_SYMBOL_GPL(rpc_wake_up_status);
+ 
+ static void __rpc_atrun(struct rpc_task *task)
+ {
+@@ -586,6 +591,7 @@ void rpc_delay(struct rpc_task *task, unsigned long delay)
+ 	task->tk_timeout = delay;
+ 	rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun);
+ }
++EXPORT_SYMBOL_GPL(rpc_delay);
+ 
+ /*
+  * Helper to call task->tk_ops->rpc_call_prepare
+@@ -614,7 +620,7 @@ void rpc_exit_task(struct rpc_task *task)
+ 		}
+ 	}
+ }
+-EXPORT_SYMBOL(rpc_exit_task);
++EXPORT_SYMBOL_GPL(rpc_exit_task);
+ 
+ void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
+ {
+@@ -690,10 +696,9 @@ static void __rpc_execute(struct rpc_task *task)
+ 
+ 		/* sync task: sleep here */
+ 		dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid);
+-		/* Note: Caller should be using rpc_clnt_sigmask() */
+ 		status = out_of_line_wait_on_bit(&task->tk_runstate,
+-				RPC_TASK_QUEUED, rpc_wait_bit_interruptible,
+-				TASK_INTERRUPTIBLE);
++				RPC_TASK_QUEUED, rpc_wait_bit_killable,
++				TASK_KILLABLE);
+ 		if (status == -ERESTARTSYS) {
+ 			/*
+ 			 * When a sync task receives a signal, it exits with
+@@ -808,40 +813,47 @@ EXPORT_SYMBOL_GPL(rpc_free);
+ /*
+  * Creation and deletion of RPC task structures
+  */
+-void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
++static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data)
+ {
+ 	memset(task, 0, sizeof(*task));
+-	init_timer(&task->tk_timer);
+-	task->tk_timer.data     = (unsigned long) task;
+-	task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer;
++	setup_timer(&task->tk_timer, (void (*)(unsigned long))rpc_run_timer,
++			(unsigned long)task);
+ 	atomic_set(&task->tk_count, 1);
+-	task->tk_client = clnt;
+-	task->tk_flags  = flags;
+-	task->tk_ops = tk_ops;
+-	if (tk_ops->rpc_call_prepare != NULL)
+-		task->tk_action = rpc_prepare_task;
+-	task->tk_calldata = calldata;
++	task->tk_flags  = task_setup_data->flags;
++	task->tk_ops = task_setup_data->callback_ops;
++	task->tk_calldata = task_setup_data->callback_data;
+ 	INIT_LIST_HEAD(&task->tk_task);
+ 
+ 	/* Initialize retry counters */
+ 	task->tk_garb_retry = 2;
+ 	task->tk_cred_retry = 2;
+ 
+-	task->tk_priority = RPC_PRIORITY_NORMAL;
+-	task->tk_cookie = (unsigned long)current;
++	task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW;
++	task->tk_owner = current->tgid;
+ 
+ 	/* Initialize workqueue for async tasks */
+ 	task->tk_workqueue = rpciod_workqueue;
+ 
+-	if (clnt) {
+-		kref_get(&clnt->cl_kref);
+-		if (clnt->cl_softrtry)
++	task->tk_client = task_setup_data->rpc_client;
++	if (task->tk_client != NULL) {
++		kref_get(&task->tk_client->cl_kref);
++		if (task->tk_client->cl_softrtry)
+ 			task->tk_flags |= RPC_TASK_SOFT;
+-		if (!clnt->cl_intr)
+-			task->tk_flags |= RPC_TASK_NOINTR;
+ 	}
+ 
+-	BUG_ON(task->tk_ops == NULL);
++	if (task->tk_ops->rpc_call_prepare != NULL)
++		task->tk_action = rpc_prepare_task;
++
++	if (task_setup_data->rpc_message != NULL) {
++		memcpy(&task->tk_msg, task_setup_data->rpc_message, sizeof(task->tk_msg));
++		/* Bind the user cred */
++		if (task->tk_msg.rpc_cred != NULL)
++			rpcauth_holdcred(task);
++		else
++			rpcauth_bindcred(task);
++		if (task->tk_action == NULL)
++			rpc_call_start(task);
++	}
+ 
+ 	/* starting timestamp */
+ 	task->tk_start = jiffies;
+@@ -866,18 +878,22 @@ static void rpc_free_task(struct rcu_head *rcu)
+ /*
+  * Create a new task for the specified client.
+  */
+-struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
++struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
+ {
+-	struct rpc_task	*task;
+-
+-	task = rpc_alloc_task();
+-	if (!task)
+-		goto out;
++	struct rpc_task	*task = setup_data->task;
++	unsigned short flags = 0;
++
++	if (task == NULL) {
++		task = rpc_alloc_task();
++		if (task == NULL)
++			goto out;
++		flags = RPC_TASK_DYNAMIC;
++	}
+ 
+-	rpc_init_task(task, clnt, flags, tk_ops, calldata);
++	rpc_init_task(task, setup_data);
+ 
++	task->tk_flags |= flags;
+ 	dprintk("RPC:       allocated task %p\n", task);
+-	task->tk_flags |= RPC_TASK_DYNAMIC;
+ out:
+ 	return task;
+ }
+@@ -903,7 +919,7 @@ void rpc_put_task(struct rpc_task *task)
+ 		call_rcu_bh(&task->u.tk_rcu, rpc_free_task);
+ 	rpc_release_calldata(tk_ops, calldata);
+ }
+-EXPORT_SYMBOL(rpc_put_task);
++EXPORT_SYMBOL_GPL(rpc_put_task);
+ 
+ static void rpc_release_task(struct rpc_task *task)
+ {
+@@ -960,6 +976,7 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
+ 	}
+ 	spin_unlock(&clnt->cl_lock);
+ }
++EXPORT_SYMBOL_GPL(rpc_killall_tasks);
+ 
+ int rpciod_up(void)
+ {
+@@ -1039,6 +1056,11 @@ rpc_init_mempool(void)
+ 		goto err_nomem;
+ 	if (!rpciod_start())
+ 		goto err_nomem;
++	/*
++	 * The following is not strictly a mempool initialisation,
++	 * but there is no harm in doing it here
++	 */
++	rpc_init_wait_queue(&delay_queue, "delayq");
+ 	return 0;
+ err_nomem:
+ 	rpc_destroy_mempool();
+diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
+index 97ac45f..a661a3a 100644
+--- a/net/sunrpc/socklib.c
++++ b/net/sunrpc/socklib.c
+@@ -72,7 +72,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct
+ 	struct page	**ppage = xdr->pages;
+ 	unsigned int	len, pglen = xdr->page_len;
+ 	ssize_t		copied = 0;
+-	int		ret;
++	size_t		ret;
+ 
+ 	len = xdr->head[0].iov_len;
+ 	if (base < len) {
+diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
+index 4d4f373..5a16875 100644
+--- a/net/sunrpc/stats.c
++++ b/net/sunrpc/stats.c
+@@ -33,7 +33,7 @@ struct proc_dir_entry	*proc_net_rpc = NULL;
+ static int rpc_proc_show(struct seq_file *seq, void *v) {
+ 	const struct rpc_stat	*statp = seq->private;
+ 	const struct rpc_program *prog = statp->program;
+-	int		i, j;
++	unsigned int i, j;
+ 
+ 	seq_printf(seq,
+ 		"net %u %u %u %u\n",
+@@ -81,7 +81,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
+ 	const struct svc_program *prog = statp->program;
+ 	const struct svc_procedure *proc;
+ 	const struct svc_version *vers;
+-	int		i, j;
++	unsigned int i, j;
+ 
+ 	seq_printf(seq,
+ 		"net %u %u %u %u\n",
+@@ -106,6 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
+ 		seq_putc(seq, '\n');
+ 	}
+ }
++EXPORT_SYMBOL(svc_seq_show);
+ 
+ /**
+  * rpc_alloc_iostats - allocate an rpc_iostats structure
+@@ -118,7 +119,7 @@ struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
+ 	new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
+ 	return new;
+ }
+-EXPORT_SYMBOL(rpc_alloc_iostats);
++EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
+ 
+ /**
+  * rpc_free_iostats - release an rpc_iostats structure
+@@ -129,7 +130,7 @@ void rpc_free_iostats(struct rpc_iostats *stats)
+ {
+ 	kfree(stats);
+ }
+-EXPORT_SYMBOL(rpc_free_iostats);
++EXPORT_SYMBOL_GPL(rpc_free_iostats);
+ 
+ /**
+  * rpc_count_iostats - tally up per-task stats
+@@ -215,7 +216,7 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
+ 				metrics->om_execute * MILLISECS_PER_JIFFY);
+ 	}
+ }
+-EXPORT_SYMBOL(rpc_print_iostats);
++EXPORT_SYMBOL_GPL(rpc_print_iostats);
+ 
+ /*
+  * Register/unregister RPC proc files
+@@ -241,24 +242,28 @@ rpc_proc_register(struct rpc_stat *statp)
+ {
+ 	return do_register(statp->program->name, statp, &rpc_proc_fops);
+ }
++EXPORT_SYMBOL_GPL(rpc_proc_register);
+ 
+ void
+ rpc_proc_unregister(const char *name)
+ {
+ 	remove_proc_entry(name, proc_net_rpc);
+ }
++EXPORT_SYMBOL_GPL(rpc_proc_unregister);
+ 
+ struct proc_dir_entry *
+ svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
+ {
+ 	return do_register(statp->program->pg_name, statp, fops);
+ }
++EXPORT_SYMBOL(svc_proc_register);
+ 
+ void
+ svc_proc_unregister(const char *name)
+ {
+ 	remove_proc_entry(name, proc_net_rpc);
+ }
++EXPORT_SYMBOL(svc_proc_unregister);
+ 
+ void
+ rpc_proc_init(void)
+diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
+index 33d89e8..843629f 100644
+--- a/net/sunrpc/sunrpc_syms.c
++++ b/net/sunrpc/sunrpc_syms.c
+@@ -22,114 +22,6 @@
+ #include <linux/sunrpc/rpc_pipe_fs.h>
+ #include <linux/sunrpc/xprtsock.h>
+ 
+-/* RPC scheduler */
+-EXPORT_SYMBOL(rpc_execute);
+-EXPORT_SYMBOL(rpc_init_task);
+-EXPORT_SYMBOL(rpc_sleep_on);
+-EXPORT_SYMBOL(rpc_wake_up_next);
+-EXPORT_SYMBOL(rpc_wake_up_task);
+-EXPORT_SYMBOL(rpc_wake_up_status);
+-
+-/* RPC client functions */
+-EXPORT_SYMBOL(rpc_clone_client);
+-EXPORT_SYMBOL(rpc_bind_new_program);
+-EXPORT_SYMBOL(rpc_shutdown_client);
+-EXPORT_SYMBOL(rpc_killall_tasks);
+-EXPORT_SYMBOL(rpc_call_sync);
+-EXPORT_SYMBOL(rpc_call_async);
+-EXPORT_SYMBOL(rpc_call_setup);
+-EXPORT_SYMBOL(rpc_clnt_sigmask);
+-EXPORT_SYMBOL(rpc_clnt_sigunmask);
+-EXPORT_SYMBOL(rpc_delay);
+-EXPORT_SYMBOL(rpc_restart_call);
+-EXPORT_SYMBOL(rpc_setbufsize);
+-EXPORT_SYMBOL(rpc_unlink);
+-EXPORT_SYMBOL(rpc_wake_up);
+-EXPORT_SYMBOL(rpc_queue_upcall);
+-EXPORT_SYMBOL(rpc_mkpipe);
+-
+-/* Client transport */
+-EXPORT_SYMBOL(xprt_set_timeout);
+-
+-/* Client credential cache */
+-EXPORT_SYMBOL(rpcauth_register);
+-EXPORT_SYMBOL(rpcauth_unregister);
+-EXPORT_SYMBOL(rpcauth_create);
+-EXPORT_SYMBOL(rpcauth_lookupcred);
+-EXPORT_SYMBOL(rpcauth_lookup_credcache);
+-EXPORT_SYMBOL(rpcauth_destroy_credcache);
+-EXPORT_SYMBOL(rpcauth_init_credcache);
+-EXPORT_SYMBOL(put_rpccred);
+-
+-/* RPC server stuff */
+-EXPORT_SYMBOL(svc_create);
+-EXPORT_SYMBOL(svc_create_thread);
+-EXPORT_SYMBOL(svc_create_pooled);
+-EXPORT_SYMBOL(svc_set_num_threads);
+-EXPORT_SYMBOL(svc_exit_thread);
+-EXPORT_SYMBOL(svc_destroy);
+-EXPORT_SYMBOL(svc_drop);
+-EXPORT_SYMBOL(svc_process);
+-EXPORT_SYMBOL(svc_recv);
+-EXPORT_SYMBOL(svc_wake_up);
+-EXPORT_SYMBOL(svc_makesock);
+-EXPORT_SYMBOL(svc_reserve);
+-EXPORT_SYMBOL(svc_auth_register);
+-EXPORT_SYMBOL(auth_domain_lookup);
+-EXPORT_SYMBOL(svc_authenticate);
+-EXPORT_SYMBOL(svc_set_client);
+-
+-/* RPC statistics */
+-#ifdef CONFIG_PROC_FS
+-EXPORT_SYMBOL(rpc_proc_register);
+-EXPORT_SYMBOL(rpc_proc_unregister);
+-EXPORT_SYMBOL(svc_proc_register);
+-EXPORT_SYMBOL(svc_proc_unregister);
+-EXPORT_SYMBOL(svc_seq_show);
+-#endif
+-
+-/* caching... */
+-EXPORT_SYMBOL(auth_domain_find);
+-EXPORT_SYMBOL(auth_domain_put);
+-EXPORT_SYMBOL(auth_unix_add_addr);
+-EXPORT_SYMBOL(auth_unix_forget_old);
+-EXPORT_SYMBOL(auth_unix_lookup);
+-EXPORT_SYMBOL(cache_check);
+-EXPORT_SYMBOL(cache_flush);
+-EXPORT_SYMBOL(cache_purge);
+-EXPORT_SYMBOL(cache_register);
+-EXPORT_SYMBOL(cache_unregister);
+-EXPORT_SYMBOL(qword_add);
+-EXPORT_SYMBOL(qword_addhex);
+-EXPORT_SYMBOL(qword_get);
+-EXPORT_SYMBOL(svcauth_unix_purge);
+-EXPORT_SYMBOL(unix_domain_find);
+-
+-/* Generic XDR */
+-EXPORT_SYMBOL(xdr_encode_string);
+-EXPORT_SYMBOL(xdr_decode_string_inplace);
+-EXPORT_SYMBOL(xdr_decode_netobj);
+-EXPORT_SYMBOL(xdr_encode_netobj);
+-EXPORT_SYMBOL(xdr_encode_pages);
+-EXPORT_SYMBOL(xdr_inline_pages);
+-EXPORT_SYMBOL(xdr_shift_buf);
+-EXPORT_SYMBOL(xdr_encode_word);
+-EXPORT_SYMBOL(xdr_decode_word);
+-EXPORT_SYMBOL(xdr_encode_array2);
+-EXPORT_SYMBOL(xdr_decode_array2);
+-EXPORT_SYMBOL(xdr_buf_from_iov);
+-EXPORT_SYMBOL(xdr_buf_subsegment);
+-EXPORT_SYMBOL(xdr_buf_read_netobj);
+-EXPORT_SYMBOL(read_bytes_from_xdr_buf);
+-
+-/* Debugging symbols */
+-#ifdef RPC_DEBUG
+-EXPORT_SYMBOL(rpc_debug);
+-EXPORT_SYMBOL(nfs_debug);
+-EXPORT_SYMBOL(nfsd_debug);
+-EXPORT_SYMBOL(nlm_debug);
+-#endif
+-
+ extern struct cache_detail ip_map_cache, unix_gid_cache;
+ 
+ static int __init
+@@ -151,7 +43,8 @@ init_sunrpc(void)
+ #endif
+ 	cache_register(&ip_map_cache);
+ 	cache_register(&unix_gid_cache);
+-	init_socket_xprt();
++	svc_init_xprt_sock();	/* svc sock transport */
++	init_socket_xprt();	/* clnt sock transport */
+ 	rpcauth_init_module();
+ out:
+ 	return err;
+@@ -162,12 +55,11 @@ cleanup_sunrpc(void)
+ {
+ 	rpcauth_remove_module();
+ 	cleanup_socket_xprt();
++	svc_cleanup_xprt_sock();
+ 	unregister_rpc_pipefs();
+ 	rpc_destroy_mempool();
+-	if (cache_unregister(&ip_map_cache))
+-		printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
+-	if (cache_unregister(&unix_gid_cache))
+-	      printk(KERN_ERR "sunrpc: failed to unregister unix_gid cache\n");
++	cache_unregister(&ip_map_cache);
++	cache_unregister(&unix_gid_cache);
+ #ifdef RPC_DEBUG
+ 	rpc_unregister_sysctl();
+ #endif
+diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
+index a4a6bf7..a290e15 100644
+--- a/net/sunrpc/svc.c
++++ b/net/sunrpc/svc.c
+@@ -18,6 +18,7 @@
+ #include <linux/mm.h>
+ #include <linux/interrupt.h>
+ #include <linux/module.h>
++#include <linux/sched.h>
+ 
+ #include <linux/sunrpc/types.h>
+ #include <linux/sunrpc/xdr.h>
+@@ -363,7 +364,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
+ 	   void (*shutdown)(struct svc_serv *serv))
+ {
+ 	struct svc_serv	*serv;
+-	int vers;
++	unsigned int vers;
+ 	unsigned int xdrsize;
+ 	unsigned int i;
+ 
+@@ -432,6 +433,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
+ {
+ 	return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+ }
++EXPORT_SYMBOL(svc_create);
+ 
+ struct svc_serv *
+ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
+@@ -451,6 +453,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
+ 
+ 	return serv;
+ }
++EXPORT_SYMBOL(svc_create_pooled);
+ 
+ /*
+  * Destroy an RPC service.  Should be called with the BKL held
+@@ -458,9 +461,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
+ void
+ svc_destroy(struct svc_serv *serv)
+ {
+-	struct svc_sock	*svsk;
+-	struct svc_sock *tmp;
+-
+ 	dprintk("svc: svc_destroy(%s, %d)\n",
+ 				serv->sv_program->pg_name,
+ 				serv->sv_nrthreads);
+@@ -475,14 +475,12 @@ svc_destroy(struct svc_serv *serv)
+ 
+ 	del_timer_sync(&serv->sv_temptimer);
+ 
+-	list_for_each_entry_safe(svsk, tmp, &serv->sv_tempsocks, sk_list)
+-		svc_force_close_socket(svsk);
++	svc_close_all(&serv->sv_tempsocks);
+ 
+ 	if (serv->sv_shutdown)
+ 		serv->sv_shutdown(serv);
+ 
+-	list_for_each_entry_safe(svsk, tmp, &serv->sv_permsocks, sk_list)
+-		svc_force_close_socket(svsk);
++	svc_close_all(&serv->sv_permsocks);
+ 
+ 	BUG_ON(!list_empty(&serv->sv_permsocks));
+ 	BUG_ON(!list_empty(&serv->sv_tempsocks));
+@@ -497,6 +495,7 @@ svc_destroy(struct svc_serv *serv)
+ 	kfree(serv->sv_pools);
+ 	kfree(serv);
+ }
++EXPORT_SYMBOL(svc_destroy);
+ 
+ /*
+  * Allocate an RPC server's buffer space.
+@@ -535,31 +534,17 @@ svc_release_buffer(struct svc_rqst *rqstp)
+ 			put_page(rqstp->rq_pages[i]);
+ }
+ 
+-/*
+- * Create a thread in the given pool.  Caller must hold BKL.
+- * On a NUMA or SMP machine, with a multi-pool serv, the thread
+- * will be restricted to run on the cpus belonging to the pool.
+- */
+-static int
+-__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
+-		    struct svc_pool *pool)
++struct svc_rqst *
++svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
+ {
+ 	struct svc_rqst	*rqstp;
+-	int		error = -ENOMEM;
+-	int		have_oldmask = 0;
+-	cpumask_t	oldmask;
+ 
+ 	rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
+ 	if (!rqstp)
+-		goto out;
++		goto out_enomem;
+ 
+ 	init_waitqueue_head(&rqstp->rq_wait);
+ 
+-	if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
+-	 || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
+-	 || !svc_init_buffer(rqstp, serv->sv_max_mesg))
+-		goto out_thread;
+-
+ 	serv->sv_nrthreads++;
+ 	spin_lock_bh(&pool->sp_lock);
+ 	pool->sp_nrthreads++;
+@@ -568,6 +553,45 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
+ 	rqstp->rq_server = serv;
+ 	rqstp->rq_pool = pool;
+ 
++	rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
++	if (!rqstp->rq_argp)
++		goto out_thread;
++
++	rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
++	if (!rqstp->rq_resp)
++		goto out_thread;
++
++	if (!svc_init_buffer(rqstp, serv->sv_max_mesg))
++		goto out_thread;
++
++	return rqstp;
++out_thread:
++	svc_exit_thread(rqstp);
++out_enomem:
++	return ERR_PTR(-ENOMEM);
++}
++EXPORT_SYMBOL(svc_prepare_thread);
++
++/*
++ * Create a thread in the given pool.  Caller must hold BKL.
++ * On a NUMA or SMP machine, with a multi-pool serv, the thread
++ * will be restricted to run on the cpus belonging to the pool.
++ */
++static int
++__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
++		    struct svc_pool *pool)
++{
++	struct svc_rqst	*rqstp;
++	int		error = -ENOMEM;
++	int		have_oldmask = 0;
++	cpumask_t	oldmask;
++
++	rqstp = svc_prepare_thread(serv, pool);
++	if (IS_ERR(rqstp)) {
++		error = PTR_ERR(rqstp);
++		goto out;
++	}
++
+ 	if (serv->sv_nrpools > 1)
+ 		have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
+ 
+@@ -596,6 +620,7 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
+ {
+ 	return __svc_create_thread(func, serv, &serv->sv_pools[0]);
+ }
++EXPORT_SYMBOL(svc_create_thread);
+ 
+ /*
+  * Choose a pool in which to create a new thread, for svc_set_num_threads
+@@ -699,6 +724,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+ 
+ 	return error;
+ }
++EXPORT_SYMBOL(svc_set_num_threads);
+ 
+ /*
+  * Called from a server thread as it's exiting.  Caller must hold BKL.
+@@ -725,6 +751,7 @@ svc_exit_thread(struct svc_rqst *rqstp)
+ 	if (serv)
+ 		svc_destroy(serv);
+ }
++EXPORT_SYMBOL(svc_exit_thread);
+ 
+ /*
+  * Register an RPC service with the local portmapper.
+@@ -736,7 +763,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
+ {
+ 	struct svc_program	*progp;
+ 	unsigned long		flags;
+-	int			i, error = 0, dummy;
++	unsigned int		i;
++	int			error = 0, dummy;
+ 
+ 	if (!port)
+ 		clear_thread_flag(TIF_SIGPENDING);
+@@ -839,9 +867,9 @@ svc_process(struct svc_rqst *rqstp)
+ 	rqstp->rq_res.tail[0].iov_len = 0;
+ 	/* Will be turned off only in gss privacy case: */
+ 	rqstp->rq_splice_ok = 1;
+-	/* tcp needs a space for the record length... */
+-	if (rqstp->rq_prot == IPPROTO_TCP)
+-		svc_putnl(resv, 0);
++
++	/* Setup reply header */
++	rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
+ 
+ 	rqstp->rq_xid = svc_getu32(argv);
+ 	svc_putu32(resv, rqstp->rq_xid);
+@@ -1048,16 +1076,15 @@ err_bad:
+ 	svc_putnl(resv, ntohl(rpc_stat));
+ 	goto sendit;
+ }
++EXPORT_SYMBOL(svc_process);
+ 
+ /*
+  * Return (transport-specific) limit on the rpc payload.
+  */
+ u32 svc_max_payload(const struct svc_rqst *rqstp)
+ {
+-	int max = RPCSVC_MAXPAYLOAD_TCP;
++	u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
+ 
+-	if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
+-		max = RPCSVC_MAXPAYLOAD_UDP;
+ 	if (rqstp->rq_server->sv_max_payload < max)
+ 		max = rqstp->rq_server->sv_max_payload;
+ 	return max;
+diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
+new file mode 100644
+index 0000000..ea377e0
+--- /dev/null
++++ b/net/sunrpc/svc_xprt.c
+@@ -0,0 +1,1055 @@
++/*
++ * linux/net/sunrpc/svc_xprt.c
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/fcntl.h>
++#include <linux/net.h>
++#include <linux/in.h>
++#include <linux/inet.h>
++#include <linux/udp.h>
++#include <linux/tcp.h>
++#include <linux/unistd.h>
++#include <linux/slab.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <linux/freezer.h>
++#include <net/sock.h>
++#include <net/checksum.h>
++#include <net/ip.h>
++#include <net/ipv6.h>
++#include <net/tcp_states.h>
++#include <linux/uaccess.h>
++#include <asm/ioctls.h>
++
++#include <linux/sunrpc/types.h>
++#include <linux/sunrpc/clnt.h>
++#include <linux/sunrpc/xdr.h>
++#include <linux/sunrpc/stats.h>
++#include <linux/sunrpc/svc_xprt.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
++static int svc_deferred_recv(struct svc_rqst *rqstp);
++static struct cache_deferred_req *svc_defer(struct cache_req *req);
++static void svc_age_temp_xprts(unsigned long closure);
++
++/* apparently the "standard" is that clients close
++ * idle connections after 5 minutes, servers after
++ * 6 minutes
++ *   http://www.connectathon.org/talks96/nfstcp.pdf
++ */
++static int svc_conn_age_period = 6*60;
++
++/* List of registered transport classes */
++static DEFINE_SPINLOCK(svc_xprt_class_lock);
++static LIST_HEAD(svc_xprt_class_list);
++
++/* SMP locking strategy:
++ *
++ *	svc_pool->sp_lock protects most of the fields of that pool.
++ *	svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
++ *	when both need to be taken (rare), svc_serv->sv_lock is first.
++ *	BKL protects svc_serv->sv_nrthread.
++ *	svc_sock->sk_lock protects the svc_sock->sk_deferred list
++ *             and the ->sk_info_authunix cache.
++ *
++ *	The XPT_BUSY bit in xprt->xpt_flags prevents a transport being
++ *	enqueued multiply. During normal transport processing this bit
++ *	is set by svc_xprt_enqueue and cleared by svc_xprt_received.
++ *	Providers should not manipulate this bit directly.
++ *
++ *	Some flags can be set to certain values at any time
++ *	providing that certain rules are followed:
++ *
++ *	XPT_CONN, XPT_DATA:
++ *		- Can be set or cleared at any time.
++ *		- After a set, svc_xprt_enqueue must be called to enqueue
++ *		  the transport for processing.
++ *		- After a clear, the transport must be read/accepted.
++ *		  If this succeeds, it must be set again.
++ *	XPT_CLOSE:
++ *		- Can set at any time. It is never cleared.
++ *      XPT_DEAD:
++ *		- Can only be set while XPT_BUSY is held which ensures
++ *		  that no other thread will be using the transport or will
++ *		  try to set XPT_DEAD.
++ */
++
++int svc_reg_xprt_class(struct svc_xprt_class *xcl)
++{
++	struct svc_xprt_class *cl;
++	int res = -EEXIST;
++
++	dprintk("svc: Adding svc transport class '%s'\n", xcl->xcl_name);
++
++	INIT_LIST_HEAD(&xcl->xcl_list);
++	spin_lock(&svc_xprt_class_lock);
++	/* Make sure there isn't already a class with the same name */
++	list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
++		if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
++			goto out;
++	}
++	list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
++	res = 0;
++out:
++	spin_unlock(&svc_xprt_class_lock);
++	return res;
++}
++EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
++
++void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
++{
++	dprintk("svc: Removing svc transport class '%s'\n", xcl->xcl_name);
++	spin_lock(&svc_xprt_class_lock);
++	list_del_init(&xcl->xcl_list);
++	spin_unlock(&svc_xprt_class_lock);
++}
++EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
++
++/*
++ * Format the transport list for printing
++ */
++int svc_print_xprts(char *buf, int maxlen)
++{
++	struct list_head *le;
++	char tmpstr[80];
++	int len = 0;
++	buf[0] = '\0';
++
++	spin_lock(&svc_xprt_class_lock);
++	list_for_each(le, &svc_xprt_class_list) {
++		int slen;
++		struct svc_xprt_class *xcl =
++			list_entry(le, struct svc_xprt_class, xcl_list);
++
++		sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
++		slen = strlen(tmpstr);
++		if (len + slen > maxlen)
++			break;
++		len += slen;
++		strcat(buf, tmpstr);
++	}
++	spin_unlock(&svc_xprt_class_lock);
++
++	return len;
++}
++
++static void svc_xprt_free(struct kref *kref)
++{
++	struct svc_xprt *xprt =
++		container_of(kref, struct svc_xprt, xpt_ref);
++	struct module *owner = xprt->xpt_class->xcl_owner;
++	if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)
++	    && xprt->xpt_auth_cache != NULL)
++		svcauth_unix_info_release(xprt->xpt_auth_cache);
++	xprt->xpt_ops->xpo_free(xprt);
++	module_put(owner);
++}
++
++void svc_xprt_put(struct svc_xprt *xprt)
++{
++	kref_put(&xprt->xpt_ref, svc_xprt_free);
++}
++EXPORT_SYMBOL_GPL(svc_xprt_put);
++
++/*
++ * Called by transport drivers to initialize the transport independent
++ * portion of the transport instance.
++ */
++void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
++		   struct svc_serv *serv)
++{
++	memset(xprt, 0, sizeof(*xprt));
++	xprt->xpt_class = xcl;
++	xprt->xpt_ops = xcl->xcl_ops;
++	kref_init(&xprt->xpt_ref);
++	xprt->xpt_server = serv;
++	INIT_LIST_HEAD(&xprt->xpt_list);
++	INIT_LIST_HEAD(&xprt->xpt_ready);
++	INIT_LIST_HEAD(&xprt->xpt_deferred);
++	mutex_init(&xprt->xpt_mutex);
++	spin_lock_init(&xprt->xpt_lock);
++	set_bit(XPT_BUSY, &xprt->xpt_flags);
++}
++EXPORT_SYMBOL_GPL(svc_xprt_init);
++
++int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
++		    int flags)
++{
++	struct svc_xprt_class *xcl;
++	struct sockaddr_in sin = {
++		.sin_family		= AF_INET,
++		.sin_addr.s_addr	= INADDR_ANY,
++		.sin_port		= htons(port),
++	};
++	dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
++	spin_lock(&svc_xprt_class_lock);
++	list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
++		struct svc_xprt *newxprt;
++
++		if (strcmp(xprt_name, xcl->xcl_name))
++			continue;
++
++		if (!try_module_get(xcl->xcl_owner))
++			goto err;
++
++		spin_unlock(&svc_xprt_class_lock);
++		newxprt = xcl->xcl_ops->
++			xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
++				   flags);
++		if (IS_ERR(newxprt)) {
++			module_put(xcl->xcl_owner);
++			return PTR_ERR(newxprt);
++		}
++
++		clear_bit(XPT_TEMP, &newxprt->xpt_flags);
++		spin_lock_bh(&serv->sv_lock);
++		list_add(&newxprt->xpt_list, &serv->sv_permsocks);
++		spin_unlock_bh(&serv->sv_lock);
++		clear_bit(XPT_BUSY, &newxprt->xpt_flags);
++		return svc_xprt_local_port(newxprt);
++	}
++ err:
++	spin_unlock(&svc_xprt_class_lock);
++	dprintk("svc: transport %s not found\n", xprt_name);
++	return -ENOENT;
++}
++EXPORT_SYMBOL_GPL(svc_create_xprt);
++
++/*
++ * Copy the local and remote xprt addresses to the rqstp structure
++ */
++void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
++{
++	struct sockaddr *sin;
++
++	memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
++	rqstp->rq_addrlen = xprt->xpt_remotelen;
++
++	/*
++	 * Destination address in request is needed for binding the
++	 * source address in RPC replies/callbacks later.
++	 */
++	sin = (struct sockaddr *)&xprt->xpt_local;
++	switch (sin->sa_family) {
++	case AF_INET:
++		rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
++		break;
++	case AF_INET6:
++		rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
++		break;
++	}
++}
++EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
++
++/**
++ * svc_print_addr - Format rq_addr field for printing
++ * @rqstp: svc_rqst struct containing address to print
++ * @buf: target buffer for formatted address
++ * @len: length of target buffer
++ *
++ */
++char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
++{
++	return __svc_print_addr(svc_addr(rqstp), buf, len);
++}
++EXPORT_SYMBOL_GPL(svc_print_addr);
++
++/*
++ * Queue up an idle server thread.  Must have pool->sp_lock held.
++ * Note: this is really a stack rather than a queue, so that we only
++ * use as many different threads as we need, and the rest don't pollute
++ * the cache.
++ */
++static void svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
++{
++	list_add(&rqstp->rq_list, &pool->sp_threads);
++}
++
++/*
++ * Dequeue an nfsd thread.  Must have pool->sp_lock held.
++ */
++static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
++{
++	list_del(&rqstp->rq_list);
++}
++
++/*
++ * Queue up a transport with data pending. If there are idle nfsd
++ * processes, wake 'em up.
++ *
++ */
++void svc_xprt_enqueue(struct svc_xprt *xprt)
++{
++	struct svc_serv	*serv = xprt->xpt_server;
++	struct svc_pool *pool;
++	struct svc_rqst	*rqstp;
++	int cpu;
++
++	if (!(xprt->xpt_flags &
++	      ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
++		return;
++	if (test_bit(XPT_DEAD, &xprt->xpt_flags))
++		return;
++
++	cpu = get_cpu();
++	pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
++	put_cpu();
++
++	spin_lock_bh(&pool->sp_lock);
++
++	if (!list_empty(&pool->sp_threads) &&
++	    !list_empty(&pool->sp_sockets))
++		printk(KERN_ERR
++		       "svc_xprt_enqueue: "
++		       "threads and transports both waiting??\n");
++
++	if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
++		/* Don't enqueue dead transports */
++		dprintk("svc: transport %p is dead, not enqueued\n", xprt);
++		goto out_unlock;
++	}
++
++	/* Mark transport as busy. It will remain in this state until
++	 * the provider calls svc_xprt_received. We update XPT_BUSY
++	 * atomically because it also guards against trying to enqueue
++	 * the transport twice.
++	 */
++	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) {
++		/* Don't enqueue transport while already enqueued */
++		dprintk("svc: transport %p busy, not enqueued\n", xprt);
++		goto out_unlock;
++	}
++	BUG_ON(xprt->xpt_pool != NULL);
++	xprt->xpt_pool = pool;
++
++	/* Handle pending connection */
++	if (test_bit(XPT_CONN, &xprt->xpt_flags))
++		goto process;
++
++	/* Handle close in-progress */
++	if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
++		goto process;
++
++	/* Check if we have space to reply to a request */
++	if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
++		/* Don't enqueue while not enough space for reply */
++		dprintk("svc: no write space, transport %p  not enqueued\n",
++			xprt);
++		xprt->xpt_pool = NULL;
++		clear_bit(XPT_BUSY, &xprt->xpt_flags);
++		goto out_unlock;
++	}
++
++ process:
++	if (!list_empty(&pool->sp_threads)) {
++		rqstp = list_entry(pool->sp_threads.next,
++				   struct svc_rqst,
++				   rq_list);
++		dprintk("svc: transport %p served by daemon %p\n",
++			xprt, rqstp);
++		svc_thread_dequeue(pool, rqstp);
++		if (rqstp->rq_xprt)
++			printk(KERN_ERR
++				"svc_xprt_enqueue: server %p, rq_xprt=%p!\n",
++				rqstp, rqstp->rq_xprt);
++		rqstp->rq_xprt = xprt;
++		svc_xprt_get(xprt);
++		rqstp->rq_reserved = serv->sv_max_mesg;
++		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
++		BUG_ON(xprt->xpt_pool != pool);
++		wake_up(&rqstp->rq_wait);
++	} else {
++		dprintk("svc: transport %p put into queue\n", xprt);
++		list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
++		BUG_ON(xprt->xpt_pool != pool);
++	}
++
++out_unlock:
++	spin_unlock_bh(&pool->sp_lock);
++}
++EXPORT_SYMBOL_GPL(svc_xprt_enqueue);
++
++/*
++ * Dequeue the first transport.  Must be called with the pool->sp_lock held.
++ */
++static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
++{
++	struct svc_xprt	*xprt;
++
++	if (list_empty(&pool->sp_sockets))
++		return NULL;
++
++	xprt = list_entry(pool->sp_sockets.next,
++			  struct svc_xprt, xpt_ready);
++	list_del_init(&xprt->xpt_ready);
++
++	dprintk("svc: transport %p dequeued, inuse=%d\n",
++		xprt, atomic_read(&xprt->xpt_ref.refcount));
++
++	return xprt;
++}
++
++/*
++ * svc_xprt_received conditionally queues the transport for processing
++ * by another thread. The caller must hold the XPT_BUSY bit and must
++ * not thereafter touch transport data.
++ *
++ * Note: XPT_DATA only gets cleared when a read-attempt finds no (or
++ * insufficient) data.
++ */
++void svc_xprt_received(struct svc_xprt *xprt)
++{
++	BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
++	xprt->xpt_pool = NULL;
++	clear_bit(XPT_BUSY, &xprt->xpt_flags);
++	svc_xprt_enqueue(xprt);
++}
++EXPORT_SYMBOL_GPL(svc_xprt_received);
++
++/**
++ * svc_reserve - change the space reserved for the reply to a request.
++ * @rqstp:  The request in question
++ * @space: new max space to reserve
++ *
++ * Each request reserves some space on the output queue of the transport
++ * to make sure the reply fits.  This function reduces that reserved
++ * space to be the amount of space used already, plus @space.
++ *
++ */
++void svc_reserve(struct svc_rqst *rqstp, int space)
++{
++	space += rqstp->rq_res.head[0].iov_len;
++
++	if (space < rqstp->rq_reserved) {
++		struct svc_xprt *xprt = rqstp->rq_xprt;
++		atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
++		rqstp->rq_reserved = space;
++
++		svc_xprt_enqueue(xprt);
++	}
++}
++EXPORT_SYMBOL(svc_reserve);
++
++static void svc_xprt_release(struct svc_rqst *rqstp)
++{
++	struct svc_xprt	*xprt = rqstp->rq_xprt;
++
++	rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
++
++	svc_free_res_pages(rqstp);
++	rqstp->rq_res.page_len = 0;
++	rqstp->rq_res.page_base = 0;
++
++	/* Reset response buffer and release
++	 * the reservation.
++	 * But first, check that enough space was reserved
++	 * for the reply, otherwise we have a bug!
++	 */
++	if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
++		printk(KERN_ERR "RPC request reserved %d but used %d\n",
++		       rqstp->rq_reserved,
++		       rqstp->rq_res.len);
++
++	rqstp->rq_res.head[0].iov_len = 0;
++	svc_reserve(rqstp, 0);
++	rqstp->rq_xprt = NULL;
++
++	svc_xprt_put(xprt);
++}
++
++/*
++ * External function to wake up a server waiting for data
++ * This really only makes sense for services like lockd
++ * which have exactly one thread anyway.
++ */
++void svc_wake_up(struct svc_serv *serv)
++{
++	struct svc_rqst	*rqstp;
++	unsigned int i;
++	struct svc_pool *pool;
++
++	for (i = 0; i < serv->sv_nrpools; i++) {
++		pool = &serv->sv_pools[i];
++
++		spin_lock_bh(&pool->sp_lock);
++		if (!list_empty(&pool->sp_threads)) {
++			rqstp = list_entry(pool->sp_threads.next,
++					   struct svc_rqst,
++					   rq_list);
++			dprintk("svc: daemon %p woken up.\n", rqstp);
++			/*
++			svc_thread_dequeue(pool, rqstp);
++			rqstp->rq_xprt = NULL;
++			 */
++			wake_up(&rqstp->rq_wait);
++		}
++		spin_unlock_bh(&pool->sp_lock);
++	}
++}
++EXPORT_SYMBOL(svc_wake_up);
++
++int svc_port_is_privileged(struct sockaddr *sin)
++{
++	switch (sin->sa_family) {
++	case AF_INET:
++		return ntohs(((struct sockaddr_in *)sin)->sin_port)
++			< PROT_SOCK;
++	case AF_INET6:
++		return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
++			< PROT_SOCK;
++	default:
++		return 0;
++	}
++}
++
++/*
++ * Make sure that we don't have too many active connections.  If we
++ * have, something must be dropped.
++ *
++ * There's no point in trying to do random drop here for DoS
++ * prevention. The NFS clients does 1 reconnect in 15 seconds. An
++ * attacker can easily beat that.
++ *
++ * The only somewhat efficient mechanism would be if drop old
++ * connections from the same IP first. But right now we don't even
++ * record the client IP in svc_sock.
++ */
++static void svc_check_conn_limits(struct svc_serv *serv)
++{
++	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
++		struct svc_xprt *xprt = NULL;
++		spin_lock_bh(&serv->sv_lock);
++		if (!list_empty(&serv->sv_tempsocks)) {
++			if (net_ratelimit()) {
++				/* Try to help the admin */
++				printk(KERN_NOTICE "%s: too many open  "
++				       "connections, consider increasing the "
++				       "number of nfsd threads\n",
++				       serv->sv_name);
++			}
++			/*
++			 * Always select the oldest connection. It's not fair,
++			 * but so is life
++			 */
++			xprt = list_entry(serv->sv_tempsocks.prev,
++					  struct svc_xprt,
++					  xpt_list);
++			set_bit(XPT_CLOSE, &xprt->xpt_flags);
++			svc_xprt_get(xprt);
++		}
++		spin_unlock_bh(&serv->sv_lock);
++
++		if (xprt) {
++			svc_xprt_enqueue(xprt);
++			svc_xprt_put(xprt);
++		}
++	}
++}
++
++/*
++ * Receive the next request on any transport.  This code is carefully
++ * organised not to touch any cachelines in the shared svc_serv
++ * structure, only cachelines in the local svc_pool.
++ */
++int svc_recv(struct svc_rqst *rqstp, long timeout)
++{
++	struct svc_xprt		*xprt = NULL;
++	struct svc_serv		*serv = rqstp->rq_server;
++	struct svc_pool		*pool = rqstp->rq_pool;
++	int			len, i;
++	int			pages;
++	struct xdr_buf		*arg;
++	DECLARE_WAITQUEUE(wait, current);
++
++	dprintk("svc: server %p waiting for data (to = %ld)\n",
++		rqstp, timeout);
++
++	if (rqstp->rq_xprt)
++		printk(KERN_ERR
++			"svc_recv: service %p, transport not NULL!\n",
++			 rqstp);
++	if (waitqueue_active(&rqstp->rq_wait))
++		printk(KERN_ERR
++			"svc_recv: service %p, wait queue active!\n",
++			 rqstp);
++
++	/* now allocate needed pages.  If we get a failure, sleep briefly */
++	pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
++	for (i = 0; i < pages ; i++)
++		while (rqstp->rq_pages[i] == NULL) {
++			struct page *p = alloc_page(GFP_KERNEL);
++			if (!p) {
++				int j = msecs_to_jiffies(500);
++				schedule_timeout_uninterruptible(j);
++			}
++			rqstp->rq_pages[i] = p;
++		}
++	rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
++	BUG_ON(pages >= RPCSVC_MAXPAGES);
++
++	/* Make arg->head point to first page and arg->pages point to rest */
++	arg = &rqstp->rq_arg;
++	arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
++	arg->head[0].iov_len = PAGE_SIZE;
++	arg->pages = rqstp->rq_pages + 1;
++	arg->page_base = 0;
++	/* save at least one page for response */
++	arg->page_len = (pages-2)*PAGE_SIZE;
++	arg->len = (pages-1)*PAGE_SIZE;
++	arg->tail[0].iov_len = 0;
++
++	try_to_freeze();
++	cond_resched();
++	if (signalled())
++		return -EINTR;
++
++	spin_lock_bh(&pool->sp_lock);
++	xprt = svc_xprt_dequeue(pool);
++	if (xprt) {
++		rqstp->rq_xprt = xprt;
++		svc_xprt_get(xprt);
++		rqstp->rq_reserved = serv->sv_max_mesg;
++		atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
++	} else {
++		/* No data pending. Go to sleep */
++		svc_thread_enqueue(pool, rqstp);
++
++		/*
++		 * We have to be able to interrupt this wait
++		 * to bring down the daemons ...
++		 */
++		set_current_state(TASK_INTERRUPTIBLE);
++		add_wait_queue(&rqstp->rq_wait, &wait);
++		spin_unlock_bh(&pool->sp_lock);
++
++		schedule_timeout(timeout);
++
++		try_to_freeze();
++
++		spin_lock_bh(&pool->sp_lock);
++		remove_wait_queue(&rqstp->rq_wait, &wait);
++
++		xprt = rqstp->rq_xprt;
++		if (!xprt) {
++			svc_thread_dequeue(pool, rqstp);
++			spin_unlock_bh(&pool->sp_lock);
++			dprintk("svc: server %p, no data yet\n", rqstp);
++			return signalled()? -EINTR : -EAGAIN;
++		}
++	}
++	spin_unlock_bh(&pool->sp_lock);
++
++	len = 0;
++	if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
++		dprintk("svc_recv: found XPT_CLOSE\n");
++		svc_delete_xprt(xprt);
++	} else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
++		struct svc_xprt *newxpt;
++		newxpt = xprt->xpt_ops->xpo_accept(xprt);
++		if (newxpt) {
++			/*
++			 * We know this module_get will succeed because the
++			 * listener holds a reference too
++			 */
++			__module_get(newxpt->xpt_class->xcl_owner);
++			svc_check_conn_limits(xprt->xpt_server);
++			spin_lock_bh(&serv->sv_lock);
++			set_bit(XPT_TEMP, &newxpt->xpt_flags);
++			list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
++			serv->sv_tmpcnt++;
++			if (serv->sv_temptimer.function == NULL) {
++				/* setup timer to age temp transports */
++				setup_timer(&serv->sv_temptimer,
++					    svc_age_temp_xprts,
++					    (unsigned long)serv);
++				mod_timer(&serv->sv_temptimer,
++					  jiffies + svc_conn_age_period * HZ);
++			}
++			spin_unlock_bh(&serv->sv_lock);
++			svc_xprt_received(newxpt);
++		}
++		svc_xprt_received(xprt);
++	} else {
++		dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
++			rqstp, pool->sp_id, xprt,
++			atomic_read(&xprt->xpt_ref.refcount));
++		rqstp->rq_deferred = svc_deferred_dequeue(xprt);
++		if (rqstp->rq_deferred) {
++			svc_xprt_received(xprt);
++			len = svc_deferred_recv(rqstp);
++		} else
++			len = xprt->xpt_ops->xpo_recvfrom(rqstp);
++		dprintk("svc: got len=%d\n", len);
++	}
++
++	/* No data, incomplete (TCP) read, or accept() */
++	if (len == 0 || len == -EAGAIN) {
++		rqstp->rq_res.len = 0;
++		svc_xprt_release(rqstp);
++		return -EAGAIN;
++	}
++	clear_bit(XPT_OLD, &xprt->xpt_flags);
++
++	rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
++	rqstp->rq_chandle.defer = svc_defer;
++
++	if (serv->sv_stats)
++		serv->sv_stats->netcnt++;
++	return len;
++}
++EXPORT_SYMBOL(svc_recv);
++
++/*
++ * Drop request
++ */
++void svc_drop(struct svc_rqst *rqstp)
++{
++	dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
++	svc_xprt_release(rqstp);
++}
++EXPORT_SYMBOL(svc_drop);
++
++/*
++ * Return reply to client.
++ */
++int svc_send(struct svc_rqst *rqstp)
++{
++	struct svc_xprt	*xprt;
++	int		len;
++	struct xdr_buf	*xb;
++
++	xprt = rqstp->rq_xprt;
++	if (!xprt)
++		return -EFAULT;
++
++	/* release the receive skb before sending the reply */
++	rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
++
++	/* calculate over-all length */
++	xb = &rqstp->rq_res;
++	xb->len = xb->head[0].iov_len +
++		xb->page_len +
++		xb->tail[0].iov_len;
++
++	/* Grab mutex to serialize outgoing data. */
++	mutex_lock(&xprt->xpt_mutex);
++	if (test_bit(XPT_DEAD, &xprt->xpt_flags))
++		len = -ENOTCONN;
++	else
++		len = xprt->xpt_ops->xpo_sendto(rqstp);
++	mutex_unlock(&xprt->xpt_mutex);
++	svc_xprt_release(rqstp);
++
++	if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
++		return 0;
++	return len;
++}
++
++/*
++ * Timer function to close old temporary transports, using
++ * a mark-and-sweep algorithm.
++ */
++static void svc_age_temp_xprts(unsigned long closure)
++{
++	struct svc_serv *serv = (struct svc_serv *)closure;
++	struct svc_xprt *xprt;
++	struct list_head *le, *next;
++	LIST_HEAD(to_be_aged);
++
++	dprintk("svc_age_temp_xprts\n");
++
++	if (!spin_trylock_bh(&serv->sv_lock)) {
++		/* busy, try again 1 sec later */
++		dprintk("svc_age_temp_xprts: busy\n");
++		mod_timer(&serv->sv_temptimer, jiffies + HZ);
++		return;
++	}
++
++	list_for_each_safe(le, next, &serv->sv_tempsocks) {
++		xprt = list_entry(le, struct svc_xprt, xpt_list);
++
++		/* First time through, just mark it OLD. Second time
++		 * through, close it. */
++		if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags))
++			continue;
++		if (atomic_read(&xprt->xpt_ref.refcount) > 1
++		    || test_bit(XPT_BUSY, &xprt->xpt_flags))
++			continue;
++		svc_xprt_get(xprt);
++		list_move(le, &to_be_aged);
++		set_bit(XPT_CLOSE, &xprt->xpt_flags);
++		set_bit(XPT_DETACHED, &xprt->xpt_flags);
++	}
++	spin_unlock_bh(&serv->sv_lock);
++
++	while (!list_empty(&to_be_aged)) {
++		le = to_be_aged.next;
++		/* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */
++		list_del_init(le);
++		xprt = list_entry(le, struct svc_xprt, xpt_list);
++
++		dprintk("queuing xprt %p for closing\n", xprt);
++
++		/* a thread will dequeue and close it soon */
++		svc_xprt_enqueue(xprt);
++		svc_xprt_put(xprt);
++	}
++
++	mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
++}
++
++/*
++ * Remove a dead transport
++ */
++void svc_delete_xprt(struct svc_xprt *xprt)
++{
++	struct svc_serv	*serv = xprt->xpt_server;
++
++	dprintk("svc: svc_delete_xprt(%p)\n", xprt);
++	xprt->xpt_ops->xpo_detach(xprt);
++
++	spin_lock_bh(&serv->sv_lock);
++	if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
++		list_del_init(&xprt->xpt_list);
++	/*
++	 * We used to delete the transport from whichever list
++	 * it's sk_xprt.xpt_ready node was on, but we don't actually
++	 * need to.  This is because the only time we're called
++	 * while still attached to a queue, the queue itself
++	 * is about to be destroyed (in svc_destroy).
++	 */
++	if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) {
++		BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2);
++		if (test_bit(XPT_TEMP, &xprt->xpt_flags))
++			serv->sv_tmpcnt--;
++		svc_xprt_put(xprt);
++	}
++	spin_unlock_bh(&serv->sv_lock);
++}
++
++void svc_close_xprt(struct svc_xprt *xprt)
++{
++	set_bit(XPT_CLOSE, &xprt->xpt_flags);
++	if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
++		/* someone else will have to effect the close */
++		return;
++
++	svc_xprt_get(xprt);
++	svc_delete_xprt(xprt);
++	clear_bit(XPT_BUSY, &xprt->xpt_flags);
++	svc_xprt_put(xprt);
++}
++EXPORT_SYMBOL_GPL(svc_close_xprt);
++
++void svc_close_all(struct list_head *xprt_list)
++{
++	struct svc_xprt *xprt;
++	struct svc_xprt *tmp;
++
++	list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
++		set_bit(XPT_CLOSE, &xprt->xpt_flags);
++		if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
++			/* Waiting to be processed, but no threads left,
++			 * So just remove it from the waiting list
++			 */
++			list_del_init(&xprt->xpt_ready);
++			clear_bit(XPT_BUSY, &xprt->xpt_flags);
++		}
++		svc_close_xprt(xprt);
++	}
++}
++
++/*
++ * Handle defer and revisit of requests
++ */
++
++static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
++{
++	struct svc_deferred_req *dr =
++		container_of(dreq, struct svc_deferred_req, handle);
++	struct svc_xprt *xprt = dr->xprt;
++
++	if (too_many) {
++		svc_xprt_put(xprt);
++		kfree(dr);
++		return;
++	}
++	dprintk("revisit queued\n");
++	dr->xprt = NULL;
++	spin_lock(&xprt->xpt_lock);
++	list_add(&dr->handle.recent, &xprt->xpt_deferred);
++	spin_unlock(&xprt->xpt_lock);
++	set_bit(XPT_DEFERRED, &xprt->xpt_flags);
++	svc_xprt_enqueue(xprt);
++	svc_xprt_put(xprt);
++}
++
++/*
++ * Save the request off for later processing. The request buffer looks
++ * like this:
++ *
++ * <xprt-header><rpc-header><rpc-pagelist><rpc-tail>
++ *
++ * This code can only handle requests that consist of an xprt-header
++ * and rpc-header.
++ */
++static struct cache_deferred_req *svc_defer(struct cache_req *req)
++{
++	struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
++	struct svc_deferred_req *dr;
++
++	if (rqstp->rq_arg.page_len)
++		return NULL; /* if more than a page, give up FIXME */
++	if (rqstp->rq_deferred) {
++		dr = rqstp->rq_deferred;
++		rqstp->rq_deferred = NULL;
++	} else {
++		size_t skip;
++		size_t size;
++		/* FIXME maybe discard if size too large */
++		size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
++		dr = kmalloc(size, GFP_KERNEL);
++		if (dr == NULL)
++			return NULL;
++
++		dr->handle.owner = rqstp->rq_server;
++		dr->prot = rqstp->rq_prot;
++		memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
++		dr->addrlen = rqstp->rq_addrlen;
++		dr->daddr = rqstp->rq_daddr;
++		dr->argslen = rqstp->rq_arg.len >> 2;
++		dr->xprt_hlen = rqstp->rq_xprt_hlen;
++
++		/* back up head to the start of the buffer and copy */
++		skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
++		memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
++		       dr->argslen << 2);
++	}
++	svc_xprt_get(rqstp->rq_xprt);
++	dr->xprt = rqstp->rq_xprt;
++
++	dr->handle.revisit = svc_revisit;
++	return &dr->handle;
++}
++
++/*
++ * recv data from a deferred request into an active one
++ */
++static int svc_deferred_recv(struct svc_rqst *rqstp)
++{
++	struct svc_deferred_req *dr = rqstp->rq_deferred;
++
++	/* setup iov_base past transport header */
++	rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2);
++	/* The iov_len does not include the transport header bytes */
++	rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen;
++	rqstp->rq_arg.page_len = 0;
++	/* The rq_arg.len includes the transport header bytes */
++	rqstp->rq_arg.len     = dr->argslen<<2;
++	rqstp->rq_prot        = dr->prot;
++	memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
++	rqstp->rq_addrlen     = dr->addrlen;
++	/* Save off transport header len in case we get deferred again */
++	rqstp->rq_xprt_hlen   = dr->xprt_hlen;
++	rqstp->rq_daddr       = dr->daddr;
++	rqstp->rq_respages    = rqstp->rq_pages;
++	return (dr->argslen<<2) - dr->xprt_hlen;
++}
++
++
++static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
++{
++	struct svc_deferred_req *dr = NULL;
++
++	if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
++		return NULL;
++	spin_lock(&xprt->xpt_lock);
++	clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
++	if (!list_empty(&xprt->xpt_deferred)) {
++		dr = list_entry(xprt->xpt_deferred.next,
++				struct svc_deferred_req,
++				handle.recent);
++		list_del_init(&dr->handle.recent);
++		set_bit(XPT_DEFERRED, &xprt->xpt_flags);
++	}
++	spin_unlock(&xprt->xpt_lock);
++	return dr;
++}
++
++/*
++ * Return the transport instance pointer for the endpoint accepting
++ * connections/peer traffic from the specified transport class,
++ * address family and port.
++ *
++ * Specifying 0 for the address family or port is effectively a
++ * wild-card, and will result in matching the first transport in the
++ * service's list that has a matching class name.
++ */
++struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
++			       int af, int port)
++{
++	struct svc_xprt *xprt;
++	struct svc_xprt *found = NULL;
++
++	/* Sanity check the args */
++	if (!serv || !xcl_name)
++		return found;
++
++	spin_lock_bh(&serv->sv_lock);
++	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
++		if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
++			continue;
++		if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
++			continue;
++		if (port && port != svc_xprt_local_port(xprt))
++			continue;
++		found = xprt;
++		svc_xprt_get(xprt);
++		break;
++	}
++	spin_unlock_bh(&serv->sv_lock);
++	return found;
++}
++EXPORT_SYMBOL_GPL(svc_find_xprt);
++
++/*
++ * Format a buffer with a list of the active transports. A zero for
++ * the buflen parameter disables target buffer overflow checking.
++ */
++int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
++{
++	struct svc_xprt *xprt;
++	char xprt_str[64];
++	int totlen = 0;
++	int len;
++
++	/* Sanity check args */
++	if (!serv)
++		return 0;
++
++	spin_lock_bh(&serv->sv_lock);
++	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
++		len = snprintf(xprt_str, sizeof(xprt_str),
++			       "%s %d\n", xprt->xpt_class->xcl_name,
++			       svc_xprt_local_port(xprt));
++		/* If the string was truncated, replace with error string */
++		if (len >= sizeof(xprt_str))
++			strcpy(xprt_str, "name-too-long\n");
++		/* Don't overflow buffer */
++		len = strlen(xprt_str);
++		if (buflen && (len + totlen >= buflen))
++			break;
++		strcpy(buf+totlen, xprt_str);
++		totlen += len;
++	}
++	spin_unlock_bh(&serv->sv_lock);
++	return totlen;
++}
++EXPORT_SYMBOL_GPL(svc_xprt_names);
+diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
+index af7c5f0..8a73cbb 100644
+--- a/net/sunrpc/svcauth.c
++++ b/net/sunrpc/svcauth.c
+@@ -57,11 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
+ 	rqstp->rq_authop = aops;
+ 	return aops->accept(rqstp, authp);
+ }
++EXPORT_SYMBOL(svc_authenticate);
+ 
+ int svc_set_client(struct svc_rqst *rqstp)
+ {
+ 	return rqstp->rq_authop->set_client(rqstp);
+ }
++EXPORT_SYMBOL(svc_set_client);
+ 
+ /* A request, which was authenticated, has now executed.
+  * Time to finalise the credentials and verifier
+@@ -93,6 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
+ 	spin_unlock(&authtab_lock);
+ 	return rv;
+ }
++EXPORT_SYMBOL(svc_auth_register);
+ 
+ void
+ svc_auth_unregister(rpc_authflavor_t flavor)
+@@ -129,6 +132,7 @@ void auth_domain_put(struct auth_domain *dom)
+ 		spin_unlock(&auth_domain_lock);
+ 	}
+ }
++EXPORT_SYMBOL(auth_domain_put);
+ 
+ struct auth_domain *
+ auth_domain_lookup(char *name, struct auth_domain *new)
+@@ -153,8 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new)
+ 	spin_unlock(&auth_domain_lock);
+ 	return new;
+ }
++EXPORT_SYMBOL(auth_domain_lookup);
+ 
+ struct auth_domain *auth_domain_find(char *name)
  {
- 	struct rpcbind_args map = {
- 		.r_prog		= prog,
-@@ -272,14 +221,13 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
- 		.rpc_resp	= &map.r_port,
- 	};
- 	struct rpc_clnt	*rpcb_clnt;
--	char hostname[40];
- 	int status;
+ 	return auth_domain_lookup(name, NULL);
+ }
++EXPORT_SYMBOL(auth_domain_find);
+diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
+index 4114794..3c64051 100644
+--- a/net/sunrpc/svcauth_unix.c
++++ b/net/sunrpc/svcauth_unix.c
+@@ -63,6 +63,7 @@ struct auth_domain *unix_domain_find(char *name)
+ 		rv = auth_domain_lookup(name, &new->h);
+ 	}
+ }
++EXPORT_SYMBOL(unix_domain_find);
  
- 	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
- 		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+ static void svcauth_unix_domain_release(struct auth_domain *dom)
+ {
+@@ -340,6 +341,7 @@ int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+ 	else
+ 		return -ENOMEM;
+ }
++EXPORT_SYMBOL(auth_unix_add_addr);
  
--	sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
--	rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
-+	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
-+				sizeof(*sin), prot, 2, 0);
- 	if (IS_ERR(rpcb_clnt))
- 		return PTR_ERR(rpcb_clnt);
+ int auth_unix_forget_old(struct auth_domain *dom)
+ {
+@@ -351,6 +353,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
+ 	udom->addr_changes++;
+ 	return 0;
+ }
++EXPORT_SYMBOL(auth_unix_forget_old);
  
-@@ -295,6 +243,24 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
+ struct auth_domain *auth_unix_lookup(struct in_addr addr)
+ {
+@@ -375,50 +378,56 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr)
+ 	cache_put(&ipm->h, &ip_map_cache);
+ 	return rv;
  }
- EXPORT_SYMBOL_GPL(rpcb_getport_sync);
++EXPORT_SYMBOL(auth_unix_lookup);
  
-+static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version)
-+{
-+	struct rpc_message msg = {
-+		.rpc_proc = rpcb_next_version[version].rpc_proc,
-+		.rpc_argp = map,
-+		.rpc_resp = &map->r_port,
-+	};
-+	struct rpc_task_setup task_setup_data = {
-+		.rpc_client = rpcb_clnt,
-+		.rpc_message = &msg,
-+		.callback_ops = &rpcb_getport_ops,
-+		.callback_data = map,
-+		.flags = RPC_TASK_ASYNC,
-+	};
-+
-+	return rpc_run_task(&task_setup_data);
-+}
-+
- /**
-  * rpcb_getport_async - obtain the port for a given RPC service on a given host
-  * @task: task that is waiting for portmapper request
-@@ -305,12 +271,14 @@ EXPORT_SYMBOL_GPL(rpcb_getport_sync);
- void rpcb_getport_async(struct rpc_task *task)
+ void svcauth_unix_purge(void)
  {
- 	struct rpc_clnt *clnt = task->tk_client;
--	int bind_version;
-+	u32 bind_version;
- 	struct rpc_xprt *xprt = task->tk_xprt;
- 	struct rpc_clnt	*rpcb_clnt;
- 	static struct rpcbind_args *map;
- 	struct rpc_task	*child;
--	struct sockaddr addr;
-+	struct sockaddr_storage addr;
-+	struct sockaddr *sap = (struct sockaddr *)&addr;
-+	size_t salen;
- 	int status;
- 	struct rpcb_info *info;
+ 	cache_purge(&ip_map_cache);
+ }
++EXPORT_SYMBOL(svcauth_unix_purge);
  
-@@ -340,10 +308,10 @@ void rpcb_getport_async(struct rpc_task *task)
- 		goto bailout_nofree;
+ static inline struct ip_map *
+ ip_map_cached_get(struct svc_rqst *rqstp)
+ {
+-	struct ip_map *ipm;
+-	struct svc_sock *svsk = rqstp->rq_sock;
+-	spin_lock(&svsk->sk_lock);
+-	ipm = svsk->sk_info_authunix;
+-	if (ipm != NULL) {
+-		if (!cache_valid(&ipm->h)) {
+-			/*
+-			 * The entry has been invalidated since it was
+-			 * remembered, e.g. by a second mount from the
+-			 * same IP address.
+-			 */
+-			svsk->sk_info_authunix = NULL;
+-			spin_unlock(&svsk->sk_lock);
+-			cache_put(&ipm->h, &ip_map_cache);
+-			return NULL;
++	struct ip_map *ipm = NULL;
++	struct svc_xprt *xprt = rqstp->rq_xprt;
++
++	if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
++		spin_lock(&xprt->xpt_lock);
++		ipm = xprt->xpt_auth_cache;
++		if (ipm != NULL) {
++			if (!cache_valid(&ipm->h)) {
++				/*
++				 * The entry has been invalidated since it was
++				 * remembered, e.g. by a second mount from the
++				 * same IP address.
++				 */
++				xprt->xpt_auth_cache = NULL;
++				spin_unlock(&xprt->xpt_lock);
++				cache_put(&ipm->h, &ip_map_cache);
++				return NULL;
++			}
++			cache_get(&ipm->h);
+ 		}
+-		cache_get(&ipm->h);
++		spin_unlock(&xprt->xpt_lock);
  	}
+-	spin_unlock(&svsk->sk_lock);
+ 	return ipm;
+ }
  
--	rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
-+	salen = rpc_peeraddr(clnt, sap, sizeof(addr));
+ static inline void
+ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+ {
+-	struct svc_sock *svsk = rqstp->rq_sock;
++	struct svc_xprt *xprt = rqstp->rq_xprt;
  
- 	/* Don't ever use rpcbind v2 for AF_INET6 requests */
--	switch (addr.sa_family) {
-+	switch (sap->sa_family) {
+-	spin_lock(&svsk->sk_lock);
+-	if (svsk->sk_sock->type == SOCK_STREAM &&
+-	    svsk->sk_info_authunix == NULL) {
+-		/* newly cached, keep the reference */
+-		svsk->sk_info_authunix = ipm;
+-		ipm = NULL;
++	if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
++		spin_lock(&xprt->xpt_lock);
++		if (xprt->xpt_auth_cache == NULL) {
++			/* newly cached, keep the reference */
++			xprt->xpt_auth_cache = ipm;
++			ipm = NULL;
++		}
++		spin_unlock(&xprt->xpt_lock);
+ 	}
+-	spin_unlock(&svsk->sk_lock);
+ 	if (ipm)
+ 		cache_put(&ipm->h, &ip_map_cache);
+ }
+diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
+index c75bffe..1d3e5fc 100644
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -5,7 +5,7 @@
+  *
+  * The server scheduling algorithm does not always distribute the load
+  * evenly when servicing a single client. May need to modify the
+- * svc_sock_enqueue procedure...
++ * svc_xprt_enqueue procedure...
+  *
+  * TCP support is largely untested and may be a little slow. The problem
+  * is that we currently do two separate recvfrom's, one for the 4-byte
+@@ -48,72 +48,40 @@
+ #include <linux/sunrpc/svcsock.h>
+ #include <linux/sunrpc/stats.h>
+ 
+-/* SMP locking strategy:
+- *
+- *	svc_pool->sp_lock protects most of the fields of that pool.
+- * 	svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
+- *	when both need to be taken (rare), svc_serv->sv_lock is first.
+- *	BKL protects svc_serv->sv_nrthread.
+- *	svc_sock->sk_lock protects the svc_sock->sk_deferred list
+- *             and the ->sk_info_authunix cache.
+- *	svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
+- *
+- *	Some flags can be set to certain values at any time
+- *	providing that certain rules are followed:
+- *
+- *	SK_CONN, SK_DATA, can be set or cleared at any time.
+- *		after a set, svc_sock_enqueue must be called.
+- *		after a clear, the socket must be read/accepted
+- *		 if this succeeds, it must be set again.
+- *	SK_CLOSE can set at any time. It is never cleared.
+- *      sk_inuse contains a bias of '1' until SK_DEAD is set.
+- *             so when sk_inuse hits zero, we know the socket is dead
+- *             and no-one is using it.
+- *      SK_DEAD can only be set while SK_BUSY is held which ensures
+- *             no other thread will be using the socket or will try to
+- *	       set SK_DEAD.
+- *
+- */
+-
+-#define RPCDBG_FACILITY	RPCDBG_SVCSOCK
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
+ 
+ 
+ static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
+ 					 int *errp, int flags);
+-static void		svc_delete_socket(struct svc_sock *svsk);
+ static void		svc_udp_data_ready(struct sock *, int);
+ static int		svc_udp_recvfrom(struct svc_rqst *);
+ static int		svc_udp_sendto(struct svc_rqst *);
+-static void		svc_close_socket(struct svc_sock *svsk);
+-
+-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
+-static int svc_deferred_recv(struct svc_rqst *rqstp);
+-static struct cache_deferred_req *svc_defer(struct cache_req *req);
+-
+-/* apparently the "standard" is that clients close
+- * idle connections after 5 minutes, servers after
+- * 6 minutes
+- *   http://www.connectathon.org/talks96/nfstcp.pdf
+- */
+-static int svc_conn_age_period = 6*60;
++static void		svc_sock_detach(struct svc_xprt *);
++static void		svc_sock_free(struct svc_xprt *);
+ 
++static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
++					  struct sockaddr *, int, int);
+ #ifdef CONFIG_DEBUG_LOCK_ALLOC
+ static struct lock_class_key svc_key[2];
+ static struct lock_class_key svc_slock_key[2];
+ 
+-static inline void svc_reclassify_socket(struct socket *sock)
++static void svc_reclassify_socket(struct socket *sock)
+ {
+ 	struct sock *sk = sock->sk;
+ 	BUG_ON(sock_owned_by_user(sk));
+ 	switch (sk->sk_family) {
  	case AF_INET:
- 		info = rpcb_next_version;
+ 		sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
+-		    &svc_slock_key[0], "sk_lock-AF_INET-NFSD", &svc_key[0]);
++					      &svc_slock_key[0],
++					      "sk_xprt.xpt_lock-AF_INET-NFSD",
++					      &svc_key[0]);
  		break;
-@@ -368,7 +336,7 @@ void rpcb_getport_async(struct rpc_task *task)
- 	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
- 		task->tk_pid, __FUNCTION__, bind_version);
- 
--	rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
-+	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
- 				bind_version, 0);
- 	if (IS_ERR(rpcb_clnt)) {
- 		status = PTR_ERR(rpcb_clnt);
-@@ -390,12 +358,10 @@ void rpcb_getport_async(struct rpc_task *task)
- 	map->r_port = 0;
- 	map->r_xprt = xprt_get(xprt);
- 	map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
--	memcpy(map->r_addr,
--	       rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
--	       sizeof(map->r_addr));
-+	map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
- 	map->r_owner = RPCB_OWNER_STRING;	/* ignored for GETADDR */
- 
--	child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
-+	child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index);
- 	rpc_release_client(rpcb_clnt);
- 	if (IS_ERR(child)) {
- 		status = -EIO;
-@@ -518,7 +484,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
- 	 * Simple sanity check.  The smallest possible universal
- 	 * address is an IPv4 address string containing 11 bytes.
- 	 */
--	if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN)
-+	if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN)
- 		goto out_err;
  
- 	/*
-@@ -569,7 +535,7 @@ out_err:
- #define RPCB_boolean_sz		(1u)
+ 	case AF_INET6:
+ 		sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
+-		    &svc_slock_key[1], "sk_lock-AF_INET6-NFSD", &svc_key[1]);
++					      &svc_slock_key[1],
++					      "sk_xprt.xpt_lock-AF_INET6-NFSD",
++					      &svc_key[1]);
+ 		break;
  
- #define RPCB_netid_sz		(1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
--#define RPCB_addr_sz		(1+XDR_QUADLEN(RPCB_MAXADDRLEN))
-+#define RPCB_addr_sz		(1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
- #define RPCB_ownerstring_sz	(1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
+ 	default:
+@@ -121,81 +89,26 @@ static inline void svc_reclassify_socket(struct socket *sock)
+ 	}
+ }
+ #else
+-static inline void svc_reclassify_socket(struct socket *sock)
++static void svc_reclassify_socket(struct socket *sock)
+ {
+ }
+ #endif
  
- #define RPCB_mappingargs_sz	RPCB_program_sz+RPCB_version_sz+	\
-diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
-index c98873f..4c66912 100644
---- a/net/sunrpc/sched.c
-+++ b/net/sunrpc/sched.c
-@@ -45,7 +45,7 @@ static void			 rpc_release_task(struct rpc_task *task);
+-static char *__svc_print_addr(struct sockaddr *addr, char *buf, size_t len)
+-{
+-	switch (addr->sa_family) {
+-	case AF_INET:
+-		snprintf(buf, len, "%u.%u.%u.%u, port=%u",
+-			NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
+-			ntohs(((struct sockaddr_in *) addr)->sin_port));
+-		break;
+-
+-	case AF_INET6:
+-		snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
+-			NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
+-			ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
+-		break;
+-
+-	default:
+-		snprintf(buf, len, "unknown address type: %d", addr->sa_family);
+-		break;
+-	}
+-	return buf;
+-}
+-
+-/**
+- * svc_print_addr - Format rq_addr field for printing
+- * @rqstp: svc_rqst struct containing address to print
+- * @buf: target buffer for formatted address
+- * @len: length of target buffer
+- *
+- */
+-char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
+-{
+-	return __svc_print_addr(svc_addr(rqstp), buf, len);
+-}
+-EXPORT_SYMBOL_GPL(svc_print_addr);
+-
+-/*
+- * Queue up an idle server thread.  Must have pool->sp_lock held.
+- * Note: this is really a stack rather than a queue, so that we only
+- * use as many different threads as we need, and the rest don't pollute
+- * the cache.
+- */
+-static inline void
+-svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
+-{
+-	list_add(&rqstp->rq_list, &pool->sp_threads);
+-}
+-
+-/*
+- * Dequeue an nfsd thread.  Must have pool->sp_lock held.
+- */
+-static inline void
+-svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
+-{
+-	list_del(&rqstp->rq_list);
+-}
+-
  /*
-  * RPC tasks sit here while waiting for conditions to improve.
+  * Release an skbuff after use
   */
--static RPC_WAITQ(delay_queue, "delayq");
-+static struct rpc_wait_queue delay_queue;
+-static inline void
+-svc_release_skb(struct svc_rqst *rqstp)
++static void svc_release_skb(struct svc_rqst *rqstp)
+ {
+-	struct sk_buff *skb = rqstp->rq_skbuff;
++	struct sk_buff *skb = rqstp->rq_xprt_ctxt;
+ 	struct svc_deferred_req *dr = rqstp->rq_deferred;
  
- /*
-  * rpciod-related stuff
-@@ -135,7 +135,7 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct r
- 	if (unlikely(task->tk_priority > queue->maxpriority))
- 		q = &queue->tasks[queue->maxpriority];
- 	list_for_each_entry(t, q, u.tk_wait.list) {
--		if (t->tk_cookie == task->tk_cookie) {
-+		if (t->tk_owner == task->tk_owner) {
- 			list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
- 			return;
- 		}
-@@ -208,26 +208,26 @@ static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int
- 	queue->count = 1 << (priority * 2);
- }
+ 	if (skb) {
+-		rqstp->rq_skbuff = NULL;
++		struct svc_sock *svsk =
++			container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
++		rqstp->rq_xprt_ctxt = NULL;
  
--static inline void rpc_set_waitqueue_cookie(struct rpc_wait_queue *queue, unsigned long cookie)
-+static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
- {
--	queue->cookie = cookie;
-+	queue->owner = pid;
- 	queue->nr = RPC_BATCH_COUNT;
+ 		dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
+-		skb_free_datagram(rqstp->rq_sock->sk_sk, skb);
++		skb_free_datagram(svsk->sk_sk, skb);
+ 	}
+ 	if (dr) {
+ 		rqstp->rq_deferred = NULL;
+@@ -203,253 +116,6 @@ svc_release_skb(struct svc_rqst *rqstp)
+ 	}
  }
  
- static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
- {
- 	rpc_set_waitqueue_priority(queue, queue->maxpriority);
--	rpc_set_waitqueue_cookie(queue, 0);
-+	rpc_set_waitqueue_owner(queue, 0);
- }
+-/*
+- * Any space to write?
+- */
+-static inline unsigned long
+-svc_sock_wspace(struct svc_sock *svsk)
+-{
+-	int wspace;
+-
+-	if (svsk->sk_sock->type == SOCK_STREAM)
+-		wspace = sk_stream_wspace(svsk->sk_sk);
+-	else
+-		wspace = sock_wspace(svsk->sk_sk);
+-
+-	return wspace;
+-}
+-
+-/*
+- * Queue up a socket with data pending. If there are idle nfsd
+- * processes, wake 'em up.
+- *
+- */
+-static void
+-svc_sock_enqueue(struct svc_sock *svsk)
+-{
+-	struct svc_serv	*serv = svsk->sk_server;
+-	struct svc_pool *pool;
+-	struct svc_rqst	*rqstp;
+-	int cpu;
+-
+-	if (!(svsk->sk_flags &
+-	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
+-		return;
+-	if (test_bit(SK_DEAD, &svsk->sk_flags))
+-		return;
+-
+-	cpu = get_cpu();
+-	pool = svc_pool_for_cpu(svsk->sk_server, cpu);
+-	put_cpu();
+-
+-	spin_lock_bh(&pool->sp_lock);
+-
+-	if (!list_empty(&pool->sp_threads) &&
+-	    !list_empty(&pool->sp_sockets))
+-		printk(KERN_ERR
+-			"svc_sock_enqueue: threads and sockets both waiting??\n");
+-
+-	if (test_bit(SK_DEAD, &svsk->sk_flags)) {
+-		/* Don't enqueue dead sockets */
+-		dprintk("svc: socket %p is dead, not enqueued\n", svsk->sk_sk);
+-		goto out_unlock;
+-	}
+-
+-	/* Mark socket as busy. It will remain in this state until the
+-	 * server has processed all pending data and put the socket back
+-	 * on the idle list.  We update SK_BUSY atomically because
+-	 * it also guards against trying to enqueue the svc_sock twice.
+-	 */
+-	if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) {
+-		/* Don't enqueue socket while already enqueued */
+-		dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
+-		goto out_unlock;
+-	}
+-	BUG_ON(svsk->sk_pool != NULL);
+-	svsk->sk_pool = pool;
+-
+-	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+-	if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
+-	     > svc_sock_wspace(svsk))
+-	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
+-	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
+-		/* Don't enqueue while not enough space for reply */
+-		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
+-			svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
+-			svc_sock_wspace(svsk));
+-		svsk->sk_pool = NULL;
+-		clear_bit(SK_BUSY, &svsk->sk_flags);
+-		goto out_unlock;
+-	}
+-	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+-
+-
+-	if (!list_empty(&pool->sp_threads)) {
+-		rqstp = list_entry(pool->sp_threads.next,
+-				   struct svc_rqst,
+-				   rq_list);
+-		dprintk("svc: socket %p served by daemon %p\n",
+-			svsk->sk_sk, rqstp);
+-		svc_thread_dequeue(pool, rqstp);
+-		if (rqstp->rq_sock)
+-			printk(KERN_ERR
+-				"svc_sock_enqueue: server %p, rq_sock=%p!\n",
+-				rqstp, rqstp->rq_sock);
+-		rqstp->rq_sock = svsk;
+-		atomic_inc(&svsk->sk_inuse);
+-		rqstp->rq_reserved = serv->sv_max_mesg;
+-		atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
+-		BUG_ON(svsk->sk_pool != pool);
+-		wake_up(&rqstp->rq_wait);
+-	} else {
+-		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
+-		list_add_tail(&svsk->sk_ready, &pool->sp_sockets);
+-		BUG_ON(svsk->sk_pool != pool);
+-	}
+-
+-out_unlock:
+-	spin_unlock_bh(&pool->sp_lock);
+-}
+-
+-/*
+- * Dequeue the first socket.  Must be called with the pool->sp_lock held.
+- */
+-static inline struct svc_sock *
+-svc_sock_dequeue(struct svc_pool *pool)
+-{
+-	struct svc_sock	*svsk;
+-
+-	if (list_empty(&pool->sp_sockets))
+-		return NULL;
+-
+-	svsk = list_entry(pool->sp_sockets.next,
+-			  struct svc_sock, sk_ready);
+-	list_del_init(&svsk->sk_ready);
+-
+-	dprintk("svc: socket %p dequeued, inuse=%d\n",
+-		svsk->sk_sk, atomic_read(&svsk->sk_inuse));
+-
+-	return svsk;
+-}
+-
+-/*
+- * Having read something from a socket, check whether it
+- * needs to be re-enqueued.
+- * Note: SK_DATA only gets cleared when a read-attempt finds
+- * no (or insufficient) data.
+- */
+-static inline void
+-svc_sock_received(struct svc_sock *svsk)
+-{
+-	svsk->sk_pool = NULL;
+-	clear_bit(SK_BUSY, &svsk->sk_flags);
+-	svc_sock_enqueue(svsk);
+-}
+-
+-
+-/**
+- * svc_reserve - change the space reserved for the reply to a request.
+- * @rqstp:  The request in question
+- * @space: new max space to reserve
+- *
+- * Each request reserves some space on the output queue of the socket
+- * to make sure the reply fits.  This function reduces that reserved
+- * space to be the amount of space used already, plus @space.
+- *
+- */
+-void svc_reserve(struct svc_rqst *rqstp, int space)
+-{
+-	space += rqstp->rq_res.head[0].iov_len;
+-
+-	if (space < rqstp->rq_reserved) {
+-		struct svc_sock *svsk = rqstp->rq_sock;
+-		atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved);
+-		rqstp->rq_reserved = space;
+-
+-		svc_sock_enqueue(svsk);
+-	}
+-}
+-
+-/*
+- * Release a socket after use.
+- */
+-static inline void
+-svc_sock_put(struct svc_sock *svsk)
+-{
+-	if (atomic_dec_and_test(&svsk->sk_inuse)) {
+-		BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags));
+-
+-		dprintk("svc: releasing dead socket\n");
+-		if (svsk->sk_sock->file)
+-			sockfd_put(svsk->sk_sock);
+-		else
+-			sock_release(svsk->sk_sock);
+-		if (svsk->sk_info_authunix != NULL)
+-			svcauth_unix_info_release(svsk->sk_info_authunix);
+-		kfree(svsk);
+-	}
+-}
+-
+-static void
+-svc_sock_release(struct svc_rqst *rqstp)
+-{
+-	struct svc_sock	*svsk = rqstp->rq_sock;
+-
+-	svc_release_skb(rqstp);
+-
+-	svc_free_res_pages(rqstp);
+-	rqstp->rq_res.page_len = 0;
+-	rqstp->rq_res.page_base = 0;
+-
+-
+-	/* Reset response buffer and release
+-	 * the reservation.
+-	 * But first, check that enough space was reserved
+-	 * for the reply, otherwise we have a bug!
+-	 */
+-	if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
+-		printk(KERN_ERR "RPC request reserved %d but used %d\n",
+-		       rqstp->rq_reserved,
+-		       rqstp->rq_res.len);
+-
+-	rqstp->rq_res.head[0].iov_len = 0;
+-	svc_reserve(rqstp, 0);
+-	rqstp->rq_sock = NULL;
+-
+-	svc_sock_put(svsk);
+-}
+-
+-/*
+- * External function to wake up a server waiting for data
+- * This really only makes sense for services like lockd
+- * which have exactly one thread anyway.
+- */
+-void
+-svc_wake_up(struct svc_serv *serv)
+-{
+-	struct svc_rqst	*rqstp;
+-	unsigned int i;
+-	struct svc_pool *pool;
+-
+-	for (i = 0; i < serv->sv_nrpools; i++) {
+-		pool = &serv->sv_pools[i];
+-
+-		spin_lock_bh(&pool->sp_lock);
+-		if (!list_empty(&pool->sp_threads)) {
+-			rqstp = list_entry(pool->sp_threads.next,
+-					   struct svc_rqst,
+-					   rq_list);
+-			dprintk("svc: daemon %p woken up.\n", rqstp);
+-			/*
+-			svc_thread_dequeue(pool, rqstp);
+-			rqstp->rq_sock = NULL;
+-			 */
+-			wake_up(&rqstp->rq_wait);
+-		}
+-		spin_unlock_bh(&pool->sp_lock);
+-	}
+-}
+-
+ union svc_pktinfo_u {
+ 	struct in_pktinfo pkti;
+ 	struct in6_pktinfo pkti6;
+@@ -459,7 +125,9 @@ union svc_pktinfo_u {
  
--static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, int maxprio)
-+static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
+ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
  {
- 	int i;
- 
- 	spin_lock_init(&queue->lock);
- 	for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
- 		INIT_LIST_HEAD(&queue->tasks[i]);
--	queue->maxpriority = maxprio;
-+	queue->maxpriority = nr_queues - 1;
- 	rpc_reset_waitqueue_priority(queue);
- #ifdef RPC_DEBUG
- 	queue->name = qname;
-@@ -236,18 +236,18 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
+-	switch (rqstp->rq_sock->sk_sk->sk_family) {
++	struct svc_sock *svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
++	switch (svsk->sk_sk->sk_family) {
+ 	case AF_INET: {
+ 			struct in_pktinfo *pki = CMSG_DATA(cmh);
  
- void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+@@ -489,10 +157,10 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
+ /*
+  * Generic sendto routine
+  */
+-static int
+-svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
++static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
  {
--	__rpc_init_priority_wait_queue(queue, qname, RPC_PRIORITY_HIGH);
-+	__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
- }
+-	struct svc_sock	*svsk = rqstp->rq_sock;
++	struct svc_sock	*svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ 	struct socket	*sock = svsk->sk_sock;
+ 	int		slen;
+ 	union {
+@@ -565,7 +233,7 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
+ 	}
+ out:
+ 	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n",
+-		rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len,
++		svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
+ 		xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
  
- void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
+ 	return len;
+@@ -602,7 +270,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
+ 	if (!serv)
+ 		return 0;
+ 	spin_lock_bh(&serv->sv_lock);
+-	list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
++	list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
+ 		int onelen = one_sock_name(buf+len, svsk);
+ 		if (toclose && strcmp(toclose, buf+len) == 0)
+ 			closesk = svsk;
+@@ -614,7 +282,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
+ 		/* Should unregister with portmap, but you cannot
+ 		 * unregister just one protocol...
+ 		 */
+-		svc_close_socket(closesk);
++		svc_close_xprt(&closesk->sk_xprt);
+ 	else if (toclose)
+ 		return -ENOENT;
+ 	return len;
+@@ -624,8 +292,7 @@ EXPORT_SYMBOL(svc_sock_names);
+ /*
+  * Check input queue length
+  */
+-static int
+-svc_recv_available(struct svc_sock *svsk)
++static int svc_recv_available(struct svc_sock *svsk)
  {
--	__rpc_init_priority_wait_queue(queue, qname, 0);
-+	__rpc_init_priority_wait_queue(queue, qname, 1);
+ 	struct socket	*sock = svsk->sk_sock;
+ 	int		avail, err;
+@@ -638,48 +305,31 @@ svc_recv_available(struct svc_sock *svsk)
+ /*
+  * Generic recvfrom routine.
+  */
+-static int
+-svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen)
++static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
++			int buflen)
+ {
+-	struct svc_sock *svsk = rqstp->rq_sock;
++	struct svc_sock *svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+ 	struct msghdr msg = {
+ 		.msg_flags	= MSG_DONTWAIT,
+ 	};
+-	struct sockaddr *sin;
+ 	int len;
+ 
++	rqstp->rq_xprt_hlen = 0;
++
+ 	len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
+ 				msg.msg_flags);
+ 
+-	/* sock_recvmsg doesn't fill in the name/namelen, so we must..
+-	 */
+-	memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen);
+-	rqstp->rq_addrlen = svsk->sk_remotelen;
+-
+-	/* Destination address in request is needed for binding the
+-	 * source address in RPC callbacks later.
+-	 */
+-	sin = (struct sockaddr *)&svsk->sk_local;
+-	switch (sin->sa_family) {
+-	case AF_INET:
+-		rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
+-		break;
+-	case AF_INET6:
+-		rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
+-		break;
+-	}
+-
+ 	dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
+ 		svsk, iov[0].iov_base, iov[0].iov_len, len);
+-
+ 	return len;
  }
--EXPORT_SYMBOL(rpc_init_wait_queue);
-+EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
  
--static int rpc_wait_bit_interruptible(void *word)
-+static int rpc_wait_bit_killable(void *word)
+ /*
+  * Set socket snd and rcv buffer lengths
+  */
+-static inline void
+-svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
++static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
++				unsigned int rcv)
  {
--	if (signal_pending(current))
-+	if (fatal_signal_pending(current))
- 		return -ERESTARTSYS;
- 	schedule();
- 	return 0;
-@@ -299,11 +299,11 @@ static void rpc_mark_complete_task(struct rpc_task *task)
- int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
+ #if 0
+ 	mm_segment_t	oldfs;
+@@ -704,16 +354,16 @@ svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+ /*
+  * INET callback when data has been received on the socket.
+  */
+-static void
+-svc_udp_data_ready(struct sock *sk, int count)
++static void svc_udp_data_ready(struct sock *sk, int count)
  {
- 	if (action == NULL)
--		action = rpc_wait_bit_interruptible;
-+		action = rpc_wait_bit_killable;
- 	return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
--			action, TASK_INTERRUPTIBLE);
-+			action, TASK_KILLABLE);
- }
--EXPORT_SYMBOL(__rpc_wait_for_completion_task);
-+EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
+ 	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
  
+ 	if (svsk) {
+ 		dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
+-			svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
+-		set_bit(SK_DATA, &svsk->sk_flags);
+-		svc_sock_enqueue(svsk);
++			svsk, sk, count,
++			test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
++		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
++		svc_xprt_enqueue(&svsk->sk_xprt);
+ 	}
+ 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ 		wake_up_interruptible(sk->sk_sleep);
+@@ -722,15 +372,14 @@ svc_udp_data_ready(struct sock *sk, int count)
  /*
-  * Make an RPC task runnable.
-@@ -373,6 +373,7 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
- 	__rpc_sleep_on(q, task, action, timer);
- 	spin_unlock_bh(&q->lock);
- }
-+EXPORT_SYMBOL_GPL(rpc_sleep_on);
+  * INET callback when space is newly available on the socket.
+  */
+-static void
+-svc_write_space(struct sock *sk)
++static void svc_write_space(struct sock *sk)
+ {
+ 	struct svc_sock	*svsk = (struct svc_sock *)(sk->sk_user_data);
  
- /**
-  * __rpc_do_wake_up_task - wake up a single rpc_task
-@@ -444,6 +445,7 @@ void rpc_wake_up_task(struct rpc_task *task)
+ 	if (svsk) {
+ 		dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
+-			svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
+-		svc_sock_enqueue(svsk);
++			svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
++		svc_xprt_enqueue(&svsk->sk_xprt);
+ 	}
+ 
+ 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) {
+@@ -740,10 +389,19 @@ svc_write_space(struct sock *sk)
  	}
- 	rcu_read_unlock_bh();
  }
-+EXPORT_SYMBOL_GPL(rpc_wake_up_task);
  
+-static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
+-					    struct cmsghdr *cmh)
++/*
++ * Copy the UDP datagram's destination address to the rqstp structure.
++ * The 'destination' address in this case is the address to which the
++ * peer sent the datagram, i.e. our local address. For multihomed
++ * hosts, this can change from msg to msg. Note that only the IP
++ * address changes, the port number should remain the same.
++ */
++static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
++				     struct cmsghdr *cmh)
+ {
+-	switch (rqstp->rq_sock->sk_sk->sk_family) {
++	struct svc_sock *svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
++	switch (svsk->sk_sk->sk_family) {
+ 	case AF_INET: {
+ 		struct in_pktinfo *pki = CMSG_DATA(cmh);
+ 		rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
+@@ -760,11 +418,11 @@ static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
  /*
-  * Wake up the next task on a priority queue.
-@@ -454,12 +456,12 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
- 	struct rpc_task *task;
+  * Receive a datagram from a UDP socket.
+  */
+-static int
+-svc_udp_recvfrom(struct svc_rqst *rqstp)
++static int svc_udp_recvfrom(struct svc_rqst *rqstp)
+ {
+-	struct svc_sock	*svsk = rqstp->rq_sock;
+-	struct svc_serv	*serv = svsk->sk_server;
++	struct svc_sock	*svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
++	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
+ 	struct sk_buff	*skb;
+ 	union {
+ 		struct cmsghdr	hdr;
+@@ -779,7 +437,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ 		.msg_flags = MSG_DONTWAIT,
+ 	};
  
- 	/*
--	 * Service a batch of tasks from a single cookie.
-+	 * Service a batch of tasks from a single owner.
- 	 */
- 	q = &queue->tasks[queue->priority];
- 	if (!list_empty(q)) {
- 		task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
--		if (queue->cookie == task->tk_cookie) {
-+		if (queue->owner == task->tk_owner) {
- 			if (--queue->nr)
- 				goto out;
- 			list_move_tail(&task->u.tk_wait.list, q);
-@@ -468,7 +470,7 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
- 		 * Check if we need to switch queues.
- 		 */
- 		if (--queue->count)
--			goto new_cookie;
-+			goto new_owner;
+-	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
++	if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
+ 	    /* udp sockets need large rcvbuf as all pending
+ 	     * requests are still in that buffer.  sndbuf must
+ 	     * also be large enough that there is enough space
+@@ -792,17 +450,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ 				(serv->sv_nrthreads+3) * serv->sv_max_mesg,
+ 				(serv->sv_nrthreads+3) * serv->sv_max_mesg);
+ 
+-	if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
+-		svc_sock_received(svsk);
+-		return svc_deferred_recv(rqstp);
+-	}
+-
+-	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
+-		svc_delete_socket(svsk);
+-		return 0;
+-	}
+-
+-	clear_bit(SK_DATA, &svsk->sk_flags);
++	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ 	skb = NULL;
+ 	err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
+ 			     0, 0, MSG_PEEK | MSG_DONTWAIT);
+@@ -813,24 +461,27 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ 		if (err != -EAGAIN) {
+ 			/* possibly an icmp error */
+ 			dprintk("svc: recvfrom returned error %d\n", -err);
+-			set_bit(SK_DATA, &svsk->sk_flags);
++			set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ 		}
+-		svc_sock_received(svsk);
++		svc_xprt_received(&svsk->sk_xprt);
+ 		return -EAGAIN;
  	}
+-	rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
++	len = svc_addr_len(svc_addr(rqstp));
++	if (len < 0)
++		return len;
++	rqstp->rq_addrlen = len;
+ 	if (skb->tstamp.tv64 == 0) {
+ 		skb->tstamp = ktime_get_real();
+ 		/* Don't enable netstamp, sunrpc doesn't
+ 		   need that much accuracy */
+ 	}
+ 	svsk->sk_sk->sk_stamp = skb->tstamp;
+-	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
++	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
  
  	/*
-@@ -490,8 +492,8 @@ static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queu
- 
- new_queue:
- 	rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
--new_cookie:
--	rpc_set_waitqueue_cookie(queue, task->tk_cookie);
-+new_owner:
-+	rpc_set_waitqueue_owner(queue, task->tk_owner);
- out:
- 	__rpc_wake_up_task(task);
- 	return task;
-@@ -519,6 +521,7 @@ struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
+ 	 * Maybe more packets - kick another thread ASAP.
+ 	 */
+-	svc_sock_received(svsk);
++	svc_xprt_received(&svsk->sk_xprt);
  
- 	return task;
- }
-+EXPORT_SYMBOL_GPL(rpc_wake_up_next);
+ 	len  = skb->len - sizeof(struct udphdr);
+ 	rqstp->rq_arg.len = len;
+@@ -861,13 +512,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
+ 		skb_free_datagram(svsk->sk_sk, skb);
+ 	} else {
+ 		/* we can use it in-place */
+-		rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr);
++		rqstp->rq_arg.head[0].iov_base = skb->data +
++			sizeof(struct udphdr);
+ 		rqstp->rq_arg.head[0].iov_len = len;
+ 		if (skb_checksum_complete(skb)) {
+ 			skb_free_datagram(svsk->sk_sk, skb);
+ 			return 0;
+ 		}
+-		rqstp->rq_skbuff = skb;
++		rqstp->rq_xprt_ctxt = skb;
+ 	}
  
- /**
-  * rpc_wake_up - wake up all rpc_tasks
-@@ -544,6 +547,7 @@ void rpc_wake_up(struct rpc_wait_queue *queue)
- 	spin_unlock(&queue->lock);
- 	rcu_read_unlock_bh();
+ 	rqstp->rq_arg.page_base = 0;
+@@ -900,27 +552,81 @@ svc_udp_sendto(struct svc_rqst *rqstp)
+ 	return error;
  }
-+EXPORT_SYMBOL_GPL(rpc_wake_up);
  
- /**
-  * rpc_wake_up_status - wake up all rpc_tasks and set their status value.
-@@ -572,6 +576,7 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
- 	spin_unlock(&queue->lock);
- 	rcu_read_unlock_bh();
- }
-+EXPORT_SYMBOL_GPL(rpc_wake_up_status);
+-static void
+-svc_udp_init(struct svc_sock *svsk)
++static void svc_udp_prep_reply_hdr(struct svc_rqst *rqstp)
++{
++}
++
++static int svc_udp_has_wspace(struct svc_xprt *xprt)
++{
++	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
++	struct svc_serv	*serv = xprt->xpt_server;
++	unsigned long required;
++
++	/*
++	 * Set the SOCK_NOSPACE flag before checking the available
++	 * sock space.
++	 */
++	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
++	required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
++	if (required*2 > sock_wspace(svsk->sk_sk))
++		return 0;
++	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
++	return 1;
++}
++
++static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
++{
++	BUG();
++	return NULL;
++}
++
++static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
++				       struct sockaddr *sa, int salen,
++				       int flags)
++{
++	return svc_create_socket(serv, IPPROTO_UDP, sa, salen, flags);
++}
++
++static struct svc_xprt_ops svc_udp_ops = {
++	.xpo_create = svc_udp_create,
++	.xpo_recvfrom = svc_udp_recvfrom,
++	.xpo_sendto = svc_udp_sendto,
++	.xpo_release_rqst = svc_release_skb,
++	.xpo_detach = svc_sock_detach,
++	.xpo_free = svc_sock_free,
++	.xpo_prep_reply_hdr = svc_udp_prep_reply_hdr,
++	.xpo_has_wspace = svc_udp_has_wspace,
++	.xpo_accept = svc_udp_accept,
++};
++
++static struct svc_xprt_class svc_udp_class = {
++	.xcl_name = "udp",
++	.xcl_owner = THIS_MODULE,
++	.xcl_ops = &svc_udp_ops,
++	.xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
++};
++
++static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
+ {
+ 	int one = 1;
+ 	mm_segment_t oldfs;
+ 
++	svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
++	clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
+ 	svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
+ 	svsk->sk_sk->sk_write_space = svc_write_space;
+-	svsk->sk_recvfrom = svc_udp_recvfrom;
+-	svsk->sk_sendto = svc_udp_sendto;
+ 
+ 	/* initialise setting must have enough space to
+ 	 * receive and respond to one request.
+ 	 * svc_udp_recvfrom will re-adjust if necessary
+ 	 */
+ 	svc_sock_setbufsize(svsk->sk_sock,
+-			    3 * svsk->sk_server->sv_max_mesg,
+-			    3 * svsk->sk_server->sv_max_mesg);
++			    3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
++			    3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
+ 
+-	set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
+-	set_bit(SK_CHNGBUF, &svsk->sk_flags);
++	/* data might have come in before data_ready set up */
++	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
++	set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
  
- static void __rpc_atrun(struct rpc_task *task)
+ 	oldfs = get_fs();
+ 	set_fs(KERNEL_DS);
+@@ -934,8 +640,7 @@ svc_udp_init(struct svc_sock *svsk)
+  * A data_ready event on a listening socket means there's a connection
+  * pending. Do not use state_change as a substitute for it.
+  */
+-static void
+-svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
++static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
  {
-@@ -586,6 +591,7 @@ void rpc_delay(struct rpc_task *task, unsigned long delay)
- 	task->tk_timeout = delay;
- 	rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun);
- }
-+EXPORT_SYMBOL_GPL(rpc_delay);
+ 	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
  
+@@ -954,8 +659,8 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
+ 	 */
+ 	if (sk->sk_state == TCP_LISTEN) {
+ 		if (svsk) {
+-			set_bit(SK_CONN, &svsk->sk_flags);
+-			svc_sock_enqueue(svsk);
++			set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
++			svc_xprt_enqueue(&svsk->sk_xprt);
+ 		} else
+ 			printk("svc: socket %p: no user data\n", sk);
+ 	}
+@@ -967,8 +672,7 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
  /*
-  * Helper to call task->tk_ops->rpc_call_prepare
-@@ -614,7 +620,7 @@ void rpc_exit_task(struct rpc_task *task)
- 		}
+  * A state change on a connected socket means it's dying or dead.
+  */
+-static void
+-svc_tcp_state_change(struct sock *sk)
++static void svc_tcp_state_change(struct sock *sk)
+ {
+ 	struct svc_sock	*svsk = (struct svc_sock *)sk->sk_user_data;
+ 
+@@ -978,51 +682,36 @@ svc_tcp_state_change(struct sock *sk)
+ 	if (!svsk)
+ 		printk("svc: socket %p: no user data\n", sk);
+ 	else {
+-		set_bit(SK_CLOSE, &svsk->sk_flags);
+-		svc_sock_enqueue(svsk);
++		set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
++		svc_xprt_enqueue(&svsk->sk_xprt);
  	}
+ 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ 		wake_up_interruptible_all(sk->sk_sleep);
  }
--EXPORT_SYMBOL(rpc_exit_task);
-+EXPORT_SYMBOL_GPL(rpc_exit_task);
  
- void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
+-static void
+-svc_tcp_data_ready(struct sock *sk, int count)
++static void svc_tcp_data_ready(struct sock *sk, int count)
  {
-@@ -690,10 +696,9 @@ static void __rpc_execute(struct rpc_task *task)
+ 	struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
  
- 		/* sync task: sleep here */
- 		dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid);
--		/* Note: Caller should be using rpc_clnt_sigmask() */
- 		status = out_of_line_wait_on_bit(&task->tk_runstate,
--				RPC_TASK_QUEUED, rpc_wait_bit_interruptible,
--				TASK_INTERRUPTIBLE);
-+				RPC_TASK_QUEUED, rpc_wait_bit_killable,
-+				TASK_KILLABLE);
- 		if (status == -ERESTARTSYS) {
- 			/*
- 			 * When a sync task receives a signal, it exits with
-@@ -808,40 +813,47 @@ EXPORT_SYMBOL_GPL(rpc_free);
+ 	dprintk("svc: socket %p TCP data ready (svsk %p)\n",
+ 		sk, sk->sk_user_data);
+ 	if (svsk) {
+-		set_bit(SK_DATA, &svsk->sk_flags);
+-		svc_sock_enqueue(svsk);
++		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
++		svc_xprt_enqueue(&svsk->sk_xprt);
+ 	}
+ 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+ 		wake_up_interruptible(sk->sk_sleep);
+ }
+ 
+-static inline int svc_port_is_privileged(struct sockaddr *sin)
+-{
+-	switch (sin->sa_family) {
+-	case AF_INET:
+-		return ntohs(((struct sockaddr_in *)sin)->sin_port)
+-			< PROT_SOCK;
+-	case AF_INET6:
+-		return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
+-			< PROT_SOCK;
+-	default:
+-		return 0;
+-	}
+-}
+-
  /*
-  * Creation and deletion of RPC task structures
+  * Accept a TCP connection
   */
--void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
-+static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data)
+-static void
+-svc_tcp_accept(struct svc_sock *svsk)
++static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
  {
- 	memset(task, 0, sizeof(*task));
--	init_timer(&task->tk_timer);
--	task->tk_timer.data     = (unsigned long) task;
--	task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer;
-+	setup_timer(&task->tk_timer, (void (*)(unsigned long))rpc_run_timer,
-+			(unsigned long)task);
- 	atomic_set(&task->tk_count, 1);
--	task->tk_client = clnt;
--	task->tk_flags  = flags;
--	task->tk_ops = tk_ops;
--	if (tk_ops->rpc_call_prepare != NULL)
--		task->tk_action = rpc_prepare_task;
--	task->tk_calldata = calldata;
-+	task->tk_flags  = task_setup_data->flags;
-+	task->tk_ops = task_setup_data->callback_ops;
-+	task->tk_calldata = task_setup_data->callback_data;
- 	INIT_LIST_HEAD(&task->tk_task);
++	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+ 	struct sockaddr_storage addr;
+ 	struct sockaddr	*sin = (struct sockaddr *) &addr;
+-	struct svc_serv	*serv = svsk->sk_server;
++	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
+ 	struct socket	*sock = svsk->sk_sock;
+ 	struct socket	*newsock;
+ 	struct svc_sock	*newsvsk;
+@@ -1031,9 +720,9 @@ svc_tcp_accept(struct svc_sock *svsk)
  
- 	/* Initialize retry counters */
- 	task->tk_garb_retry = 2;
- 	task->tk_cred_retry = 2;
- 
--	task->tk_priority = RPC_PRIORITY_NORMAL;
--	task->tk_cookie = (unsigned long)current;
-+	task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW;
-+	task->tk_owner = current->tgid;
+ 	dprintk("svc: tcp_accept %p sock %p\n", svsk, sock);
+ 	if (!sock)
+-		return;
++		return NULL;
  
- 	/* Initialize workqueue for async tasks */
- 	task->tk_workqueue = rpciod_workqueue;
+-	clear_bit(SK_CONN, &svsk->sk_flags);
++	clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
+ 	err = kernel_accept(sock, &newsock, O_NONBLOCK);
+ 	if (err < 0) {
+ 		if (err == -ENOMEM)
+@@ -1042,11 +731,9 @@ svc_tcp_accept(struct svc_sock *svsk)
+ 		else if (err != -EAGAIN && net_ratelimit())
+ 			printk(KERN_WARNING "%s: accept failed (err %d)!\n",
+ 				   serv->sv_name, -err);
+-		return;
++		return NULL;
+ 	}
+-
+-	set_bit(SK_CONN, &svsk->sk_flags);
+-	svc_sock_enqueue(svsk);
++	set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
  
--	if (clnt) {
--		kref_get(&clnt->cl_kref);
--		if (clnt->cl_softrtry)
-+	task->tk_client = task_setup_data->rpc_client;
-+	if (task->tk_client != NULL) {
-+		kref_get(&task->tk_client->cl_kref);
-+		if (task->tk_client->cl_softrtry)
- 			task->tk_flags |= RPC_TASK_SOFT;
--		if (!clnt->cl_intr)
--			task->tk_flags |= RPC_TASK_NOINTR;
+ 	err = kernel_getpeername(newsock, sin, &slen);
+ 	if (err < 0) {
+@@ -1077,106 +764,42 @@ svc_tcp_accept(struct svc_sock *svsk)
+ 	if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
+ 				 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
+ 		goto failed;
+-	memcpy(&newsvsk->sk_remote, sin, slen);
+-	newsvsk->sk_remotelen = slen;
++	svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
+ 	err = kernel_getsockname(newsock, sin, &slen);
+ 	if (unlikely(err < 0)) {
+ 		dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
+ 		slen = offsetof(struct sockaddr, sa_data);
  	}
+-	memcpy(&newsvsk->sk_local, sin, slen);
+-
+-	svc_sock_received(newsvsk);
+-
+-	/* make sure that we don't have too many active connections.
+-	 * If we have, something must be dropped.
+-	 *
+-	 * There's no point in trying to do random drop here for
+-	 * DoS prevention. The NFS clients does 1 reconnect in 15
+-	 * seconds. An attacker can easily beat that.
+-	 *
+-	 * The only somewhat efficient mechanism would be if drop
+-	 * old connections from the same IP first. But right now
+-	 * we don't even record the client IP in svc_sock.
+-	 */
+-	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
+-		struct svc_sock *svsk = NULL;
+-		spin_lock_bh(&serv->sv_lock);
+-		if (!list_empty(&serv->sv_tempsocks)) {
+-			if (net_ratelimit()) {
+-				/* Try to help the admin */
+-				printk(KERN_NOTICE "%s: too many open TCP "
+-					"sockets, consider increasing the "
+-					"number of nfsd threads\n",
+-						   serv->sv_name);
+-				printk(KERN_NOTICE
+-				       "%s: last TCP connect from %s\n",
+-				       serv->sv_name, __svc_print_addr(sin,
+-							buf, sizeof(buf)));
+-			}
+-			/*
+-			 * Always select the oldest socket. It's not fair,
+-			 * but so is life
+-			 */
+-			svsk = list_entry(serv->sv_tempsocks.prev,
+-					  struct svc_sock,
+-					  sk_list);
+-			set_bit(SK_CLOSE, &svsk->sk_flags);
+-			atomic_inc(&svsk->sk_inuse);
+-		}
+-		spin_unlock_bh(&serv->sv_lock);
+-
+-		if (svsk) {
+-			svc_sock_enqueue(svsk);
+-			svc_sock_put(svsk);
+-		}
+-
+-	}
++	svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
  
--	BUG_ON(task->tk_ops == NULL);
-+	if (task->tk_ops->rpc_call_prepare != NULL)
-+		task->tk_action = rpc_prepare_task;
-+
-+	if (task_setup_data->rpc_message != NULL) {
-+		memcpy(&task->tk_msg, task_setup_data->rpc_message, sizeof(task->tk_msg));
-+		/* Bind the user cred */
-+		if (task->tk_msg.rpc_cred != NULL)
-+			rpcauth_holdcred(task);
-+		else
-+			rpcauth_bindcred(task);
-+		if (task->tk_action == NULL)
-+			rpc_call_start(task);
-+	}
+ 	if (serv->sv_stats)
+ 		serv->sv_stats->nettcpconn++;
+ 
+-	return;
++	return &newsvsk->sk_xprt;
+ 
+ failed:
+ 	sock_release(newsock);
+-	return;
++	return NULL;
+ }
  
- 	/* starting timestamp */
- 	task->tk_start = jiffies;
-@@ -866,18 +878,22 @@ static void rpc_free_task(struct rcu_head *rcu)
  /*
-  * Create a new task for the specified client.
+  * Receive data from a TCP socket.
   */
--struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
-+struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
+-static int
+-svc_tcp_recvfrom(struct svc_rqst *rqstp)
++static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
  {
--	struct rpc_task	*task;
+-	struct svc_sock	*svsk = rqstp->rq_sock;
+-	struct svc_serv	*serv = svsk->sk_server;
++	struct svc_sock	*svsk =
++		container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
++	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
+ 	int		len;
+ 	struct kvec *vec;
+ 	int pnum, vlen;
+ 
+ 	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
+-		svsk, test_bit(SK_DATA, &svsk->sk_flags),
+-		test_bit(SK_CONN, &svsk->sk_flags),
+-		test_bit(SK_CLOSE, &svsk->sk_flags));
++		svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags),
++		test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
++		test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
+ 
+-	if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
+-		svc_sock_received(svsk);
+-		return svc_deferred_recv(rqstp);
+-	}
 -
--	task = rpc_alloc_task();
--	if (!task)
--		goto out;
-+	struct rpc_task	*task = setup_data->task;
-+	unsigned short flags = 0;
-+
-+	if (task == NULL) {
-+		task = rpc_alloc_task();
-+		if (task == NULL)
-+			goto out;
-+		flags = RPC_TASK_DYNAMIC;
-+	}
+-	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
+-		svc_delete_socket(svsk);
+-		return 0;
+-	}
+-
+-	if (svsk->sk_sk->sk_state == TCP_LISTEN) {
+-		svc_tcp_accept(svsk);
+-		svc_sock_received(svsk);
+-		return 0;
+-	}
+-
+-	if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
++	if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
+ 		/* sndbuf needs to have room for one request
+ 		 * per thread, otherwise we can stall even when the
+ 		 * network isn't a bottleneck.
+@@ -1193,7 +816,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ 				    (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+ 				    3 * serv->sv_max_mesg);
+ 
+-	clear_bit(SK_DATA, &svsk->sk_flags);
++	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ 
+ 	/* Receive data. If we haven't got the record length yet, get
+ 	 * the next four bytes. Otherwise try to gobble up as much as
+@@ -1212,7 +835,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ 		if (len < want) {
+ 			dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
+ 				len, want);
+-			svc_sock_received(svsk);
++			svc_xprt_received(&svsk->sk_xprt);
+ 			return -EAGAIN; /* record header not complete */
+ 		}
+ 
+@@ -1248,11 +871,11 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ 	if (len < svsk->sk_reclen) {
+ 		dprintk("svc: incomplete TCP record (%d of %d)\n",
+ 			len, svsk->sk_reclen);
+-		svc_sock_received(svsk);
++		svc_xprt_received(&svsk->sk_xprt);
+ 		return -EAGAIN;	/* record not complete */
+ 	}
+ 	len = svsk->sk_reclen;
+-	set_bit(SK_DATA, &svsk->sk_flags);
++	set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ 
+ 	vec = rqstp->rq_vec;
+ 	vec[0] = rqstp->rq_arg.head[0];
+@@ -1281,30 +904,31 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ 		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
+ 	}
+ 
+-	rqstp->rq_skbuff      = NULL;
++	rqstp->rq_xprt_ctxt   = NULL;
+ 	rqstp->rq_prot	      = IPPROTO_TCP;
+ 
+ 	/* Reset TCP read info */
+ 	svsk->sk_reclen = 0;
+ 	svsk->sk_tcplen = 0;
+ 
+-	svc_sock_received(svsk);
++	svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
++	svc_xprt_received(&svsk->sk_xprt);
+ 	if (serv->sv_stats)
+ 		serv->sv_stats->nettcpcnt++;
  
--	rpc_init_task(task, clnt, flags, tk_ops, calldata);
-+	rpc_init_task(task, setup_data);
+ 	return len;
  
-+	task->tk_flags |= flags;
- 	dprintk("RPC:       allocated task %p\n", task);
--	task->tk_flags |= RPC_TASK_DYNAMIC;
- out:
- 	return task;
- }
-@@ -903,7 +919,7 @@ void rpc_put_task(struct rpc_task *task)
- 		call_rcu_bh(&task->u.tk_rcu, rpc_free_task);
- 	rpc_release_calldata(tk_ops, calldata);
- }
--EXPORT_SYMBOL(rpc_put_task);
-+EXPORT_SYMBOL_GPL(rpc_put_task);
+  err_delete:
+-	svc_delete_socket(svsk);
++	set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+ 	return -EAGAIN;
  
- static void rpc_release_task(struct rpc_task *task)
+  error:
+ 	if (len == -EAGAIN) {
+ 		dprintk("RPC: TCP recvfrom got EAGAIN\n");
+-		svc_sock_received(svsk);
++		svc_xprt_received(&svsk->sk_xprt);
+ 	} else {
+ 		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
+-					svsk->sk_server->sv_name, -len);
++		       svsk->sk_xprt.xpt_server->sv_name, -len);
+ 		goto err_delete;
+ 	}
+ 
+@@ -1314,8 +938,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
+ /*
+  * Send out data on TCP socket.
+  */
+-static int
+-svc_tcp_sendto(struct svc_rqst *rqstp)
++static int svc_tcp_sendto(struct svc_rqst *rqstp)
  {
-@@ -960,6 +976,7 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
+ 	struct xdr_buf	*xbufp = &rqstp->rq_res;
+ 	int sent;
+@@ -1328,35 +951,109 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
+ 	reclen = htonl(0x80000000|((xbufp->len ) - 4));
+ 	memcpy(xbufp->head[0].iov_base, &reclen, 4);
+ 
+-	if (test_bit(SK_DEAD, &rqstp->rq_sock->sk_flags))
++	if (test_bit(XPT_DEAD, &rqstp->rq_xprt->xpt_flags))
+ 		return -ENOTCONN;
+ 
+ 	sent = svc_sendto(rqstp, &rqstp->rq_res);
+ 	if (sent != xbufp->len) {
+-		printk(KERN_NOTICE "rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
+-		       rqstp->rq_sock->sk_server->sv_name,
++		printk(KERN_NOTICE
++		       "rpc-srv/tcp: %s: %s %d when sending %d bytes "
++		       "- shutting down socket\n",
++		       rqstp->rq_xprt->xpt_server->sv_name,
+ 		       (sent<0)?"got error":"sent only",
+ 		       sent, xbufp->len);
+-		set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags);
+-		svc_sock_enqueue(rqstp->rq_sock);
++		set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
++		svc_xprt_enqueue(rqstp->rq_xprt);
+ 		sent = -EAGAIN;
  	}
- 	spin_unlock(&clnt->cl_lock);
+ 	return sent;
  }
-+EXPORT_SYMBOL_GPL(rpc_killall_tasks);
  
- int rpciod_up(void)
- {
-@@ -1039,6 +1056,11 @@ rpc_init_mempool(void)
- 		goto err_nomem;
- 	if (!rpciod_start())
- 		goto err_nomem;
+-static void
+-svc_tcp_init(struct svc_sock *svsk)
++/*
++ * Setup response header. TCP has a 4B record length field.
++ */
++static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
++{
++	struct kvec *resv = &rqstp->rq_res.head[0];
++
++	/* tcp needs a space for the record length... */
++	svc_putnl(resv, 0);
++}
++
++static int svc_tcp_has_wspace(struct svc_xprt *xprt)
++{
++	struct svc_sock *svsk =	container_of(xprt, struct svc_sock, sk_xprt);
++	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
++	int required;
++	int wspace;
++
 +	/*
-+	 * The following is not strictly a mempool initialisation,
-+	 * but there is no harm in doing it here
++	 * Set the SOCK_NOSPACE flag before checking the available
++	 * sock space.
 +	 */
-+	rpc_init_wait_queue(&delay_queue, "delayq");
- 	return 0;
- err_nomem:
- 	rpc_destroy_mempool();
-diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
-index 97ac45f..a661a3a 100644
---- a/net/sunrpc/socklib.c
-+++ b/net/sunrpc/socklib.c
-@@ -72,7 +72,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct
- 	struct page	**ppage = xdr->pages;
- 	unsigned int	len, pglen = xdr->page_len;
- 	ssize_t		copied = 0;
--	int		ret;
-+	size_t		ret;
++	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
++	required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
++	wspace = sk_stream_wspace(svsk->sk_sk);
++
++	if (wspace < sk_stream_min_wspace(svsk->sk_sk))
++		return 0;
++	if (required * 2 > wspace)
++		return 0;
++
++	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
++	return 1;
++}
++
++static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
++				       struct sockaddr *sa, int salen,
++				       int flags)
++{
++	return svc_create_socket(serv, IPPROTO_TCP, sa, salen, flags);
++}
++
++static struct svc_xprt_ops svc_tcp_ops = {
++	.xpo_create = svc_tcp_create,
++	.xpo_recvfrom = svc_tcp_recvfrom,
++	.xpo_sendto = svc_tcp_sendto,
++	.xpo_release_rqst = svc_release_skb,
++	.xpo_detach = svc_sock_detach,
++	.xpo_free = svc_sock_free,
++	.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
++	.xpo_has_wspace = svc_tcp_has_wspace,
++	.xpo_accept = svc_tcp_accept,
++};
++
++static struct svc_xprt_class svc_tcp_class = {
++	.xcl_name = "tcp",
++	.xcl_owner = THIS_MODULE,
++	.xcl_ops = &svc_tcp_ops,
++	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
++};
++
++void svc_init_xprt_sock(void)
++{
++	svc_reg_xprt_class(&svc_tcp_class);
++	svc_reg_xprt_class(&svc_udp_class);
++}
++
++void svc_cleanup_xprt_sock(void)
++{
++	svc_unreg_xprt_class(&svc_tcp_class);
++	svc_unreg_xprt_class(&svc_udp_class);
++}
++
++static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
+ {
+ 	struct sock	*sk = svsk->sk_sk;
+ 	struct tcp_sock *tp = tcp_sk(sk);
  
- 	len = xdr->head[0].iov_len;
- 	if (base < len) {
-diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
-index 4d4f373..74df2d3 100644
---- a/net/sunrpc/stats.c
-+++ b/net/sunrpc/stats.c
-@@ -118,7 +118,7 @@ struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
- 	new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
- 	return new;
+-	svsk->sk_recvfrom = svc_tcp_recvfrom;
+-	svsk->sk_sendto = svc_tcp_sendto;
+-
++	svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
++	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
+ 	if (sk->sk_state == TCP_LISTEN) {
+ 		dprintk("setting up TCP socket for listening\n");
++		set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
+ 		sk->sk_data_ready = svc_tcp_listen_data_ready;
+-		set_bit(SK_CONN, &svsk->sk_flags);
++		set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
+ 	} else {
+ 		dprintk("setting up TCP socket for reading\n");
+ 		sk->sk_state_change = svc_tcp_state_change;
+@@ -1373,18 +1070,17 @@ svc_tcp_init(struct svc_sock *svsk)
+ 		 * svc_tcp_recvfrom will re-adjust if necessary
+ 		 */
+ 		svc_sock_setbufsize(svsk->sk_sock,
+-				    3 * svsk->sk_server->sv_max_mesg,
+-				    3 * svsk->sk_server->sv_max_mesg);
++				    3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
++				    3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
+ 
+-		set_bit(SK_CHNGBUF, &svsk->sk_flags);
+-		set_bit(SK_DATA, &svsk->sk_flags);
++		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
++		set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ 		if (sk->sk_state != TCP_ESTABLISHED)
+-			set_bit(SK_CLOSE, &svsk->sk_flags);
++			set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+ 	}
  }
--EXPORT_SYMBOL(rpc_alloc_iostats);
-+EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
  
- /**
-  * rpc_free_iostats - release an rpc_iostats structure
-@@ -129,7 +129,7 @@ void rpc_free_iostats(struct rpc_iostats *stats)
+-void
+-svc_sock_update_bufs(struct svc_serv *serv)
++void svc_sock_update_bufs(struct svc_serv *serv)
  {
- 	kfree(stats);
+ 	/*
+ 	 * The number of server threads has changed. Update
+@@ -1395,232 +1091,18 @@ svc_sock_update_bufs(struct svc_serv *serv)
+ 	spin_lock_bh(&serv->sv_lock);
+ 	list_for_each(le, &serv->sv_permsocks) {
+ 		struct svc_sock *svsk =
+-			list_entry(le, struct svc_sock, sk_list);
+-		set_bit(SK_CHNGBUF, &svsk->sk_flags);
++			list_entry(le, struct svc_sock, sk_xprt.xpt_list);
++		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
+ 	}
+ 	list_for_each(le, &serv->sv_tempsocks) {
+ 		struct svc_sock *svsk =
+-			list_entry(le, struct svc_sock, sk_list);
+-		set_bit(SK_CHNGBUF, &svsk->sk_flags);
++			list_entry(le, struct svc_sock, sk_xprt.xpt_list);
++		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
+ 	}
+ 	spin_unlock_bh(&serv->sv_lock);
  }
--EXPORT_SYMBOL(rpc_free_iostats);
-+EXPORT_SYMBOL_GPL(rpc_free_iostats);
  
- /**
-  * rpc_count_iostats - tally up per-task stats
-@@ -215,7 +215,7 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
- 				metrics->om_execute * MILLISECS_PER_JIFFY);
+ /*
+- * Receive the next request on any socket.  This code is carefully
+- * organised not to touch any cachelines in the shared svc_serv
+- * structure, only cachelines in the local svc_pool.
+- */
+-int
+-svc_recv(struct svc_rqst *rqstp, long timeout)
+-{
+-	struct svc_sock		*svsk = NULL;
+-	struct svc_serv		*serv = rqstp->rq_server;
+-	struct svc_pool		*pool = rqstp->rq_pool;
+-	int			len, i;
+-	int 			pages;
+-	struct xdr_buf		*arg;
+-	DECLARE_WAITQUEUE(wait, current);
+-
+-	dprintk("svc: server %p waiting for data (to = %ld)\n",
+-		rqstp, timeout);
+-
+-	if (rqstp->rq_sock)
+-		printk(KERN_ERR
+-			"svc_recv: service %p, socket not NULL!\n",
+-			 rqstp);
+-	if (waitqueue_active(&rqstp->rq_wait))
+-		printk(KERN_ERR
+-			"svc_recv: service %p, wait queue active!\n",
+-			 rqstp);
+-
+-
+-	/* now allocate needed pages.  If we get a failure, sleep briefly */
+-	pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
+-	for (i=0; i < pages ; i++)
+-		while (rqstp->rq_pages[i] == NULL) {
+-			struct page *p = alloc_page(GFP_KERNEL);
+-			if (!p)
+-				schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+-			rqstp->rq_pages[i] = p;
+-		}
+-	rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
+-	BUG_ON(pages >= RPCSVC_MAXPAGES);
+-
+-	/* Make arg->head point to first page and arg->pages point to rest */
+-	arg = &rqstp->rq_arg;
+-	arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
+-	arg->head[0].iov_len = PAGE_SIZE;
+-	arg->pages = rqstp->rq_pages + 1;
+-	arg->page_base = 0;
+-	/* save at least one page for response */
+-	arg->page_len = (pages-2)*PAGE_SIZE;
+-	arg->len = (pages-1)*PAGE_SIZE;
+-	arg->tail[0].iov_len = 0;
+-
+-	try_to_freeze();
+-	cond_resched();
+-	if (signalled())
+-		return -EINTR;
+-
+-	spin_lock_bh(&pool->sp_lock);
+-	if ((svsk = svc_sock_dequeue(pool)) != NULL) {
+-		rqstp->rq_sock = svsk;
+-		atomic_inc(&svsk->sk_inuse);
+-		rqstp->rq_reserved = serv->sv_max_mesg;
+-		atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
+-	} else {
+-		/* No data pending. Go to sleep */
+-		svc_thread_enqueue(pool, rqstp);
+-
+-		/*
+-		 * We have to be able to interrupt this wait
+-		 * to bring down the daemons ...
+-		 */
+-		set_current_state(TASK_INTERRUPTIBLE);
+-		add_wait_queue(&rqstp->rq_wait, &wait);
+-		spin_unlock_bh(&pool->sp_lock);
+-
+-		schedule_timeout(timeout);
+-
+-		try_to_freeze();
+-
+-		spin_lock_bh(&pool->sp_lock);
+-		remove_wait_queue(&rqstp->rq_wait, &wait);
+-
+-		if (!(svsk = rqstp->rq_sock)) {
+-			svc_thread_dequeue(pool, rqstp);
+-			spin_unlock_bh(&pool->sp_lock);
+-			dprintk("svc: server %p, no data yet\n", rqstp);
+-			return signalled()? -EINTR : -EAGAIN;
+-		}
+-	}
+-	spin_unlock_bh(&pool->sp_lock);
+-
+-	dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
+-		 rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse));
+-	len = svsk->sk_recvfrom(rqstp);
+-	dprintk("svc: got len=%d\n", len);
+-
+-	/* No data, incomplete (TCP) read, or accept() */
+-	if (len == 0 || len == -EAGAIN) {
+-		rqstp->rq_res.len = 0;
+-		svc_sock_release(rqstp);
+-		return -EAGAIN;
+-	}
+-	svsk->sk_lastrecv = get_seconds();
+-	clear_bit(SK_OLD, &svsk->sk_flags);
+-
+-	rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
+-	rqstp->rq_chandle.defer = svc_defer;
+-
+-	if (serv->sv_stats)
+-		serv->sv_stats->netcnt++;
+-	return len;
+-}
+-
+-/*
+- * Drop request
+- */
+-void
+-svc_drop(struct svc_rqst *rqstp)
+-{
+-	dprintk("svc: socket %p dropped request\n", rqstp->rq_sock);
+-	svc_sock_release(rqstp);
+-}
+-
+-/*
+- * Return reply to client.
+- */
+-int
+-svc_send(struct svc_rqst *rqstp)
+-{
+-	struct svc_sock	*svsk;
+-	int		len;
+-	struct xdr_buf	*xb;
+-
+-	if ((svsk = rqstp->rq_sock) == NULL) {
+-		printk(KERN_WARNING "NULL socket pointer in %s:%d\n",
+-				__FILE__, __LINE__);
+-		return -EFAULT;
+-	}
+-
+-	/* release the receive skb before sending the reply */
+-	svc_release_skb(rqstp);
+-
+-	/* calculate over-all length */
+-	xb = & rqstp->rq_res;
+-	xb->len = xb->head[0].iov_len +
+-		xb->page_len +
+-		xb->tail[0].iov_len;
+-
+-	/* Grab svsk->sk_mutex to serialize outgoing data. */
+-	mutex_lock(&svsk->sk_mutex);
+-	if (test_bit(SK_DEAD, &svsk->sk_flags))
+-		len = -ENOTCONN;
+-	else
+-		len = svsk->sk_sendto(rqstp);
+-	mutex_unlock(&svsk->sk_mutex);
+-	svc_sock_release(rqstp);
+-
+-	if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
+-		return 0;
+-	return len;
+-}
+-
+-/*
+- * Timer function to close old temporary sockets, using
+- * a mark-and-sweep algorithm.
+- */
+-static void
+-svc_age_temp_sockets(unsigned long closure)
+-{
+-	struct svc_serv *serv = (struct svc_serv *)closure;
+-	struct svc_sock *svsk;
+-	struct list_head *le, *next;
+-	LIST_HEAD(to_be_aged);
+-
+-	dprintk("svc_age_temp_sockets\n");
+-
+-	if (!spin_trylock_bh(&serv->sv_lock)) {
+-		/* busy, try again 1 sec later */
+-		dprintk("svc_age_temp_sockets: busy\n");
+-		mod_timer(&serv->sv_temptimer, jiffies + HZ);
+-		return;
+-	}
+-
+-	list_for_each_safe(le, next, &serv->sv_tempsocks) {
+-		svsk = list_entry(le, struct svc_sock, sk_list);
+-
+-		if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
+-			continue;
+-		if (atomic_read(&svsk->sk_inuse) > 1 || test_bit(SK_BUSY, &svsk->sk_flags))
+-			continue;
+-		atomic_inc(&svsk->sk_inuse);
+-		list_move(le, &to_be_aged);
+-		set_bit(SK_CLOSE, &svsk->sk_flags);
+-		set_bit(SK_DETACHED, &svsk->sk_flags);
+-	}
+-	spin_unlock_bh(&serv->sv_lock);
+-
+-	while (!list_empty(&to_be_aged)) {
+-		le = to_be_aged.next;
+-		/* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
+-		list_del_init(le);
+-		svsk = list_entry(le, struct svc_sock, sk_list);
+-
+-		dprintk("queuing svsk %p for closing, %lu seconds old\n",
+-			svsk, get_seconds() - svsk->sk_lastrecv);
+-
+-		/* a thread will dequeue and close it soon */
+-		svc_sock_enqueue(svsk);
+-		svc_sock_put(svsk);
+-	}
+-
+-	mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
+-}
+-
+-/*
+  * Initialize socket for RPC use and create svc_sock struct
+  * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
+  */
+@@ -1631,7 +1113,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
+ 	struct svc_sock	*svsk;
+ 	struct sock	*inet;
+ 	int		pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
+-	int		is_temporary = flags & SVC_SOCK_TEMPORARY;
+ 
+ 	dprintk("svc: svc_setup_socket %p\n", sock);
+ 	if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
+@@ -1651,44 +1132,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
+ 		return NULL;
  	}
- }
--EXPORT_SYMBOL(rpc_print_iostats);
-+EXPORT_SYMBOL_GPL(rpc_print_iostats);
  
- /*
-  * Register/unregister RPC proc files
-@@ -241,12 +241,14 @@ rpc_proc_register(struct rpc_stat *statp)
+-	set_bit(SK_BUSY, &svsk->sk_flags);
+ 	inet->sk_user_data = svsk;
+ 	svsk->sk_sock = sock;
+ 	svsk->sk_sk = inet;
+ 	svsk->sk_ostate = inet->sk_state_change;
+ 	svsk->sk_odata = inet->sk_data_ready;
+ 	svsk->sk_owspace = inet->sk_write_space;
+-	svsk->sk_server = serv;
+-	atomic_set(&svsk->sk_inuse, 1);
+-	svsk->sk_lastrecv = get_seconds();
+-	spin_lock_init(&svsk->sk_lock);
+-	INIT_LIST_HEAD(&svsk->sk_deferred);
+-	INIT_LIST_HEAD(&svsk->sk_ready);
+-	mutex_init(&svsk->sk_mutex);
+ 
+ 	/* Initialize the socket */
+ 	if (sock->type == SOCK_DGRAM)
+-		svc_udp_init(svsk);
++		svc_udp_init(svsk, serv);
+ 	else
+-		svc_tcp_init(svsk);
+-
+-	spin_lock_bh(&serv->sv_lock);
+-	if (is_temporary) {
+-		set_bit(SK_TEMP, &svsk->sk_flags);
+-		list_add(&svsk->sk_list, &serv->sv_tempsocks);
+-		serv->sv_tmpcnt++;
+-		if (serv->sv_temptimer.function == NULL) {
+-			/* setup timer to age temp sockets */
+-			setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
+-					(unsigned long)serv);
+-			mod_timer(&serv->sv_temptimer,
+-					jiffies + svc_conn_age_period * HZ);
+-		}
+-	} else {
+-		clear_bit(SK_TEMP, &svsk->sk_flags);
+-		list_add(&svsk->sk_list, &serv->sv_permsocks);
+-	}
+-	spin_unlock_bh(&serv->sv_lock);
++		svc_tcp_init(svsk, serv);
+ 
+ 	dprintk("svc: svc_setup_socket created %p (inet %p)\n",
+ 				svsk, svsk->sk_sk);
+@@ -1717,7 +1172,16 @@ int svc_addsock(struct svc_serv *serv,
+ 	else {
+ 		svsk = svc_setup_socket(serv, so, &err, SVC_SOCK_DEFAULTS);
+ 		if (svsk) {
+-			svc_sock_received(svsk);
++			struct sockaddr_storage addr;
++			struct sockaddr *sin = (struct sockaddr *)&addr;
++			int salen;
++			if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
++				svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
++			clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags);
++			spin_lock_bh(&serv->sv_lock);
++			list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks);
++			spin_unlock_bh(&serv->sv_lock);
++			svc_xprt_received(&svsk->sk_xprt);
+ 			err = 0;
+ 		}
+ 	}
+@@ -1733,14 +1197,19 @@ EXPORT_SYMBOL_GPL(svc_addsock);
+ /*
+  * Create socket for RPC service.
+  */
+-static int svc_create_socket(struct svc_serv *serv, int protocol,
+-				struct sockaddr *sin, int len, int flags)
++static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
++					  int protocol,
++					  struct sockaddr *sin, int len,
++					  int flags)
  {
- 	return do_register(statp->program->name, statp, &rpc_proc_fops);
+ 	struct svc_sock	*svsk;
+ 	struct socket	*sock;
+ 	int		error;
+ 	int		type;
+ 	char		buf[RPC_MAX_ADDRBUFLEN];
++	struct sockaddr_storage addr;
++	struct sockaddr *newsin = (struct sockaddr *)&addr;
++	int		newlen;
+ 
+ 	dprintk("svc: svc_create_socket(%s, %d, %s)\n",
+ 			serv->sv_program->pg_name, protocol,
+@@ -1749,13 +1218,13 @@ static int svc_create_socket(struct svc_serv *serv, int protocol,
+ 	if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
+ 		printk(KERN_WARNING "svc: only UDP and TCP "
+ 				"sockets supported\n");
+-		return -EINVAL;
++		return ERR_PTR(-EINVAL);
+ 	}
+ 	type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
+ 
+ 	error = sock_create_kern(sin->sa_family, type, protocol, &sock);
+ 	if (error < 0)
+-		return error;
++		return ERR_PTR(error);
+ 
+ 	svc_reclassify_socket(sock);
+ 
+@@ -1765,203 +1234,55 @@ static int svc_create_socket(struct svc_serv *serv, int protocol,
+ 	if (error < 0)
+ 		goto bummer;
+ 
++	newlen = len;
++	error = kernel_getsockname(sock, newsin, &newlen);
++	if (error < 0)
++		goto bummer;
++
+ 	if (protocol == IPPROTO_TCP) {
+ 		if ((error = kernel_listen(sock, 64)) < 0)
+ 			goto bummer;
+ 	}
+ 
+ 	if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
+-		svc_sock_received(svsk);
+-		return ntohs(inet_sk(svsk->sk_sk)->sport);
++		svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
++		return (struct svc_xprt *)svsk;
+ 	}
+ 
+ bummer:
+ 	dprintk("svc: svc_create_socket error = %d\n", -error);
+ 	sock_release(sock);
+-	return error;
++	return ERR_PTR(error);
  }
-+EXPORT_SYMBOL_GPL(rpc_proc_register);
  
- void
- rpc_proc_unregister(const char *name)
+ /*
+- * Remove a dead socket
++ * Detach the svc_sock from the socket so that no
++ * more callbacks occur.
+  */
+-static void
+-svc_delete_socket(struct svc_sock *svsk)
++static void svc_sock_detach(struct svc_xprt *xprt)
  {
- 	remove_proc_entry(name, proc_net_rpc);
- }
-+EXPORT_SYMBOL_GPL(rpc_proc_unregister);
+-	struct svc_serv	*serv;
+-	struct sock	*sk;
+-
+-	dprintk("svc: svc_delete_socket(%p)\n", svsk);
++	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
++	struct sock *sk = svsk->sk_sk;
  
- struct proc_dir_entry *
- svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
-diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
-index 33d89e8..1a7e309 100644
---- a/net/sunrpc/sunrpc_syms.c
-+++ b/net/sunrpc/sunrpc_syms.c
-@@ -22,45 +22,6 @@
- #include <linux/sunrpc/rpc_pipe_fs.h>
- #include <linux/sunrpc/xprtsock.h>
+-	serv = svsk->sk_server;
+-	sk = svsk->sk_sk;
++	dprintk("svc: svc_sock_detach(%p)\n", svsk);
  
--/* RPC scheduler */
--EXPORT_SYMBOL(rpc_execute);
--EXPORT_SYMBOL(rpc_init_task);
--EXPORT_SYMBOL(rpc_sleep_on);
--EXPORT_SYMBOL(rpc_wake_up_next);
--EXPORT_SYMBOL(rpc_wake_up_task);
--EXPORT_SYMBOL(rpc_wake_up_status);
++	/* put back the old socket callbacks */
+ 	sk->sk_state_change = svsk->sk_ostate;
+ 	sk->sk_data_ready = svsk->sk_odata;
+ 	sk->sk_write_space = svsk->sk_owspace;
 -
--/* RPC client functions */
--EXPORT_SYMBOL(rpc_clone_client);
--EXPORT_SYMBOL(rpc_bind_new_program);
--EXPORT_SYMBOL(rpc_shutdown_client);
--EXPORT_SYMBOL(rpc_killall_tasks);
--EXPORT_SYMBOL(rpc_call_sync);
--EXPORT_SYMBOL(rpc_call_async);
--EXPORT_SYMBOL(rpc_call_setup);
--EXPORT_SYMBOL(rpc_clnt_sigmask);
--EXPORT_SYMBOL(rpc_clnt_sigunmask);
--EXPORT_SYMBOL(rpc_delay);
--EXPORT_SYMBOL(rpc_restart_call);
--EXPORT_SYMBOL(rpc_setbufsize);
--EXPORT_SYMBOL(rpc_unlink);
--EXPORT_SYMBOL(rpc_wake_up);
--EXPORT_SYMBOL(rpc_queue_upcall);
--EXPORT_SYMBOL(rpc_mkpipe);
+-	spin_lock_bh(&serv->sv_lock);
 -
--/* Client transport */
--EXPORT_SYMBOL(xprt_set_timeout);
+-	if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
+-		list_del_init(&svsk->sk_list);
+-	/*
+-	 * We used to delete the svc_sock from whichever list
+-	 * it's sk_ready node was on, but we don't actually
+-	 * need to.  This is because the only time we're called
+-	 * while still attached to a queue, the queue itself
+-	 * is about to be destroyed (in svc_destroy).
+-	 */
+-	if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) {
+-		BUG_ON(atomic_read(&svsk->sk_inuse)<2);
+-		atomic_dec(&svsk->sk_inuse);
+-		if (test_bit(SK_TEMP, &svsk->sk_flags))
+-			serv->sv_tmpcnt--;
+-	}
 -
--/* Client credential cache */
--EXPORT_SYMBOL(rpcauth_register);
--EXPORT_SYMBOL(rpcauth_unregister);
--EXPORT_SYMBOL(rpcauth_create);
--EXPORT_SYMBOL(rpcauth_lookupcred);
--EXPORT_SYMBOL(rpcauth_lookup_credcache);
--EXPORT_SYMBOL(rpcauth_destroy_credcache);
--EXPORT_SYMBOL(rpcauth_init_credcache);
--EXPORT_SYMBOL(put_rpccred);
+-	spin_unlock_bh(&serv->sv_lock);
+-}
 -
- /* RPC server stuff */
- EXPORT_SYMBOL(svc_create);
- EXPORT_SYMBOL(svc_create_thread);
-@@ -81,8 +42,6 @@ EXPORT_SYMBOL(svc_set_client);
- 
- /* RPC statistics */
- #ifdef CONFIG_PROC_FS
--EXPORT_SYMBOL(rpc_proc_register);
--EXPORT_SYMBOL(rpc_proc_unregister);
- EXPORT_SYMBOL(svc_proc_register);
- EXPORT_SYMBOL(svc_proc_unregister);
- EXPORT_SYMBOL(svc_seq_show);
-@@ -105,31 +64,6 @@ EXPORT_SYMBOL(qword_get);
- EXPORT_SYMBOL(svcauth_unix_purge);
- EXPORT_SYMBOL(unix_domain_find);
- 
--/* Generic XDR */
--EXPORT_SYMBOL(xdr_encode_string);
--EXPORT_SYMBOL(xdr_decode_string_inplace);
--EXPORT_SYMBOL(xdr_decode_netobj);
--EXPORT_SYMBOL(xdr_encode_netobj);
--EXPORT_SYMBOL(xdr_encode_pages);
--EXPORT_SYMBOL(xdr_inline_pages);
--EXPORT_SYMBOL(xdr_shift_buf);
--EXPORT_SYMBOL(xdr_encode_word);
--EXPORT_SYMBOL(xdr_decode_word);
--EXPORT_SYMBOL(xdr_encode_array2);
--EXPORT_SYMBOL(xdr_decode_array2);
--EXPORT_SYMBOL(xdr_buf_from_iov);
--EXPORT_SYMBOL(xdr_buf_subsegment);
--EXPORT_SYMBOL(xdr_buf_read_netobj);
--EXPORT_SYMBOL(read_bytes_from_xdr_buf);
+-static void svc_close_socket(struct svc_sock *svsk)
+-{
+-	set_bit(SK_CLOSE, &svsk->sk_flags);
+-	if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
+-		/* someone else will have to effect the close */
+-		return;
 -
--/* Debugging symbols */
--#ifdef RPC_DEBUG
--EXPORT_SYMBOL(rpc_debug);
--EXPORT_SYMBOL(nfs_debug);
--EXPORT_SYMBOL(nfsd_debug);
--EXPORT_SYMBOL(nlm_debug);
--#endif
+-	atomic_inc(&svsk->sk_inuse);
+-	svc_delete_socket(svsk);
+-	clear_bit(SK_BUSY, &svsk->sk_flags);
+-	svc_sock_put(svsk);
+-}
 -
- extern struct cache_detail ip_map_cache, unix_gid_cache;
+-void svc_force_close_socket(struct svc_sock *svsk)
+-{
+-	set_bit(SK_CLOSE, &svsk->sk_flags);
+-	if (test_bit(SK_BUSY, &svsk->sk_flags)) {
+-		/* Waiting to be processed, but no threads left,
+-		 * So just remove it from the waiting list
+-		 */
+-		list_del_init(&svsk->sk_ready);
+-		clear_bit(SK_BUSY, &svsk->sk_flags);
+-	}
+-	svc_close_socket(svsk);
+-}
+-
+-/**
+- * svc_makesock - Make a socket for nfsd and lockd
+- * @serv: RPC server structure
+- * @protocol: transport protocol to use
+- * @port: port to use
+- * @flags: requested socket characteristics
+- *
+- */
+-int svc_makesock(struct svc_serv *serv, int protocol, unsigned short port,
+-			int flags)
+-{
+-	struct sockaddr_in sin = {
+-		.sin_family		= AF_INET,
+-		.sin_addr.s_addr	= INADDR_ANY,
+-		.sin_port		= htons(port),
+-	};
+-
+-	dprintk("svc: creating socket proto = %d\n", protocol);
+-	return svc_create_socket(serv, protocol, (struct sockaddr *) &sin,
+-							sizeof(sin), flags);
+ }
  
- static int __init
-diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
-index a4a6bf7..4ad5fbb 100644
---- a/net/sunrpc/svc.c
-+++ b/net/sunrpc/svc.c
-@@ -18,6 +18,7 @@
- #include <linux/mm.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
-+#include <linux/sched.h>
+ /*
+- * Handle defer and revisit of requests
++ * Free the svc_sock's socket resources and the svc_sock itself.
+  */
+-
+-static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
++static void svc_sock_free(struct svc_xprt *xprt)
+ {
+-	struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
+-	struct svc_sock *svsk;
++	struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
++	dprintk("svc: svc_sock_free(%p)\n", svsk);
  
- #include <linux/sunrpc/types.h>
- #include <linux/sunrpc/xdr.h>
+-	if (too_many) {
+-		svc_sock_put(dr->svsk);
+-		kfree(dr);
+-		return;
+-	}
+-	dprintk("revisit queued\n");
+-	svsk = dr->svsk;
+-	dr->svsk = NULL;
+-	spin_lock(&svsk->sk_lock);
+-	list_add(&dr->handle.recent, &svsk->sk_deferred);
+-	spin_unlock(&svsk->sk_lock);
+-	set_bit(SK_DEFERRED, &svsk->sk_flags);
+-	svc_sock_enqueue(svsk);
+-	svc_sock_put(svsk);
+-}
+-
+-static struct cache_deferred_req *
+-svc_defer(struct cache_req *req)
+-{
+-	struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
+-	int size = sizeof(struct svc_deferred_req) + (rqstp->rq_arg.len);
+-	struct svc_deferred_req *dr;
+-
+-	if (rqstp->rq_arg.page_len)
+-		return NULL; /* if more than a page, give up FIXME */
+-	if (rqstp->rq_deferred) {
+-		dr = rqstp->rq_deferred;
+-		rqstp->rq_deferred = NULL;
+-	} else {
+-		int skip  = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
+-		/* FIXME maybe discard if size too large */
+-		dr = kmalloc(size, GFP_KERNEL);
+-		if (dr == NULL)
+-			return NULL;
+-
+-		dr->handle.owner = rqstp->rq_server;
+-		dr->prot = rqstp->rq_prot;
+-		memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
+-		dr->addrlen = rqstp->rq_addrlen;
+-		dr->daddr = rqstp->rq_daddr;
+-		dr->argslen = rqstp->rq_arg.len >> 2;
+-		memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2);
+-	}
+-	atomic_inc(&rqstp->rq_sock->sk_inuse);
+-	dr->svsk = rqstp->rq_sock;
+-
+-	dr->handle.revisit = svc_revisit;
+-	return &dr->handle;
+-}
+-
+-/*
+- * recv data from a deferred request into an active one
+- */
+-static int svc_deferred_recv(struct svc_rqst *rqstp)
+-{
+-	struct svc_deferred_req *dr = rqstp->rq_deferred;
+-
+-	rqstp->rq_arg.head[0].iov_base = dr->args;
+-	rqstp->rq_arg.head[0].iov_len = dr->argslen<<2;
+-	rqstp->rq_arg.page_len = 0;
+-	rqstp->rq_arg.len = dr->argslen<<2;
+-	rqstp->rq_prot        = dr->prot;
+-	memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
+-	rqstp->rq_addrlen     = dr->addrlen;
+-	rqstp->rq_daddr       = dr->daddr;
+-	rqstp->rq_respages    = rqstp->rq_pages;
+-	return dr->argslen<<2;
+-}
+-
+-
+-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
+-{
+-	struct svc_deferred_req *dr = NULL;
+-
+-	if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
+-		return NULL;
+-	spin_lock(&svsk->sk_lock);
+-	clear_bit(SK_DEFERRED, &svsk->sk_flags);
+-	if (!list_empty(&svsk->sk_deferred)) {
+-		dr = list_entry(svsk->sk_deferred.next,
+-				struct svc_deferred_req,
+-				handle.recent);
+-		list_del_init(&dr->handle.recent);
+-		set_bit(SK_DEFERRED, &svsk->sk_flags);
+-	}
+-	spin_unlock(&svsk->sk_lock);
+-	return dr;
++	if (svsk->sk_sock->file)
++		sockfd_put(svsk->sk_sock);
++	else
++		sock_release(svsk->sk_sock);
++	kfree(svsk);
+ }
 diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
-index 2be714e..bada7de 100644
+index 2be714e..0f8c439 100644
 --- a/net/sunrpc/sysctl.c
 +++ b/net/sunrpc/sysctl.c
-@@ -23,9 +23,16 @@
+@@ -18,14 +18,22 @@
+ #include <linux/sunrpc/types.h>
+ #include <linux/sunrpc/sched.h>
+ #include <linux/sunrpc/stats.h>
++#include <linux/sunrpc/svc_xprt.h>
+ 
+ /*
   * Declare the debug flags here
   */
  unsigned int	rpc_debug;
@@ -922869,8 +994673,52 @@
  
  #ifdef RPC_DEBUG
  
+@@ -48,6 +56,30 @@ rpc_unregister_sysctl(void)
+ 	}
+ }
+ 
++static int proc_do_xprt(ctl_table *table, int write, struct file *file,
++			void __user *buffer, size_t *lenp, loff_t *ppos)
++{
++	char tmpbuf[256];
++	int len;
++	if ((*ppos && !write) || !*lenp) {
++		*lenp = 0;
++		return 0;
++	}
++	if (write)
++		return -EINVAL;
++	else {
++		len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
++		if (!access_ok(VERIFY_WRITE, buffer, len))
++			return -EFAULT;
++
++		if (__copy_to_user(buffer, tmpbuf, len))
++			return -EFAULT;
++	}
++	*lenp -= len;
++	*ppos += len;
++	return 0;
++}
++
+ static int
+ proc_dodebug(ctl_table *table, int write, struct file *file,
+ 				void __user *buffer, size_t *lenp, loff_t *ppos)
+@@ -140,6 +172,12 @@ static ctl_table debug_table[] = {
+ 		.mode		= 0644,
+ 		.proc_handler	= &proc_dodebug
+ 	},
++	{
++		.procname	= "transports",
++		.maxlen		= 256,
++		.mode		= 0444,
++		.proc_handler	= &proc_do_xprt,
++	},
+ 	{ .ctl_name = 0 }
+ };
+ 
 diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
-index fdc5e6d..5426406 100644
+index fdc5e6d..995c3fd 100644
 --- a/net/sunrpc/xdr.c
 +++ b/net/sunrpc/xdr.c
 @@ -28,6 +28,7 @@ xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
@@ -922889,15 +994737,25 @@
  
  /**
   * xdr_encode_opaque_fixed - Encode fixed length opaque data
-@@ -91,6 +93,7 @@ xdr_encode_string(__be32 *p, const char *string)
+@@ -91,18 +93,22 @@ xdr_encode_string(__be32 *p, const char *string)
  {
  	return xdr_encode_array(p, string, strlen(string));
  }
 +EXPORT_SYMBOL(xdr_encode_string);
  
  __be32 *
- xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
-@@ -103,6 +106,7 @@ xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
+-xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
++xdr_decode_string_inplace(__be32 *p, char **sp,
++			  unsigned int *lenp, unsigned int maxlen)
+ {
+-	unsigned int	len;
++	u32 len;
+ 
+-	if ((len = ntohl(*p++)) > maxlen)
++	len = ntohl(*p++);
++	if (len > maxlen)
+ 		return NULL;
+ 	*lenp = len;
  	*sp = (char *) p;
  	return p + XDR_QUADLEN(len);
  }
@@ -922905,7 +994763,7 @@
  
  void
  xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
-@@ -130,6 +134,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
+@@ -130,6 +136,7 @@ xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
  	xdr->buflen += len;
  	xdr->len += len;
  }
@@ -922913,7 +994771,7 @@
  
  void
  xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
-@@ -151,7 +156,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
+@@ -151,7 +158,7 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
  
  	xdr->buflen += len;
  }
@@ -922922,7 +994780,7 @@
  
  /*
   * Helper routines for doing 'memmove' like operations on a struct xdr_buf
-@@ -418,6 +423,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
+@@ -418,6 +425,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
  {
  	xdr_shrink_bufhead(buf, len);
  }
@@ -922930,7 +994788,7 @@
  
  /**
   * xdr_init_encode - Initialize a struct xdr_stream for sending data.
-@@ -639,6 +645,7 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
+@@ -639,6 +647,7 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
  	buf->page_len = 0;
  	buf->buflen = buf->len = iov->iov_len;
  }
@@ -922938,7 +994796,7 @@
  
  /* Sets subbuf to the portion of buf of length len beginning base bytes
   * from the start of buf. Returns -1 if base of length are out of bounds. */
-@@ -687,6 +694,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
+@@ -687,6 +696,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
  		return -1;
  	return 0;
  }
@@ -922946,7 +994804,7 @@
  
  static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
  {
-@@ -717,6 +725,7 @@ int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, u
+@@ -717,6 +727,7 @@ int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, u
  	__read_bytes_from_xdr_buf(&subbuf, obj, len);
  	return 0;
  }
@@ -922954,7 +994812,7 @@
  
  static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
  {
-@@ -760,6 +769,7 @@ xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
+@@ -760,6 +771,7 @@ xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
  	*obj = ntohl(raw);
  	return 0;
  }
@@ -922962,7 +994820,7 @@
  
  int
  xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
-@@ -768,6 +778,7 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
+@@ -768,6 +780,7 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
  
  	return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
  }
@@ -922970,7 +994828,7 @@
  
  /* If the netobj starting offset bytes from the start of xdr_buf is contained
   * entirely in the head or the tail, set object to point to it; otherwise
-@@ -805,6 +816,7 @@ int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned in
+@@ -805,6 +818,7 @@ int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned in
  	__read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);
  	return 0;
  }
@@ -922978,7 +994836,7 @@
  
  /* Returns 0 on success, or else a negative error code. */
  static int
-@@ -1010,6 +1022,7 @@ xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
+@@ -1010,6 +1024,7 @@ xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
  
  	return xdr_xcode_array2(buf, base, desc, 0);
  }
@@ -922986,7 +994844,7 @@
  
  int
  xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
-@@ -1021,6 +1034,7 @@ xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
+@@ -1021,6 +1036,7 @@ xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
  
  	return xdr_xcode_array2(buf, base, desc, 1);
  }
@@ -923122,6 +994980,19 @@
  	xprt->last_used = jiffies;
  	xprt->cwnd = RPC_INITCWND;
  	xprt->bind_index = 0;
+diff --git a/net/sunrpc/xprtrdma/Makefile b/net/sunrpc/xprtrdma/Makefile
+index 264f0fe..5a8f268 100644
+--- a/net/sunrpc/xprtrdma/Makefile
++++ b/net/sunrpc/xprtrdma/Makefile
+@@ -1,3 +1,8 @@
+ obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
+ 
+ xprtrdma-y := transport.o rpc_rdma.o verbs.o
++
++obj-$(CONFIG_SUNRPC_XPRT_RDMA) += svcrdma.o
++
++svcrdma-y := svc_rdma.o svc_rdma_transport.o \
++	svc_rdma_marshal.o svc_rdma_sendto.o svc_rdma_recvfrom.o
 diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
 index ee8de7a..e55427f 100644
 --- a/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -923185,6 +995056,2900 @@
  {
  	unsigned int i, total_len;
  	struct rpcrdma_write_chunk *cur_wchunk;
+diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
+new file mode 100644
+index 0000000..88c0ca2
+--- /dev/null
++++ b/net/sunrpc/xprtrdma/svc_rdma.c
+@@ -0,0 +1,266 @@
++/*
++ * Copyright (c) 2005-2006 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/sysctl.h>
++#include <linux/sunrpc/clnt.h>
++#include <linux/sunrpc/sched.h>
++#include <linux/sunrpc/svc_rdma.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++/* RPC/RDMA parameters */
++unsigned int svcrdma_ord = RPCRDMA_ORD;
++static unsigned int min_ord = 1;
++static unsigned int max_ord = 4096;
++unsigned int svcrdma_max_requests = RPCRDMA_MAX_REQUESTS;
++static unsigned int min_max_requests = 4;
++static unsigned int max_max_requests = 16384;
++unsigned int svcrdma_max_req_size = RPCRDMA_MAX_REQ_SIZE;
++static unsigned int min_max_inline = 4096;
++static unsigned int max_max_inline = 65536;
++
++atomic_t rdma_stat_recv;
++atomic_t rdma_stat_read;
++atomic_t rdma_stat_write;
++atomic_t rdma_stat_sq_starve;
++atomic_t rdma_stat_rq_starve;
++atomic_t rdma_stat_rq_poll;
++atomic_t rdma_stat_rq_prod;
++atomic_t rdma_stat_sq_poll;
++atomic_t rdma_stat_sq_prod;
++
++/*
++ * This function implements reading and resetting an atomic_t stat
++ * variable through read/write to a proc file. Any write to the file
++ * resets the associated statistic to zero. Any read returns it's
++ * current value.
++ */
++static int read_reset_stat(ctl_table *table, int write,
++			   struct file *filp, void __user *buffer, size_t *lenp,
++			   loff_t *ppos)
++{
++	atomic_t *stat = (atomic_t *)table->data;
++
++	if (!stat)
++		return -EINVAL;
++
++	if (write)
++		atomic_set(stat, 0);
++	else {
++		char str_buf[32];
++		char *data;
++		int len = snprintf(str_buf, 32, "%d\n", atomic_read(stat));
++		if (len >= 32)
++			return -EFAULT;
++		len = strlen(str_buf);
++		if (*ppos > len) {
++			*lenp = 0;
++			return 0;
++		}
++		data = &str_buf[*ppos];
++		len -= *ppos;
++		if (len > *lenp)
++			len = *lenp;
++		if (len && copy_to_user(buffer, str_buf, len))
++			return -EFAULT;
++		*lenp = len;
++		*ppos += len;
++	}
++	return 0;
++}
++
++static struct ctl_table_header *svcrdma_table_header;
++static ctl_table svcrdma_parm_table[] = {
++	{
++		.procname	= "max_requests",
++		.data		= &svcrdma_max_requests,
++		.maxlen		= sizeof(unsigned int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec_minmax,
++		.strategy	= &sysctl_intvec,
++		.extra1		= &min_max_requests,
++		.extra2		= &max_max_requests
++	},
++	{
++		.procname	= "max_req_size",
++		.data		= &svcrdma_max_req_size,
++		.maxlen		= sizeof(unsigned int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec_minmax,
++		.strategy	= &sysctl_intvec,
++		.extra1		= &min_max_inline,
++		.extra2		= &max_max_inline
++	},
++	{
++		.procname	= "max_outbound_read_requests",
++		.data		= &svcrdma_ord,
++		.maxlen		= sizeof(unsigned int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec_minmax,
++		.strategy	= &sysctl_intvec,
++		.extra1		= &min_ord,
++		.extra2		= &max_ord,
++	},
++
++	{
++		.procname	= "rdma_stat_read",
++		.data		= &rdma_stat_read,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_recv",
++		.data		= &rdma_stat_recv,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_write",
++		.data		= &rdma_stat_write,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_sq_starve",
++		.data		= &rdma_stat_sq_starve,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_rq_starve",
++		.data		= &rdma_stat_rq_starve,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_rq_poll",
++		.data		= &rdma_stat_rq_poll,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_rq_prod",
++		.data		= &rdma_stat_rq_prod,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_sq_poll",
++		.data		= &rdma_stat_sq_poll,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.procname	= "rdma_stat_sq_prod",
++		.data		= &rdma_stat_sq_prod,
++		.maxlen		= sizeof(atomic_t),
++		.mode		= 0644,
++		.proc_handler	= &read_reset_stat,
++	},
++	{
++		.ctl_name = 0,
++	},
++};
++
++static ctl_table svcrdma_table[] = {
++	{
++		.procname	= "svc_rdma",
++		.mode		= 0555,
++		.child		= svcrdma_parm_table
++	},
++	{
++		.ctl_name = 0,
++	},
++};
++
++static ctl_table svcrdma_root_table[] = {
++	{
++		.ctl_name	= CTL_SUNRPC,
++		.procname	= "sunrpc",
++		.mode		= 0555,
++		.child		= svcrdma_table
++	},
++	{
++		.ctl_name = 0,
++	},
++};
++
++void svc_rdma_cleanup(void)
++{
++	dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
++	if (svcrdma_table_header) {
++		unregister_sysctl_table(svcrdma_table_header);
++		svcrdma_table_header = NULL;
++	}
++	svc_unreg_xprt_class(&svc_rdma_class);
++}
++
++int svc_rdma_init(void)
++{
++	dprintk("SVCRDMA Module Init, register RPC RDMA transport\n");
++	dprintk("\tsvcrdma_ord      : %d\n", svcrdma_ord);
++	dprintk("\tmax_requests     : %d\n", svcrdma_max_requests);
++	dprintk("\tsq_depth         : %d\n",
++		svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
++	dprintk("\tmax_inline       : %d\n", svcrdma_max_req_size);
++	if (!svcrdma_table_header)
++		svcrdma_table_header =
++			register_sysctl_table(svcrdma_root_table);
++
++	/* Register RDMA with the SVC transport switch */
++	svc_reg_xprt_class(&svc_rdma_class);
++	return 0;
++}
++MODULE_AUTHOR("Tom Tucker <tom at opengridcomputing.com>");
++MODULE_DESCRIPTION("SVC RDMA Transport");
++MODULE_LICENSE("Dual BSD/GPL");
++module_init(svc_rdma_init);
++module_exit(svc_rdma_cleanup);
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+new file mode 100644
+index 0000000..9530ef2
+--- /dev/null
++++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+@@ -0,0 +1,412 @@
++/*
++ * Copyright (c) 2005-2006 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#include <linux/sunrpc/xdr.h>
++#include <linux/sunrpc/debug.h>
++#include <asm/unaligned.h>
++#include <linux/sunrpc/rpc_rdma.h>
++#include <linux/sunrpc/svc_rdma.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++/*
++ * Decodes a read chunk list. The expected format is as follows:
++ *    descrim  : xdr_one
++ *    position : u32 offset into XDR stream
++ *    handle   : u32 RKEY
++ *    . . .
++ *  end-of-list: xdr_zero
++ */
++static u32 *decode_read_list(u32 *va, u32 *vaend)
++{
++	struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
++
++	while (ch->rc_discrim != xdr_zero) {
++		u64 ch_offset;
++
++		if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
++		    (unsigned long)vaend) {
++			dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
++			return NULL;
++		}
++
++		ch->rc_discrim = ntohl(ch->rc_discrim);
++		ch->rc_position = ntohl(ch->rc_position);
++		ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle);
++		ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length);
++		va = (u32 *)&ch->rc_target.rs_offset;
++		xdr_decode_hyper(va, &ch_offset);
++		put_unaligned(ch_offset, (u64 *)va);
++		ch++;
++	}
++	return (u32 *)&ch->rc_position;
++}
++
++/*
++ * Determine number of chunks and total bytes in chunk list. The chunk
++ * list has already been verified to fit within the RPCRDMA header.
++ */
++void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
++			       int *ch_count, int *byte_count)
++{
++	/* compute the number of bytes represented by read chunks */
++	*byte_count = 0;
++	*ch_count = 0;
++	for (; ch->rc_discrim != 0; ch++) {
++		*byte_count = *byte_count + ch->rc_target.rs_length;
++		*ch_count = *ch_count + 1;
++	}
++}
++
++/*
++ * Decodes a write chunk list. The expected format is as follows:
++ *    descrim  : xdr_one
++ *    nchunks  : <count>
++ *       handle   : u32 RKEY              ---+
++ *       length   : u32 <len of segment>     |
++ *       offset   : remove va                + <count>
++ *       . . .                               |
++ *                                        ---+
++ */
++static u32 *decode_write_list(u32 *va, u32 *vaend)
++{
++	int ch_no;
++	struct rpcrdma_write_array *ary =
++		(struct rpcrdma_write_array *)va;
++
++	/* Check for not write-array */
++	if (ary->wc_discrim == xdr_zero)
++		return (u32 *)&ary->wc_nchunks;
++
++	if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
++	    (unsigned long)vaend) {
++		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
++		return NULL;
++	}
++	ary->wc_discrim = ntohl(ary->wc_discrim);
++	ary->wc_nchunks = ntohl(ary->wc_nchunks);
++	if (((unsigned long)&ary->wc_array[0] +
++	     (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
++	    (unsigned long)vaend) {
++		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
++			ary, ary->wc_nchunks, vaend);
++		return NULL;
++	}
++	for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
++		u64 ch_offset;
++
++		ary->wc_array[ch_no].wc_target.rs_handle =
++			ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
++		ary->wc_array[ch_no].wc_target.rs_length =
++			ntohl(ary->wc_array[ch_no].wc_target.rs_length);
++		va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
++		xdr_decode_hyper(va, &ch_offset);
++		put_unaligned(ch_offset, (u64 *)va);
++	}
++
++	/*
++	 * rs_length is the 2nd 4B field in wc_target and taking its
++	 * address skips the list terminator
++	 */
++	return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length;
++}
++
++static u32 *decode_reply_array(u32 *va, u32 *vaend)
++{
++	int ch_no;
++	struct rpcrdma_write_array *ary =
++		(struct rpcrdma_write_array *)va;
++
++	/* Check for no reply-array */
++	if (ary->wc_discrim == xdr_zero)
++		return (u32 *)&ary->wc_nchunks;
++
++	if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
++	    (unsigned long)vaend) {
++		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
++		return NULL;
++	}
++	ary->wc_discrim = ntohl(ary->wc_discrim);
++	ary->wc_nchunks = ntohl(ary->wc_nchunks);
++	if (((unsigned long)&ary->wc_array[0] +
++	     (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
++	    (unsigned long)vaend) {
++		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
++			ary, ary->wc_nchunks, vaend);
++		return NULL;
++	}
++	for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
++		u64 ch_offset;
++
++		ary->wc_array[ch_no].wc_target.rs_handle =
++			ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
++		ary->wc_array[ch_no].wc_target.rs_length =
++			ntohl(ary->wc_array[ch_no].wc_target.rs_length);
++		va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
++		xdr_decode_hyper(va, &ch_offset);
++		put_unaligned(ch_offset, (u64 *)va);
++	}
++
++	return (u32 *)&ary->wc_array[ch_no];
++}
++
++int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
++			    struct svc_rqst *rqstp)
++{
++	struct rpcrdma_msg *rmsgp = NULL;
++	u32 *va;
++	u32 *vaend;
++	u32 hdr_len;
++
++	rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
++
++	/* Verify that there's enough bytes for header + something */
++	if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_MIN) {
++		dprintk("svcrdma: header too short = %d\n",
++			rqstp->rq_arg.len);
++		return -EINVAL;
++	}
++
++	/* Decode the header */
++	rmsgp->rm_xid = ntohl(rmsgp->rm_xid);
++	rmsgp->rm_vers = ntohl(rmsgp->rm_vers);
++	rmsgp->rm_credit = ntohl(rmsgp->rm_credit);
++	rmsgp->rm_type = ntohl(rmsgp->rm_type);
++
++	if (rmsgp->rm_vers != RPCRDMA_VERSION)
++		return -ENOSYS;
++
++	/* Pull in the extra for the padded case and bump our pointer */
++	if (rmsgp->rm_type == RDMA_MSGP) {
++		int hdrlen;
++		rmsgp->rm_body.rm_padded.rm_align =
++			ntohl(rmsgp->rm_body.rm_padded.rm_align);
++		rmsgp->rm_body.rm_padded.rm_thresh =
++			ntohl(rmsgp->rm_body.rm_padded.rm_thresh);
++
++		va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
++		rqstp->rq_arg.head[0].iov_base = va;
++		hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
++		rqstp->rq_arg.head[0].iov_len -= hdrlen;
++		if (hdrlen > rqstp->rq_arg.len)
++			return -EINVAL;
++		return hdrlen;
++	}
++
++	/* The chunk list may contain either a read chunk list or a write
++	 * chunk list and a reply chunk list.
++	 */
++	va = &rmsgp->rm_body.rm_chunks[0];
++	vaend = (u32 *)((unsigned long)rmsgp + rqstp->rq_arg.len);
++	va = decode_read_list(va, vaend);
++	if (!va)
++		return -EINVAL;
++	va = decode_write_list(va, vaend);
++	if (!va)
++		return -EINVAL;
++	va = decode_reply_array(va, vaend);
++	if (!va)
++		return -EINVAL;
++
++	rqstp->rq_arg.head[0].iov_base = va;
++	hdr_len = (unsigned long)va - (unsigned long)rmsgp;
++	rqstp->rq_arg.head[0].iov_len -= hdr_len;
++
++	*rdma_req = rmsgp;
++	return hdr_len;
++}
++
++int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *rqstp)
++{
++	struct rpcrdma_msg *rmsgp = NULL;
++	struct rpcrdma_read_chunk *ch;
++	struct rpcrdma_write_array *ary;
++	u32 *va;
++	u32 hdrlen;
++
++	dprintk("svcrdma: processing deferred RDMA header on rqstp=%p\n",
++		rqstp);
++	rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
++
++	/* Pull in the extra for the padded case and bump our pointer */
++	if (rmsgp->rm_type == RDMA_MSGP) {
++		va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
++		rqstp->rq_arg.head[0].iov_base = va;
++		hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
++		rqstp->rq_arg.head[0].iov_len -= hdrlen;
++		return hdrlen;
++	}
++
++	/*
++	 * Skip all chunks to find RPC msg. These were previously processed
++	 */
++	va = &rmsgp->rm_body.rm_chunks[0];
++
++	/* Skip read-list */
++	for (ch = (struct rpcrdma_read_chunk *)va;
++	     ch->rc_discrim != xdr_zero; ch++);
++	va = (u32 *)&ch->rc_position;
++
++	/* Skip write-list */
++	ary = (struct rpcrdma_write_array *)va;
++	if (ary->wc_discrim == xdr_zero)
++		va = (u32 *)&ary->wc_nchunks;
++	else
++		/*
++		 * rs_length is the 2nd 4B field in wc_target and taking its
++		 * address skips the list terminator
++		 */
++		va = (u32 *)&ary->wc_array[ary->wc_nchunks].wc_target.rs_length;
++
++	/* Skip reply-array */
++	ary = (struct rpcrdma_write_array *)va;
++	if (ary->wc_discrim == xdr_zero)
++		va = (u32 *)&ary->wc_nchunks;
++	else
++		va = (u32 *)&ary->wc_array[ary->wc_nchunks];
++
++	rqstp->rq_arg.head[0].iov_base = va;
++	hdrlen = (unsigned long)va - (unsigned long)rmsgp;
++	rqstp->rq_arg.head[0].iov_len -= hdrlen;
++
++	return hdrlen;
++}
++
++int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,
++			      struct rpcrdma_msg *rmsgp,
++			      enum rpcrdma_errcode err, u32 *va)
++{
++	u32 *startp = va;
++
++	*va++ = htonl(rmsgp->rm_xid);
++	*va++ = htonl(rmsgp->rm_vers);
++	*va++ = htonl(xprt->sc_max_requests);
++	*va++ = htonl(RDMA_ERROR);
++	*va++ = htonl(err);
++	if (err == ERR_VERS) {
++		*va++ = htonl(RPCRDMA_VERSION);
++		*va++ = htonl(RPCRDMA_VERSION);
++	}
++
++	return (int)((unsigned long)va - (unsigned long)startp);
++}
++
++int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *rmsgp)
++{
++	struct rpcrdma_write_array *wr_ary;
++
++	/* There is no read-list in a reply */
++
++	/* skip write list */
++	wr_ary = (struct rpcrdma_write_array *)
++		&rmsgp->rm_body.rm_chunks[1];
++	if (wr_ary->wc_discrim)
++		wr_ary = (struct rpcrdma_write_array *)
++			&wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)].
++			wc_target.rs_length;
++	else
++		wr_ary = (struct rpcrdma_write_array *)
++			&wr_ary->wc_nchunks;
++
++	/* skip reply array */
++	if (wr_ary->wc_discrim)
++		wr_ary = (struct rpcrdma_write_array *)
++			&wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)];
++	else
++		wr_ary = (struct rpcrdma_write_array *)
++			&wr_ary->wc_nchunks;
++
++	return (unsigned long) wr_ary - (unsigned long) rmsgp;
++}
++
++void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *rmsgp, int chunks)
++{
++	struct rpcrdma_write_array *ary;
++
++	/* no read-list */
++	rmsgp->rm_body.rm_chunks[0] = xdr_zero;
++
++	/* write-array discrim */
++	ary = (struct rpcrdma_write_array *)
++		&rmsgp->rm_body.rm_chunks[1];
++	ary->wc_discrim = xdr_one;
++	ary->wc_nchunks = htonl(chunks);
++
++	/* write-list terminator */
++	ary->wc_array[chunks].wc_target.rs_handle = xdr_zero;
++
++	/* reply-array discriminator */
++	ary->wc_array[chunks].wc_target.rs_length = xdr_zero;
++}
++
++void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
++				 int chunks)
++{
++	ary->wc_discrim = xdr_one;
++	ary->wc_nchunks = htonl(chunks);
++}
++
++void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
++				     int chunk_no,
++				     u32 rs_handle, u64 rs_offset,
++				     u32 write_len)
++{
++	struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
++	seg->rs_handle = htonl(rs_handle);
++	seg->rs_length = htonl(write_len);
++	xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset);
++}
++
++void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
++				  struct rpcrdma_msg *rdma_argp,
++				  struct rpcrdma_msg *rdma_resp,
++				  enum rpcrdma_proc rdma_type)
++{
++	rdma_resp->rm_xid = htonl(rdma_argp->rm_xid);
++	rdma_resp->rm_vers = htonl(rdma_argp->rm_vers);
++	rdma_resp->rm_credit = htonl(xprt->sc_max_requests);
++	rdma_resp->rm_type = htonl(rdma_type);
++
++	/* Encode <nul> chunks lists */
++	rdma_resp->rm_body.rm_chunks[0] = xdr_zero;
++	rdma_resp->rm_body.rm_chunks[1] = xdr_zero;
++	rdma_resp->rm_body.rm_chunks[2] = xdr_zero;
++}
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+new file mode 100644
+index 0000000..ab54a73
+--- /dev/null
++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+@@ -0,0 +1,586 @@
++/*
++ * Copyright (c) 2005-2006 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#include <linux/sunrpc/debug.h>
++#include <linux/sunrpc/rpc_rdma.h>
++#include <linux/spinlock.h>
++#include <asm/unaligned.h>
++#include <rdma/ib_verbs.h>
++#include <rdma/rdma_cm.h>
++#include <linux/sunrpc/svc_rdma.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++/*
++ * Replace the pages in the rq_argpages array with the pages from the SGE in
++ * the RDMA_RECV completion. The SGL should contain full pages up until the
++ * last one.
++ */
++static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
++			       struct svc_rdma_op_ctxt *ctxt,
++			       u32 byte_count)
++{
++	struct page *page;
++	u32 bc;
++	int sge_no;
++
++	/* Swap the page in the SGE with the page in argpages */
++	page = ctxt->pages[0];
++	put_page(rqstp->rq_pages[0]);
++	rqstp->rq_pages[0] = page;
++
++	/* Set up the XDR head */
++	rqstp->rq_arg.head[0].iov_base = page_address(page);
++	rqstp->rq_arg.head[0].iov_len = min(byte_count, ctxt->sge[0].length);
++	rqstp->rq_arg.len = byte_count;
++	rqstp->rq_arg.buflen = byte_count;
++
++	/* Compute bytes past head in the SGL */
++	bc = byte_count - rqstp->rq_arg.head[0].iov_len;
++
++	/* If data remains, store it in the pagelist */
++	rqstp->rq_arg.page_len = bc;
++	rqstp->rq_arg.page_base = 0;
++	rqstp->rq_arg.pages = &rqstp->rq_pages[1];
++	sge_no = 1;
++	while (bc && sge_no < ctxt->count) {
++		page = ctxt->pages[sge_no];
++		put_page(rqstp->rq_pages[sge_no]);
++		rqstp->rq_pages[sge_no] = page;
++		bc -= min(bc, ctxt->sge[sge_no].length);
++		rqstp->rq_arg.buflen += ctxt->sge[sge_no].length;
++		sge_no++;
++	}
++	rqstp->rq_respages = &rqstp->rq_pages[sge_no];
++
++	/* We should never run out of SGE because the limit is defined to
++	 * support the max allowed RPC data length
++	 */
++	BUG_ON(bc && (sge_no == ctxt->count));
++	BUG_ON((rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len)
++	       != byte_count);
++	BUG_ON(rqstp->rq_arg.len != byte_count);
++
++	/* If not all pages were used from the SGL, free the remaining ones */
++	bc = sge_no;
++	while (sge_no < ctxt->count) {
++		page = ctxt->pages[sge_no++];
++		put_page(page);
++	}
++	ctxt->count = bc;
++
++	/* Set up tail */
++	rqstp->rq_arg.tail[0].iov_base = NULL;
++	rqstp->rq_arg.tail[0].iov_len = 0;
++}
++
++struct chunk_sge {
++	int start;		/* sge no for this chunk */
++	int count;		/* sge count for this chunk */
++};
++
++/* Encode a read-chunk-list as an array of IB SGE
++ *
++ * Assumptions:
++ * - chunk[0]->position points to pages[0] at an offset of 0
++ * - pages[] is not physically or virtually contigous and consists of
++ *   PAGE_SIZE elements.
++ *
++ * Output:
++ * - sge array pointing into pages[] array.
++ * - chunk_sge array specifying sge index and count for each
++ *   chunk in the read list
++ *
++ */
++static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
++			   struct svc_rqst *rqstp,
++			   struct svc_rdma_op_ctxt *head,
++			   struct rpcrdma_msg *rmsgp,
++			   struct ib_sge *sge,
++			   struct chunk_sge *ch_sge_ary,
++			   int ch_count,
++			   int byte_count)
++{
++	int sge_no;
++	int sge_bytes;
++	int page_off;
++	int page_no;
++	int ch_bytes;
++	int ch_no;
++	struct rpcrdma_read_chunk *ch;
++
++	sge_no = 0;
++	page_no = 0;
++	page_off = 0;
++	ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
++	ch_no = 0;
++	ch_bytes = ch->rc_target.rs_length;
++	head->arg.head[0] = rqstp->rq_arg.head[0];
++	head->arg.tail[0] = rqstp->rq_arg.tail[0];
++	head->arg.pages = &head->pages[head->count];
++	head->sge[0].length = head->count; /* save count of hdr pages */
++	head->arg.page_base = 0;
++	head->arg.page_len = ch_bytes;
++	head->arg.len = rqstp->rq_arg.len + ch_bytes;
++	head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes;
++	head->count++;
++	ch_sge_ary[0].start = 0;
++	while (byte_count) {
++		sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes);
++		sge[sge_no].addr =
++			ib_dma_map_page(xprt->sc_cm_id->device,
++					rqstp->rq_arg.pages[page_no],
++					page_off, sge_bytes,
++					DMA_FROM_DEVICE);
++		sge[sge_no].length = sge_bytes;
++		sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
++		/*
++		 * Don't bump head->count here because the same page
++		 * may be used by multiple SGE.
++		 */
++		head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
++		rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1];
++
++		byte_count -= sge_bytes;
++		ch_bytes -= sge_bytes;
++		sge_no++;
++		/*
++		 * If all bytes for this chunk have been mapped to an
++		 * SGE, move to the next SGE
++		 */
++		if (ch_bytes == 0) {
++			ch_sge_ary[ch_no].count =
++				sge_no - ch_sge_ary[ch_no].start;
++			ch_no++;
++			ch++;
++			ch_sge_ary[ch_no].start = sge_no;
++			ch_bytes = ch->rc_target.rs_length;
++			/* If bytes remaining account for next chunk */
++			if (byte_count) {
++				head->arg.page_len += ch_bytes;
++				head->arg.len += ch_bytes;
++				head->arg.buflen += ch_bytes;
++			}
++		}
++		/*
++		 * If this SGE consumed all of the page, move to the
++		 * next page
++		 */
++		if ((sge_bytes + page_off) == PAGE_SIZE) {
++			page_no++;
++			page_off = 0;
++			/*
++			 * If there are still bytes left to map, bump
++			 * the page count
++			 */
++			if (byte_count)
++				head->count++;
++		} else
++			page_off += sge_bytes;
++	}
++	BUG_ON(byte_count != 0);
++	return sge_no;
++}
++
++static void rdma_set_ctxt_sge(struct svc_rdma_op_ctxt *ctxt,
++			      struct ib_sge *sge,
++			      u64 *sgl_offset,
++			      int count)
++{
++	int i;
++
++	ctxt->count = count;
++	for (i = 0; i < count; i++) {
++		ctxt->sge[i].addr = sge[i].addr;
++		ctxt->sge[i].length = sge[i].length;
++		*sgl_offset = *sgl_offset + sge[i].length;
++	}
++}
++
++static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
++{
++#ifdef RDMA_TRANSPORT_IWARP
++	if ((RDMA_TRANSPORT_IWARP ==
++	     rdma_node_get_transport(xprt->sc_cm_id->
++				     device->node_type))
++	    && sge_count > 1)
++		return 1;
++	else
++#endif
++		return min_t(int, sge_count, xprt->sc_max_sge);
++}
++
++/*
++ * Use RDMA_READ to read data from the advertised client buffer into the
++ * XDR stream starting at rq_arg.head[0].iov_base.
++ * Each chunk in the array
++ * contains the following fields:
++ * discrim      - '1', This isn't used for data placement
++ * position     - The xdr stream offset (the same for every chunk)
++ * handle       - RMR for client memory region
++ * length       - data transfer length
++ * offset       - 64 bit tagged offset in remote memory region
++ *
++ * On our side, we need to read into a pagelist. The first page immediately
++ * follows the RPC header.
++ *
++ * This function returns 1 to indicate success. The data is not yet in
++ * the pagelist and therefore the RPC request must be deferred. The
++ * I/O completion will enqueue the transport again and
++ * svc_rdma_recvfrom will complete the request.
++ *
++ * NOTE: The ctxt must not be touched after the last WR has been posted
++ * because the I/O completion processing may occur on another
++ * processor and free / modify the context. Ne touche pas!
++ */
++static int rdma_read_xdr(struct svcxprt_rdma *xprt,
++			 struct rpcrdma_msg *rmsgp,
++			 struct svc_rqst *rqstp,
++			 struct svc_rdma_op_ctxt *hdr_ctxt)
++{
++	struct ib_send_wr read_wr;
++	int err = 0;
++	int ch_no;
++	struct ib_sge *sge;
++	int ch_count;
++	int byte_count;
++	int sge_count;
++	u64 sgl_offset;
++	struct rpcrdma_read_chunk *ch;
++	struct svc_rdma_op_ctxt *ctxt = NULL;
++	struct svc_rdma_op_ctxt *head;
++	struct svc_rdma_op_ctxt *tmp_sge_ctxt;
++	struct svc_rdma_op_ctxt *tmp_ch_ctxt;
++	struct chunk_sge *ch_sge_ary;
++
++	/* If no read list is present, return 0 */
++	ch = svc_rdma_get_read_chunk(rmsgp);
++	if (!ch)
++		return 0;
++
++	/* Allocate temporary contexts to keep SGE */
++	BUG_ON(sizeof(struct ib_sge) < sizeof(struct chunk_sge));
++	tmp_sge_ctxt = svc_rdma_get_context(xprt);
++	sge = tmp_sge_ctxt->sge;
++	tmp_ch_ctxt = svc_rdma_get_context(xprt);
++	ch_sge_ary = (struct chunk_sge *)tmp_ch_ctxt->sge;
++
++	svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
++	sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
++				    sge, ch_sge_ary,
++				    ch_count, byte_count);
++	head = svc_rdma_get_context(xprt);
++	sgl_offset = 0;
++	ch_no = 0;
++
++	for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
++	     ch->rc_discrim != 0; ch++, ch_no++) {
++next_sge:
++		if (!ctxt)
++			ctxt = head;
++		else {
++			ctxt->next = svc_rdma_get_context(xprt);
++			ctxt = ctxt->next;
++		}
++		ctxt->next = NULL;
++		ctxt->direction = DMA_FROM_DEVICE;
++		clear_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
++		clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
++		if ((ch+1)->rc_discrim == 0) {
++			/*
++			 * Checked in sq_cq_reap to see if we need to
++			 * be enqueued
++			 */
++			set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
++			ctxt->next = hdr_ctxt;
++			hdr_ctxt->next = head;
++		}
++
++		/* Prepare READ WR */
++		memset(&read_wr, 0, sizeof read_wr);
++		ctxt->wr_op = IB_WR_RDMA_READ;
++		read_wr.wr_id = (unsigned long)ctxt;
++		read_wr.opcode = IB_WR_RDMA_READ;
++		read_wr.send_flags = IB_SEND_SIGNALED;
++		read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
++		read_wr.wr.rdma.remote_addr =
++			get_unaligned(&(ch->rc_target.rs_offset)) +
++			sgl_offset;
++		read_wr.sg_list = &sge[ch_sge_ary[ch_no].start];
++		read_wr.num_sge =
++			rdma_read_max_sge(xprt, ch_sge_ary[ch_no].count);
++		rdma_set_ctxt_sge(ctxt, &sge[ch_sge_ary[ch_no].start],
++				  &sgl_offset,
++				  read_wr.num_sge);
++
++		/* Post the read */
++		err = svc_rdma_send(xprt, &read_wr);
++		if (err) {
++			printk(KERN_ERR "svcrdma: Error posting send = %d\n",
++			       err);
++			/*
++			 * Break the circular list so free knows when
++			 * to stop if the error happened to occur on
++			 * the last read
++			 */
++			ctxt->next = NULL;
++			goto out;
++		}
++		atomic_inc(&rdma_stat_read);
++
++		if (read_wr.num_sge < ch_sge_ary[ch_no].count) {
++			ch_sge_ary[ch_no].count -= read_wr.num_sge;
++			ch_sge_ary[ch_no].start += read_wr.num_sge;
++			goto next_sge;
++		}
++		sgl_offset = 0;
++		err = 0;
++	}
++
++ out:
++	svc_rdma_put_context(tmp_sge_ctxt, 0);
++	svc_rdma_put_context(tmp_ch_ctxt, 0);
++
++	/* Detach arg pages. svc_recv will replenish them */
++	for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++)
++		rqstp->rq_pages[ch_no] = NULL;
++
++	/*
++	 * Detach res pages. svc_release must see a resused count of
++	 * zero or it will attempt to put them.
++	 */
++	while (rqstp->rq_resused)
++		rqstp->rq_respages[--rqstp->rq_resused] = NULL;
++
++	if (err) {
++		printk(KERN_ERR "svcrdma : RDMA_READ error = %d\n", err);
++		set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
++		/* Free the linked list of read contexts */
++		while (head != NULL) {
++			ctxt = head->next;
++			svc_rdma_put_context(head, 1);
++			head = ctxt;
++		}
++		return 0;
++	}
++
++	return 1;
++}
++
++static int rdma_read_complete(struct svc_rqst *rqstp,
++			      struct svc_rdma_op_ctxt *data)
++{
++	struct svc_rdma_op_ctxt *head = data->next;
++	int page_no;
++	int ret;
++
++	BUG_ON(!head);
++
++	/* Copy RPC pages */
++	for (page_no = 0; page_no < head->count; page_no++) {
++		put_page(rqstp->rq_pages[page_no]);
++		rqstp->rq_pages[page_no] = head->pages[page_no];
++	}
++	/* Point rq_arg.pages past header */
++	rqstp->rq_arg.pages = &rqstp->rq_pages[head->sge[0].length];
++	rqstp->rq_arg.page_len = head->arg.page_len;
++	rqstp->rq_arg.page_base = head->arg.page_base;
++
++	/* rq_respages starts after the last arg page */
++	rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
++	rqstp->rq_resused = 0;
++
++	/* Rebuild rq_arg head and tail. */
++	rqstp->rq_arg.head[0] = head->arg.head[0];
++	rqstp->rq_arg.tail[0] = head->arg.tail[0];
++	rqstp->rq_arg.len = head->arg.len;
++	rqstp->rq_arg.buflen = head->arg.buflen;
++
++	/* XXX: What should this be? */
++	rqstp->rq_prot = IPPROTO_MAX;
++
++	/*
++	 * Free the contexts we used to build the RDMA_READ. We have
++	 * to be careful here because the context list uses the same
++	 * next pointer used to chain the contexts associated with the
++	 * RDMA_READ
++	 */
++	data->next = NULL;	/* terminate circular list */
++	do {
++		data = head->next;
++		svc_rdma_put_context(head, 0);
++		head = data;
++	} while (head != NULL);
++
++	ret = rqstp->rq_arg.head[0].iov_len
++		+ rqstp->rq_arg.page_len
++		+ rqstp->rq_arg.tail[0].iov_len;
++	dprintk("svcrdma: deferred read ret=%d, rq_arg.len =%d, "
++		"rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
++		ret, rqstp->rq_arg.len,	rqstp->rq_arg.head[0].iov_base,
++		rqstp->rq_arg.head[0].iov_len);
++
++	/* Indicate that we've consumed an RQ credit */
++	rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
++	svc_xprt_received(rqstp->rq_xprt);
++	return ret;
++}
++
++/*
++ * Set up the rqstp thread context to point to the RQ buffer. If
++ * necessary, pull additional data from the client with an RDMA_READ
++ * request.
++ */
++int svc_rdma_recvfrom(struct svc_rqst *rqstp)
++{
++	struct svc_xprt *xprt = rqstp->rq_xprt;
++	struct svcxprt_rdma *rdma_xprt =
++		container_of(xprt, struct svcxprt_rdma, sc_xprt);
++	struct svc_rdma_op_ctxt *ctxt = NULL;
++	struct rpcrdma_msg *rmsgp;
++	int ret = 0;
++	int len;
++
++	dprintk("svcrdma: rqstp=%p\n", rqstp);
++
++	/*
++	 * The rq_xprt_ctxt indicates if we've consumed an RQ credit
++	 * or not. It is used in the rdma xpo_release_rqst function to
++	 * determine whether or not to return an RQ WQE to the RQ.
++	 */
++	rqstp->rq_xprt_ctxt = NULL;
++
++	spin_lock_bh(&rdma_xprt->sc_read_complete_lock);
++	if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
++		ctxt = list_entry(rdma_xprt->sc_read_complete_q.next,
++				  struct svc_rdma_op_ctxt,
++				  dto_q);
++		list_del_init(&ctxt->dto_q);
++	}
++	spin_unlock_bh(&rdma_xprt->sc_read_complete_lock);
++	if (ctxt)
++		return rdma_read_complete(rqstp, ctxt);
++
++	spin_lock_bh(&rdma_xprt->sc_rq_dto_lock);
++	if (!list_empty(&rdma_xprt->sc_rq_dto_q)) {
++		ctxt = list_entry(rdma_xprt->sc_rq_dto_q.next,
++				  struct svc_rdma_op_ctxt,
++				  dto_q);
++		list_del_init(&ctxt->dto_q);
++	} else {
++		atomic_inc(&rdma_stat_rq_starve);
++		clear_bit(XPT_DATA, &xprt->xpt_flags);
++		ctxt = NULL;
++	}
++	spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
++	if (!ctxt) {
++		/* This is the EAGAIN path. The svc_recv routine will
++		 * return -EAGAIN, the nfsd thread will go to call into
++		 * svc_recv again and we shouldn't be on the active
++		 * transport list
++		 */
++		if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
++			goto close_out;
++
++		BUG_ON(ret);
++		goto out;
++	}
++	dprintk("svcrdma: processing ctxt=%p on xprt=%p, rqstp=%p, status=%d\n",
++		ctxt, rdma_xprt, rqstp, ctxt->wc_status);
++	BUG_ON(ctxt->wc_status != IB_WC_SUCCESS);
++	atomic_inc(&rdma_stat_recv);
++
++	/* Build up the XDR from the receive buffers. */
++	rdma_build_arg_xdr(rqstp, ctxt, ctxt->byte_len);
++
++	/* Decode the RDMA header. */
++	len = svc_rdma_xdr_decode_req(&rmsgp, rqstp);
++	rqstp->rq_xprt_hlen = len;
++
++	/* If the request is invalid, reply with an error */
++	if (len < 0) {
++		if (len == -ENOSYS)
++			(void)svc_rdma_send_error(rdma_xprt, rmsgp, ERR_VERS);
++		goto close_out;
++	}
++
++	/* Read read-list data. If we would need to wait, defer
++	 * it. Not that in this case, we don't return the RQ credit
++	 * until after the read completes.
++	 */
++	if (rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt)) {
++		svc_xprt_received(xprt);
++		return 0;
++	}
++
++	/* Indicate we've consumed an RQ credit */
++	rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
++
++	ret = rqstp->rq_arg.head[0].iov_len
++		+ rqstp->rq_arg.page_len
++		+ rqstp->rq_arg.tail[0].iov_len;
++	svc_rdma_put_context(ctxt, 0);
++ out:
++	dprintk("svcrdma: ret = %d, rq_arg.len =%d, "
++		"rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
++		ret, rqstp->rq_arg.len,
++		rqstp->rq_arg.head[0].iov_base,
++		rqstp->rq_arg.head[0].iov_len);
++	rqstp->rq_prot = IPPROTO_MAX;
++	svc_xprt_copy_addrs(rqstp, xprt);
++	svc_xprt_received(xprt);
++	return ret;
++
++ close_out:
++	if (ctxt) {
++		svc_rdma_put_context(ctxt, 1);
++		/* Indicate we've consumed an RQ credit */
++		rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
++	}
++	dprintk("svcrdma: transport %p is closing\n", xprt);
++	/*
++	 * Set the close bit and enqueue it. svc_recv will see the
++	 * close bit and call svc_xprt_delete
++	 */
++	set_bit(XPT_CLOSE, &xprt->xpt_flags);
++	svc_xprt_received(xprt);
++	return 0;
++}
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+new file mode 100644
+index 0000000..3e32194
+--- /dev/null
++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+@@ -0,0 +1,520 @@
++/*
++ * Copyright (c) 2005-2006 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#include <linux/sunrpc/debug.h>
++#include <linux/sunrpc/rpc_rdma.h>
++#include <linux/spinlock.h>
++#include <asm/unaligned.h>
++#include <rdma/ib_verbs.h>
++#include <rdma/rdma_cm.h>
++#include <linux/sunrpc/svc_rdma.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++/* Encode an XDR as an array of IB SGE
++ *
++ * Assumptions:
++ * - head[0] is physically contiguous.
++ * - tail[0] is physically contiguous.
++ * - pages[] is not physically or virtually contigous and consists of
++ *   PAGE_SIZE elements.
++ *
++ * Output:
++ * SGE[0]              reserved for RCPRDMA header
++ * SGE[1]              data from xdr->head[]
++ * SGE[2..sge_count-2] data from xdr->pages[]
++ * SGE[sge_count-1]    data from xdr->tail.
++ *
++ */
++static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
++				 struct xdr_buf *xdr,
++				 struct ib_sge *sge,
++				 int *sge_count)
++{
++	/* Max we need is the length of the XDR / pagesize + one for
++	 * head + one for tail + one for RPCRDMA header
++	 */
++	int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
++	int sge_no;
++	u32 byte_count = xdr->len;
++	u32 sge_bytes;
++	u32 page_bytes;
++	int page_off;
++	int page_no;
++
++	/* Skip the first sge, this is for the RPCRDMA header */
++	sge_no = 1;
++
++	/* Head SGE */
++	sge[sge_no].addr = ib_dma_map_single(xprt->sc_cm_id->device,
++					     xdr->head[0].iov_base,
++					     xdr->head[0].iov_len,
++					     DMA_TO_DEVICE);
++	sge_bytes = min_t(u32, byte_count, xdr->head[0].iov_len);
++	byte_count -= sge_bytes;
++	sge[sge_no].length = sge_bytes;
++	sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
++	sge_no++;
++
++	/* pages SGE */
++	page_no = 0;
++	page_bytes = xdr->page_len;
++	page_off = xdr->page_base;
++	while (byte_count && page_bytes) {
++		sge_bytes = min_t(u32, byte_count, (PAGE_SIZE-page_off));
++		sge[sge_no].addr =
++			ib_dma_map_page(xprt->sc_cm_id->device,
++					xdr->pages[page_no], page_off,
++					sge_bytes, DMA_TO_DEVICE);
++		sge_bytes = min(sge_bytes, page_bytes);
++		byte_count -= sge_bytes;
++		page_bytes -= sge_bytes;
++		sge[sge_no].length = sge_bytes;
++		sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
++
++		sge_no++;
++		page_no++;
++		page_off = 0; /* reset for next time through loop */
++	}
++
++	/* Tail SGE */
++	if (byte_count && xdr->tail[0].iov_len) {
++		sge[sge_no].addr =
++			ib_dma_map_single(xprt->sc_cm_id->device,
++					  xdr->tail[0].iov_base,
++					  xdr->tail[0].iov_len,
++					  DMA_TO_DEVICE);
++		sge_bytes = min_t(u32, byte_count, xdr->tail[0].iov_len);
++		byte_count -= sge_bytes;
++		sge[sge_no].length = sge_bytes;
++		sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
++		sge_no++;
++	}
++
++	BUG_ON(sge_no > sge_max);
++	BUG_ON(byte_count != 0);
++
++	*sge_count = sge_no;
++	return sge;
++}
++
++
++/* Assumptions:
++ * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
++ */
++static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
++		      u32 rmr, u64 to,
++		      u32 xdr_off, int write_len,
++		      struct ib_sge *xdr_sge, int sge_count)
++{
++	struct svc_rdma_op_ctxt *tmp_sge_ctxt;
++	struct ib_send_wr write_wr;
++	struct ib_sge *sge;
++	int xdr_sge_no;
++	int sge_no;
++	int sge_bytes;
++	int sge_off;
++	int bc;
++	struct svc_rdma_op_ctxt *ctxt;
++	int ret = 0;
++
++	BUG_ON(sge_count >= 32);
++	dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, "
++		"write_len=%d, xdr_sge=%p, sge_count=%d\n",
++		rmr, to, xdr_off, write_len, xdr_sge, sge_count);
++
++	ctxt = svc_rdma_get_context(xprt);
++	ctxt->count = 0;
++	tmp_sge_ctxt = svc_rdma_get_context(xprt);
++	sge = tmp_sge_ctxt->sge;
++
++	/* Find the SGE associated with xdr_off */
++	for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < sge_count;
++	     xdr_sge_no++) {
++		if (xdr_sge[xdr_sge_no].length > bc)
++			break;
++		bc -= xdr_sge[xdr_sge_no].length;
++	}
++
++	sge_off = bc;
++	bc = write_len;
++	sge_no = 0;
++
++	/* Copy the remaining SGE */
++	while (bc != 0 && xdr_sge_no < sge_count) {
++		sge[sge_no].addr = xdr_sge[xdr_sge_no].addr + sge_off;
++		sge[sge_no].lkey = xdr_sge[xdr_sge_no].lkey;
++		sge_bytes = min((size_t)bc,
++				(size_t)(xdr_sge[xdr_sge_no].length-sge_off));
++		sge[sge_no].length = sge_bytes;
++
++		sge_off = 0;
++		sge_no++;
++		xdr_sge_no++;
++		bc -= sge_bytes;
++	}
++
++	BUG_ON(bc != 0);
++	BUG_ON(xdr_sge_no > sge_count);
++
++	/* Prepare WRITE WR */
++	memset(&write_wr, 0, sizeof write_wr);
++	ctxt->wr_op = IB_WR_RDMA_WRITE;
++	write_wr.wr_id = (unsigned long)ctxt;
++	write_wr.sg_list = &sge[0];
++	write_wr.num_sge = sge_no;
++	write_wr.opcode = IB_WR_RDMA_WRITE;
++	write_wr.send_flags = IB_SEND_SIGNALED;
++	write_wr.wr.rdma.rkey = rmr;
++	write_wr.wr.rdma.remote_addr = to;
++
++	/* Post It */
++	atomic_inc(&rdma_stat_write);
++	if (svc_rdma_send(xprt, &write_wr)) {
++		svc_rdma_put_context(ctxt, 1);
++		/* Fatal error, close transport */
++		ret = -EIO;
++	}
++	svc_rdma_put_context(tmp_sge_ctxt, 0);
++	return ret;
++}
++
++static int send_write_chunks(struct svcxprt_rdma *xprt,
++			     struct rpcrdma_msg *rdma_argp,
++			     struct rpcrdma_msg *rdma_resp,
++			     struct svc_rqst *rqstp,
++			     struct ib_sge *sge,
++			     int sge_count)
++{
++	u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
++	int write_len;
++	int max_write;
++	u32 xdr_off;
++	int chunk_off;
++	int chunk_no;
++	struct rpcrdma_write_array *arg_ary;
++	struct rpcrdma_write_array *res_ary;
++	int ret;
++
++	arg_ary = svc_rdma_get_write_array(rdma_argp);
++	if (!arg_ary)
++		return 0;
++	res_ary = (struct rpcrdma_write_array *)
++		&rdma_resp->rm_body.rm_chunks[1];
++
++	max_write = xprt->sc_max_sge * PAGE_SIZE;
++
++	/* Write chunks start at the pagelist */
++	for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
++	     xfer_len && chunk_no < arg_ary->wc_nchunks;
++	     chunk_no++) {
++		struct rpcrdma_segment *arg_ch;
++		u64 rs_offset;
++
++		arg_ch = &arg_ary->wc_array[chunk_no].wc_target;
++		write_len = min(xfer_len, arg_ch->rs_length);
++
++		/* Prepare the response chunk given the length actually
++		 * written */
++		rs_offset = get_unaligned(&(arg_ch->rs_offset));
++		svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
++					    arg_ch->rs_handle,
++					    rs_offset,
++					    write_len);
++		chunk_off = 0;
++		while (write_len) {
++			int this_write;
++			this_write = min(write_len, max_write);
++			ret = send_write(xprt, rqstp,
++					 arg_ch->rs_handle,
++					 rs_offset + chunk_off,
++					 xdr_off,
++					 this_write,
++					 sge,
++					 sge_count);
++			if (ret) {
++				dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
++					ret);
++				return -EIO;
++			}
++			chunk_off += this_write;
++			xdr_off += this_write;
++			xfer_len -= this_write;
++			write_len -= this_write;
++		}
++	}
++	/* Update the req with the number of chunks actually used */
++	svc_rdma_xdr_encode_write_list(rdma_resp, chunk_no);
++
++	return rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
++}
++
++static int send_reply_chunks(struct svcxprt_rdma *xprt,
++			     struct rpcrdma_msg *rdma_argp,
++			     struct rpcrdma_msg *rdma_resp,
++			     struct svc_rqst *rqstp,
++			     struct ib_sge *sge,
++			     int sge_count)
++{
++	u32 xfer_len = rqstp->rq_res.len;
++	int write_len;
++	int max_write;
++	u32 xdr_off;
++	int chunk_no;
++	int chunk_off;
++	struct rpcrdma_segment *ch;
++	struct rpcrdma_write_array *arg_ary;
++	struct rpcrdma_write_array *res_ary;
++	int ret;
++
++	arg_ary = svc_rdma_get_reply_array(rdma_argp);
++	if (!arg_ary)
++		return 0;
++	/* XXX: need to fix when reply lists occur with read-list and or
++	 * write-list */
++	res_ary = (struct rpcrdma_write_array *)
++		&rdma_resp->rm_body.rm_chunks[2];
++
++	max_write = xprt->sc_max_sge * PAGE_SIZE;
++
++	/* xdr offset starts at RPC message */
++	for (xdr_off = 0, chunk_no = 0;
++	     xfer_len && chunk_no < arg_ary->wc_nchunks;
++	     chunk_no++) {
++		u64 rs_offset;
++		ch = &arg_ary->wc_array[chunk_no].wc_target;
++		write_len = min(xfer_len, ch->rs_length);
++
++
++		/* Prepare the reply chunk given the length actually
++		 * written */
++		rs_offset = get_unaligned(&(ch->rs_offset));
++		svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
++					    ch->rs_handle, rs_offset,
++					    write_len);
++		chunk_off = 0;
++		while (write_len) {
++			int this_write;
++
++			this_write = min(write_len, max_write);
++			ret = send_write(xprt, rqstp,
++					 ch->rs_handle,
++					 rs_offset + chunk_off,
++					 xdr_off,
++					 this_write,
++					 sge,
++					 sge_count);
++			if (ret) {
++				dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
++					ret);
++				return -EIO;
++			}
++			chunk_off += this_write;
++			xdr_off += this_write;
++			xfer_len -= this_write;
++			write_len -= this_write;
++		}
++	}
++	/* Update the req with the number of chunks actually used */
++	svc_rdma_xdr_encode_reply_array(res_ary, chunk_no);
++
++	return rqstp->rq_res.len;
++}
++
++/* This function prepares the portion of the RPCRDMA message to be
++ * sent in the RDMA_SEND. This function is called after data sent via
++ * RDMA has already been transmitted. There are three cases:
++ * - The RPCRDMA header, RPC header, and payload are all sent in a
++ *   single RDMA_SEND. This is the "inline" case.
++ * - The RPCRDMA header and some portion of the RPC header and data
++ *   are sent via this RDMA_SEND and another portion of the data is
++ *   sent via RDMA.
++ * - The RPCRDMA header [NOMSG] is sent in this RDMA_SEND and the RPC
++ *   header and data are all transmitted via RDMA.
++ * In all three cases, this function prepares the RPCRDMA header in
++ * sge[0], the 'type' parameter indicates the type to place in the
++ * RPCRDMA header, and the 'byte_count' field indicates how much of
++ * the XDR to include in this RDMA_SEND.
++ */
++static int send_reply(struct svcxprt_rdma *rdma,
++		      struct svc_rqst *rqstp,
++		      struct page *page,
++		      struct rpcrdma_msg *rdma_resp,
++		      struct svc_rdma_op_ctxt *ctxt,
++		      int sge_count,
++		      int byte_count)
++{
++	struct ib_send_wr send_wr;
++	int sge_no;
++	int sge_bytes;
++	int page_no;
++	int ret;
++
++	/* Prepare the context */
++	ctxt->pages[0] = page;
++	ctxt->count = 1;
++
++	/* Prepare the SGE for the RPCRDMA Header */
++	ctxt->sge[0].addr =
++		ib_dma_map_page(rdma->sc_cm_id->device,
++				page, 0, PAGE_SIZE, DMA_TO_DEVICE);
++	ctxt->direction = DMA_TO_DEVICE;
++	ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
++	ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
++
++	/* Determine how many of our SGE are to be transmitted */
++	for (sge_no = 1; byte_count && sge_no < sge_count; sge_no++) {
++		sge_bytes = min((size_t)ctxt->sge[sge_no].length,
++				(size_t)byte_count);
++		byte_count -= sge_bytes;
++	}
++	BUG_ON(byte_count != 0);
++
++	/* Save all respages in the ctxt and remove them from the
++	 * respages array. They are our pages until the I/O
++	 * completes.
++	 */
++	for (page_no = 0; page_no < rqstp->rq_resused; page_no++) {
++		ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
++		ctxt->count++;
++		rqstp->rq_respages[page_no] = NULL;
++	}
++
++	BUG_ON(sge_no > rdma->sc_max_sge);
++	memset(&send_wr, 0, sizeof send_wr);
++	ctxt->wr_op = IB_WR_SEND;
++	send_wr.wr_id = (unsigned long)ctxt;
++	send_wr.sg_list = ctxt->sge;
++	send_wr.num_sge = sge_no;
++	send_wr.opcode = IB_WR_SEND;
++	send_wr.send_flags =  IB_SEND_SIGNALED;
++
++	ret = svc_rdma_send(rdma, &send_wr);
++	if (ret)
++		svc_rdma_put_context(ctxt, 1);
++
++	return ret;
++}
++
++void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
++{
++}
++
++/*
++ * Return the start of an xdr buffer.
++ */
++static void *xdr_start(struct xdr_buf *xdr)
++{
++	return xdr->head[0].iov_base -
++		(xdr->len -
++		 xdr->page_len -
++		 xdr->tail[0].iov_len -
++		 xdr->head[0].iov_len);
++}
++
++int svc_rdma_sendto(struct svc_rqst *rqstp)
++{
++	struct svc_xprt *xprt = rqstp->rq_xprt;
++	struct svcxprt_rdma *rdma =
++		container_of(xprt, struct svcxprt_rdma, sc_xprt);
++	struct rpcrdma_msg *rdma_argp;
++	struct rpcrdma_msg *rdma_resp;
++	struct rpcrdma_write_array *reply_ary;
++	enum rpcrdma_proc reply_type;
++	int ret;
++	int inline_bytes;
++	struct ib_sge *sge;
++	int sge_count = 0;
++	struct page *res_page;
++	struct svc_rdma_op_ctxt *ctxt;
++
++	dprintk("svcrdma: sending response for rqstp=%p\n", rqstp);
++
++	/* Get the RDMA request header. */
++	rdma_argp = xdr_start(&rqstp->rq_arg);
++
++	/* Build an SGE for the XDR */
++	ctxt = svc_rdma_get_context(rdma);
++	ctxt->direction = DMA_TO_DEVICE;
++	sge = xdr_to_sge(rdma, &rqstp->rq_res, ctxt->sge, &sge_count);
++
++	inline_bytes = rqstp->rq_res.len;
++
++	/* Create the RDMA response header */
++	res_page = svc_rdma_get_page();
++	rdma_resp = page_address(res_page);
++	reply_ary = svc_rdma_get_reply_array(rdma_argp);
++	if (reply_ary)
++		reply_type = RDMA_NOMSG;
++	else
++		reply_type = RDMA_MSG;
++	svc_rdma_xdr_encode_reply_header(rdma, rdma_argp,
++					 rdma_resp, reply_type);
++
++	/* Send any write-chunk data and build resp write-list */
++	ret = send_write_chunks(rdma, rdma_argp, rdma_resp,
++				rqstp, sge, sge_count);
++	if (ret < 0) {
++		printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
++		       ret);
++		goto error;
++	}
++	inline_bytes -= ret;
++
++	/* Send any reply-list data and update resp reply-list */
++	ret = send_reply_chunks(rdma, rdma_argp, rdma_resp,
++				rqstp, sge, sge_count);
++	if (ret < 0) {
++		printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
++		       ret);
++		goto error;
++	}
++	inline_bytes -= ret;
++
++	ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, sge_count,
++			 inline_bytes);
++	dprintk("svcrdma: send_reply returns %d\n", ret);
++	return ret;
++ error:
++	svc_rdma_put_context(ctxt, 0);
++	put_page(res_page);
++	return ret;
++}
+diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+new file mode 100644
+index 0000000..f09444c
+--- /dev/null
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -0,0 +1,1080 @@
++/*
++ * Copyright (c) 2005-2007 Network Appliance, 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
++ * General Public License (GPL) Version 2, available from the file
++ * COPYING in the main directory of this source tree, or the BSD-type
++ * license below:
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ *      Redistributions of source code must retain the above copyright
++ *      notice, this list of conditions and the following disclaimer.
++ *
++ *      Redistributions in binary form must reproduce the above
++ *      copyright notice, this list of conditions and the following
++ *      disclaimer in the documentation and/or other materials provided
++ *      with the distribution.
++ *
++ *      Neither the name of the Network Appliance, Inc. nor the names of
++ *      its contributors may be used to endorse or promote products
++ *      derived from this software without specific prior written
++ *      permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "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 COPYRIGHT
++ * OWNER OR CONTRIBUTORS 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.
++ *
++ * Author: Tom Tucker <tom at opengridcomputing.com>
++ */
++
++#include <linux/sunrpc/svc_xprt.h>
++#include <linux/sunrpc/debug.h>
++#include <linux/sunrpc/rpc_rdma.h>
++#include <linux/spinlock.h>
++#include <rdma/ib_verbs.h>
++#include <rdma/rdma_cm.h>
++#include <linux/sunrpc/svc_rdma.h>
++
++#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
++
++static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
++					struct sockaddr *sa, int salen,
++					int flags);
++static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
++static void svc_rdma_release_rqst(struct svc_rqst *);
++static void rdma_destroy_xprt(struct svcxprt_rdma *xprt);
++static void dto_tasklet_func(unsigned long data);
++static void svc_rdma_detach(struct svc_xprt *xprt);
++static void svc_rdma_free(struct svc_xprt *xprt);
++static int svc_rdma_has_wspace(struct svc_xprt *xprt);
++static void rq_cq_reap(struct svcxprt_rdma *xprt);
++static void sq_cq_reap(struct svcxprt_rdma *xprt);
++
++DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL);
++static DEFINE_SPINLOCK(dto_lock);
++static LIST_HEAD(dto_xprt_q);
++
++static struct svc_xprt_ops svc_rdma_ops = {
++	.xpo_create = svc_rdma_create,
++	.xpo_recvfrom = svc_rdma_recvfrom,
++	.xpo_sendto = svc_rdma_sendto,
++	.xpo_release_rqst = svc_rdma_release_rqst,
++	.xpo_detach = svc_rdma_detach,
++	.xpo_free = svc_rdma_free,
++	.xpo_prep_reply_hdr = svc_rdma_prep_reply_hdr,
++	.xpo_has_wspace = svc_rdma_has_wspace,
++	.xpo_accept = svc_rdma_accept,
++};
++
++struct svc_xprt_class svc_rdma_class = {
++	.xcl_name = "rdma",
++	.xcl_owner = THIS_MODULE,
++	.xcl_ops = &svc_rdma_ops,
++	.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
++};
++
++static int rdma_bump_context_cache(struct svcxprt_rdma *xprt)
++{
++	int target;
++	int at_least_one = 0;
++	struct svc_rdma_op_ctxt *ctxt;
++
++	target = min(xprt->sc_ctxt_cnt + xprt->sc_ctxt_bump,
++		     xprt->sc_ctxt_max);
++
++	spin_lock_bh(&xprt->sc_ctxt_lock);
++	while (xprt->sc_ctxt_cnt < target) {
++		xprt->sc_ctxt_cnt++;
++		spin_unlock_bh(&xprt->sc_ctxt_lock);
++
++		ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
++
++		spin_lock_bh(&xprt->sc_ctxt_lock);
++		if (ctxt) {
++			at_least_one = 1;
++			ctxt->next = xprt->sc_ctxt_head;
++			xprt->sc_ctxt_head = ctxt;
++		} else {
++			/* kmalloc failed...give up for now */
++			xprt->sc_ctxt_cnt--;
++			break;
++		}
++	}
++	spin_unlock_bh(&xprt->sc_ctxt_lock);
++	dprintk("svcrdma: sc_ctxt_max=%d, sc_ctxt_cnt=%d\n",
++		xprt->sc_ctxt_max, xprt->sc_ctxt_cnt);
++	return at_least_one;
++}
++
++struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
++{
++	struct svc_rdma_op_ctxt *ctxt;
++
++	while (1) {
++		spin_lock_bh(&xprt->sc_ctxt_lock);
++		if (unlikely(xprt->sc_ctxt_head == NULL)) {
++			/* Try to bump my cache. */
++			spin_unlock_bh(&xprt->sc_ctxt_lock);
++
++			if (rdma_bump_context_cache(xprt))
++				continue;
++
++			printk(KERN_INFO "svcrdma: sleeping waiting for "
++			       "context memory on xprt=%p\n",
++			       xprt);
++			schedule_timeout_uninterruptible(msecs_to_jiffies(500));
++			continue;
++		}
++		ctxt = xprt->sc_ctxt_head;
++		xprt->sc_ctxt_head = ctxt->next;
++		spin_unlock_bh(&xprt->sc_ctxt_lock);
++		ctxt->xprt = xprt;
++		INIT_LIST_HEAD(&ctxt->dto_q);
++		ctxt->count = 0;
++		break;
++	}
++	return ctxt;
++}
++
++void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
++{
++	struct svcxprt_rdma *xprt;
++	int i;
++
++	BUG_ON(!ctxt);
++	xprt = ctxt->xprt;
++	if (free_pages)
++		for (i = 0; i < ctxt->count; i++)
++			put_page(ctxt->pages[i]);
++
++	for (i = 0; i < ctxt->count; i++)
++		dma_unmap_single(xprt->sc_cm_id->device->dma_device,
++				 ctxt->sge[i].addr,
++				 ctxt->sge[i].length,
++				 ctxt->direction);
++	spin_lock_bh(&xprt->sc_ctxt_lock);
++	ctxt->next = xprt->sc_ctxt_head;
++	xprt->sc_ctxt_head = ctxt;
++	spin_unlock_bh(&xprt->sc_ctxt_lock);
++}
++
++/* ib_cq event handler */
++static void cq_event_handler(struct ib_event *event, void *context)
++{
++	struct svc_xprt *xprt = context;
++	dprintk("svcrdma: received CQ event id=%d, context=%p\n",
++		event->event, context);
++	set_bit(XPT_CLOSE, &xprt->xpt_flags);
++}
++
++/* QP event handler */
++static void qp_event_handler(struct ib_event *event, void *context)
++{
++	struct svc_xprt *xprt = context;
++
++	switch (event->event) {
++	/* These are considered benign events */
++	case IB_EVENT_PATH_MIG:
++	case IB_EVENT_COMM_EST:
++	case IB_EVENT_SQ_DRAINED:
++	case IB_EVENT_QP_LAST_WQE_REACHED:
++		dprintk("svcrdma: QP event %d received for QP=%p\n",
++			event->event, event->element.qp);
++		break;
++	/* These are considered fatal events */
++	case IB_EVENT_PATH_MIG_ERR:
++	case IB_EVENT_QP_FATAL:
++	case IB_EVENT_QP_REQ_ERR:
++	case IB_EVENT_QP_ACCESS_ERR:
++	case IB_EVENT_DEVICE_FATAL:
++	default:
++		dprintk("svcrdma: QP ERROR event %d received for QP=%p, "
++			"closing transport\n",
++			event->event, event->element.qp);
++		set_bit(XPT_CLOSE, &xprt->xpt_flags);
++		break;
++	}
++}
++
++/*
++ * Data Transfer Operation Tasklet
++ *
++ * Walks a list of transports with I/O pending, removing entries as
++ * they are added to the server's I/O pending list. Two bits indicate
++ * if SQ, RQ, or both have I/O pending. The dto_lock is an irqsave
++ * spinlock that serializes access to the transport list with the RQ
++ * and SQ interrupt handlers.
++ */
++static void dto_tasklet_func(unsigned long data)
++{
++	struct svcxprt_rdma *xprt;
++	unsigned long flags;
++
++	spin_lock_irqsave(&dto_lock, flags);
++	while (!list_empty(&dto_xprt_q)) {
++		xprt = list_entry(dto_xprt_q.next,
++				  struct svcxprt_rdma, sc_dto_q);
++		list_del_init(&xprt->sc_dto_q);
++		spin_unlock_irqrestore(&dto_lock, flags);
++
++		if (test_and_clear_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags)) {
++			ib_req_notify_cq(xprt->sc_rq_cq, IB_CQ_NEXT_COMP);
++			rq_cq_reap(xprt);
++			set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
++			/*
++			 * If data arrived before established event,
++			 * don't enqueue. This defers RPC I/O until the
++			 * RDMA connection is complete.
++			 */
++			if (!test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
++				svc_xprt_enqueue(&xprt->sc_xprt);
++		}
++
++		if (test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags)) {
++			ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
++			sq_cq_reap(xprt);
++		}
++
++		spin_lock_irqsave(&dto_lock, flags);
++	}
++	spin_unlock_irqrestore(&dto_lock, flags);
++}
++
++/*
++ * Receive Queue Completion Handler
++ *
++ * Since an RQ completion handler is called on interrupt context, we
++ * need to defer the handling of the I/O to a tasklet
++ */
++static void rq_comp_handler(struct ib_cq *cq, void *cq_context)
++{
++	struct svcxprt_rdma *xprt = cq_context;
++	unsigned long flags;
++
++	/*
++	 * Set the bit regardless of whether or not it's on the list
++	 * because it may be on the list already due to an SQ
++	 * completion.
++	*/
++	set_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags);
++
++	/*
++	 * If this transport is not already on the DTO transport queue,
++	 * add it
++	 */
++	spin_lock_irqsave(&dto_lock, flags);
++	if (list_empty(&xprt->sc_dto_q))
++		list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
++	spin_unlock_irqrestore(&dto_lock, flags);
++
++	/* Tasklet does all the work to avoid irqsave locks. */
++	tasklet_schedule(&dto_tasklet);
++}
++
++/*
++ * rq_cq_reap - Process the RQ CQ.
++ *
++ * Take all completing WC off the CQE and enqueue the associated DTO
++ * context on the dto_q for the transport.
++ */
++static void rq_cq_reap(struct svcxprt_rdma *xprt)
++{
++	int ret;
++	struct ib_wc wc;
++	struct svc_rdma_op_ctxt *ctxt = NULL;
++
++	atomic_inc(&rdma_stat_rq_poll);
++
++	spin_lock_bh(&xprt->sc_rq_dto_lock);
++	while ((ret = ib_poll_cq(xprt->sc_rq_cq, 1, &wc)) > 0) {
++		ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
++		ctxt->wc_status = wc.status;
++		ctxt->byte_len = wc.byte_len;
++		if (wc.status != IB_WC_SUCCESS) {
++			/* Close the transport */
++			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
++			svc_rdma_put_context(ctxt, 1);
++			continue;
++		}
++		list_add_tail(&ctxt->dto_q, &xprt->sc_rq_dto_q);
++	}
++	spin_unlock_bh(&xprt->sc_rq_dto_lock);
++
++	if (ctxt)
++		atomic_inc(&rdma_stat_rq_prod);
++}
++
++/*
++ * Send Queue Completion Handler - potentially called on interrupt context.
++ */
++static void sq_cq_reap(struct svcxprt_rdma *xprt)
++{
++	struct svc_rdma_op_ctxt *ctxt = NULL;
++	struct ib_wc wc;
++	struct ib_cq *cq = xprt->sc_sq_cq;
++	int ret;
++
++	atomic_inc(&rdma_stat_sq_poll);
++	while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
++		ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
++		xprt = ctxt->xprt;
++
++		if (wc.status != IB_WC_SUCCESS)
++			/* Close the transport */
++			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
++
++		/* Decrement used SQ WR count */
++		atomic_dec(&xprt->sc_sq_count);
++		wake_up(&xprt->sc_send_wait);
++
++		switch (ctxt->wr_op) {
++		case IB_WR_SEND:
++		case IB_WR_RDMA_WRITE:
++			svc_rdma_put_context(ctxt, 1);
++			break;
++
++		case IB_WR_RDMA_READ:
++			if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
++				set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
++				set_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
++				spin_lock_bh(&xprt->sc_read_complete_lock);
++				list_add_tail(&ctxt->dto_q,
++					      &xprt->sc_read_complete_q);
++				spin_unlock_bh(&xprt->sc_read_complete_lock);
++				svc_xprt_enqueue(&xprt->sc_xprt);
++			}
++			break;
++
++		default:
++			printk(KERN_ERR "svcrdma: unexpected completion type, "
++			       "opcode=%d, status=%d\n",
++			       wc.opcode, wc.status);
++			break;
++		}
++	}
++
++	if (ctxt)
++		atomic_inc(&rdma_stat_sq_prod);
++}
++
++static void sq_comp_handler(struct ib_cq *cq, void *cq_context)
++{
++	struct svcxprt_rdma *xprt = cq_context;
++	unsigned long flags;
++
++	/*
++	 * Set the bit regardless of whether or not it's on the list
++	 * because it may be on the list already due to an RQ
++	 * completion.
++	*/
++	set_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags);
++
++	/*
++	 * If this transport is not already on the DTO transport queue,
++	 * add it
++	 */
++	spin_lock_irqsave(&dto_lock, flags);
++	if (list_empty(&xprt->sc_dto_q))
++		list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
++	spin_unlock_irqrestore(&dto_lock, flags);
++
++	/* Tasklet does all the work to avoid irqsave locks. */
++	tasklet_schedule(&dto_tasklet);
++}
++
++static void create_context_cache(struct svcxprt_rdma *xprt,
++				 int ctxt_count, int ctxt_bump, int ctxt_max)
++{
++	struct svc_rdma_op_ctxt *ctxt;
++	int i;
++
++	xprt->sc_ctxt_max = ctxt_max;
++	xprt->sc_ctxt_bump = ctxt_bump;
++	xprt->sc_ctxt_cnt = 0;
++	xprt->sc_ctxt_head = NULL;
++	for (i = 0; i < ctxt_count; i++) {
++		ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
++		if (ctxt) {
++			ctxt->next = xprt->sc_ctxt_head;
++			xprt->sc_ctxt_head = ctxt;
++			xprt->sc_ctxt_cnt++;
++		}
++	}
++}
++
++static void destroy_context_cache(struct svc_rdma_op_ctxt *ctxt)
++{
++	struct svc_rdma_op_ctxt *next;
++	if (!ctxt)
++		return;
++
++	do {
++		next = ctxt->next;
++		kfree(ctxt);
++		ctxt = next;
++	} while (next);
++}
++
++static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
++					     int listener)
++{
++	struct svcxprt_rdma *cma_xprt = kzalloc(sizeof *cma_xprt, GFP_KERNEL);
++
++	if (!cma_xprt)
++		return NULL;
++	svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv);
++	INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
++	INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
++	INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
++	INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
++	init_waitqueue_head(&cma_xprt->sc_send_wait);
++
++	spin_lock_init(&cma_xprt->sc_lock);
++	spin_lock_init(&cma_xprt->sc_read_complete_lock);
++	spin_lock_init(&cma_xprt->sc_ctxt_lock);
++	spin_lock_init(&cma_xprt->sc_rq_dto_lock);
++
++	cma_xprt->sc_ord = svcrdma_ord;
++
++	cma_xprt->sc_max_req_size = svcrdma_max_req_size;
++	cma_xprt->sc_max_requests = svcrdma_max_requests;
++	cma_xprt->sc_sq_depth = svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT;
++	atomic_set(&cma_xprt->sc_sq_count, 0);
++
++	if (!listener) {
++		int reqs = cma_xprt->sc_max_requests;
++		create_context_cache(cma_xprt,
++				     reqs << 1, /* starting size */
++				     reqs,	/* bump amount */
++				     reqs +
++				     cma_xprt->sc_sq_depth +
++				     RPCRDMA_MAX_THREADS + 1); /* max */
++		if (!cma_xprt->sc_ctxt_head) {
++			kfree(cma_xprt);
++			return NULL;
++		}
++		clear_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
++	} else
++		set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
++
++	return cma_xprt;
++}
++
++struct page *svc_rdma_get_page(void)
++{
++	struct page *page;
++
++	while ((page = alloc_page(GFP_KERNEL)) == NULL) {
++		/* If we can't get memory, wait a bit and try again */
++		printk(KERN_INFO "svcrdma: out of memory...retrying in 1000 "
++		       "jiffies.\n");
++		schedule_timeout_uninterruptible(msecs_to_jiffies(1000));
++	}
++	return page;
++}
++
++int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
++{
++	struct ib_recv_wr recv_wr, *bad_recv_wr;
++	struct svc_rdma_op_ctxt *ctxt;
++	struct page *page;
++	unsigned long pa;
++	int sge_no;
++	int buflen;
++	int ret;
++
++	ctxt = svc_rdma_get_context(xprt);
++	buflen = 0;
++	ctxt->direction = DMA_FROM_DEVICE;
++	for (sge_no = 0; buflen < xprt->sc_max_req_size; sge_no++) {
++		BUG_ON(sge_no >= xprt->sc_max_sge);
++		page = svc_rdma_get_page();
++		ctxt->pages[sge_no] = page;
++		pa = ib_dma_map_page(xprt->sc_cm_id->device,
++				     page, 0, PAGE_SIZE,
++				     DMA_FROM_DEVICE);
++		ctxt->sge[sge_no].addr = pa;
++		ctxt->sge[sge_no].length = PAGE_SIZE;
++		ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
++		buflen += PAGE_SIZE;
++	}
++	ctxt->count = sge_no;
++	recv_wr.next = NULL;
++	recv_wr.sg_list = &ctxt->sge[0];
++	recv_wr.num_sge = ctxt->count;
++	recv_wr.wr_id = (u64)(unsigned long)ctxt;
++
++	ret = ib_post_recv(xprt->sc_qp, &recv_wr, &bad_recv_wr);
++	return ret;
++}
++
++/*
++ * This function handles the CONNECT_REQUEST event on a listening
++ * endpoint. It is passed the cma_id for the _new_ connection. The context in
++ * this cma_id is inherited from the listening cma_id and is the svc_xprt
++ * structure for the listening endpoint.
++ *
++ * This function creates a new xprt for the new connection and enqueues it on
++ * the accept queue for the listent xprt. When the listen thread is kicked, it
++ * will call the recvfrom method on the listen xprt which will accept the new
++ * connection.
++ */
++static void handle_connect_req(struct rdma_cm_id *new_cma_id)
++{
++	struct svcxprt_rdma *listen_xprt = new_cma_id->context;
++	struct svcxprt_rdma *newxprt;
++
++	/* Create a new transport */
++	newxprt = rdma_create_xprt(listen_xprt->sc_xprt.xpt_server, 0);
++	if (!newxprt) {
++		dprintk("svcrdma: failed to create new transport\n");
++		return;
++	}
++	newxprt->sc_cm_id = new_cma_id;
++	new_cma_id->context = newxprt;
++	dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
++		newxprt, newxprt->sc_cm_id, listen_xprt);
++
++	/*
++	 * Enqueue the new transport on the accept queue of the listening
++	 * transport
++	 */
++	spin_lock_bh(&listen_xprt->sc_lock);
++	list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q);
++	spin_unlock_bh(&listen_xprt->sc_lock);
++
++	/*
++	 * Can't use svc_xprt_received here because we are not on a
++	 * rqstp thread
++	*/
++	set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags);
++	svc_xprt_enqueue(&listen_xprt->sc_xprt);
++}
++
++/*
++ * Handles events generated on the listening endpoint. These events will be
++ * either be incoming connect requests or adapter removal  events.
++ */
++static int rdma_listen_handler(struct rdma_cm_id *cma_id,
++			       struct rdma_cm_event *event)
++{
++	struct svcxprt_rdma *xprt = cma_id->context;
++	int ret = 0;
++
++	switch (event->event) {
++	case RDMA_CM_EVENT_CONNECT_REQUEST:
++		dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
++			"event=%d\n", cma_id, cma_id->context, event->event);
++		handle_connect_req(cma_id);
++		break;
++
++	case RDMA_CM_EVENT_ESTABLISHED:
++		/* Accept complete */
++		dprintk("svcrdma: Connection completed on LISTEN xprt=%p, "
++			"cm_id=%p\n", xprt, cma_id);
++		break;
++
++	case RDMA_CM_EVENT_DEVICE_REMOVAL:
++		dprintk("svcrdma: Device removal xprt=%p, cm_id=%p\n",
++			xprt, cma_id);
++		if (xprt)
++			set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
++		break;
++
++	default:
++		dprintk("svcrdma: Unexpected event on listening endpoint %p, "
++			"event=%d\n", cma_id, event->event);
++		break;
++	}
++
++	return ret;
++}
++
++static int rdma_cma_handler(struct rdma_cm_id *cma_id,
++			    struct rdma_cm_event *event)
++{
++	struct svc_xprt *xprt = cma_id->context;
++	struct svcxprt_rdma *rdma =
++		container_of(xprt, struct svcxprt_rdma, sc_xprt);
++	switch (event->event) {
++	case RDMA_CM_EVENT_ESTABLISHED:
++		/* Accept complete */
++		dprintk("svcrdma: Connection completed on DTO xprt=%p, "
++			"cm_id=%p\n", xprt, cma_id);
++		clear_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags);
++		svc_xprt_enqueue(xprt);
++		break;
++	case RDMA_CM_EVENT_DISCONNECTED:
++		dprintk("svcrdma: Disconnect on DTO xprt=%p, cm_id=%p\n",
++			xprt, cma_id);
++		if (xprt) {
++			set_bit(XPT_CLOSE, &xprt->xpt_flags);
++			svc_xprt_enqueue(xprt);
++		}
++		break;
++	case RDMA_CM_EVENT_DEVICE_REMOVAL:
++		dprintk("svcrdma: Device removal cma_id=%p, xprt = %p, "
++			"event=%d\n", cma_id, xprt, event->event);
++		if (xprt) {
++			set_bit(XPT_CLOSE, &xprt->xpt_flags);
++			svc_xprt_enqueue(xprt);
++		}
++		break;
++	default:
++		dprintk("svcrdma: Unexpected event on DTO endpoint %p, "
++			"event=%d\n", cma_id, event->event);
++		break;
++	}
++	return 0;
++}
++
++/*
++ * Create a listening RDMA service endpoint.
++ */
++static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
++					struct sockaddr *sa, int salen,
++					int flags)
++{
++	struct rdma_cm_id *listen_id;
++	struct svcxprt_rdma *cma_xprt;
++	struct svc_xprt *xprt;
++	int ret;
++
++	dprintk("svcrdma: Creating RDMA socket\n");
++
++	cma_xprt = rdma_create_xprt(serv, 1);
++	if (!cma_xprt)
++		return ERR_PTR(ENOMEM);
++	xprt = &cma_xprt->sc_xprt;
++
++	listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
++	if (IS_ERR(listen_id)) {
++		rdma_destroy_xprt(cma_xprt);
++		dprintk("svcrdma: rdma_create_id failed = %ld\n",
++			PTR_ERR(listen_id));
++		return (void *)listen_id;
++	}
++	ret = rdma_bind_addr(listen_id, sa);
++	if (ret) {
++		rdma_destroy_xprt(cma_xprt);
++		rdma_destroy_id(listen_id);
++		dprintk("svcrdma: rdma_bind_addr failed = %d\n", ret);
++		return ERR_PTR(ret);
++	}
++	cma_xprt->sc_cm_id = listen_id;
++
++	ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
++	if (ret) {
++		rdma_destroy_id(listen_id);
++		rdma_destroy_xprt(cma_xprt);
++		dprintk("svcrdma: rdma_listen failed = %d\n", ret);
++	}
++
++	/*
++	 * We need to use the address from the cm_id in case the
++	 * caller specified 0 for the port number.
++	 */
++	sa = (struct sockaddr *)&cma_xprt->sc_cm_id->route.addr.src_addr;
++	svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
++
++	return &cma_xprt->sc_xprt;
++}
++
++/*
++ * This is the xpo_recvfrom function for listening endpoints. Its
++ * purpose is to accept incoming connections. The CMA callback handler
++ * has already created a new transport and attached it to the new CMA
++ * ID.
++ *
++ * There is a queue of pending connections hung on the listening
++ * transport. This queue contains the new svc_xprt structure. This
++ * function takes svc_xprt structures off the accept_q and completes
++ * the connection.
++ */
++static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
++{
++	struct svcxprt_rdma *listen_rdma;
++	struct svcxprt_rdma *newxprt = NULL;
++	struct rdma_conn_param conn_param;
++	struct ib_qp_init_attr qp_attr;
++	struct ib_device_attr devattr;
++	struct sockaddr *sa;
++	int ret;
++	int i;
++
++	listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt);
++	clear_bit(XPT_CONN, &xprt->xpt_flags);
++	/* Get the next entry off the accept list */
++	spin_lock_bh(&listen_rdma->sc_lock);
++	if (!list_empty(&listen_rdma->sc_accept_q)) {
++		newxprt = list_entry(listen_rdma->sc_accept_q.next,
++				     struct svcxprt_rdma, sc_accept_q);
++		list_del_init(&newxprt->sc_accept_q);
++	}
++	if (!list_empty(&listen_rdma->sc_accept_q))
++		set_bit(XPT_CONN, &listen_rdma->sc_xprt.xpt_flags);
++	spin_unlock_bh(&listen_rdma->sc_lock);
++	if (!newxprt)
++		return NULL;
++
++	dprintk("svcrdma: newxprt from accept queue = %p, cm_id=%p\n",
++		newxprt, newxprt->sc_cm_id);
++
++	ret = ib_query_device(newxprt->sc_cm_id->device, &devattr);
++	if (ret) {
++		dprintk("svcrdma: could not query device attributes on "
++			"device %p, rc=%d\n", newxprt->sc_cm_id->device, ret);
++		goto errout;
++	}
++
++	/* Qualify the transport resource defaults with the
++	 * capabilities of this particular device */
++	newxprt->sc_max_sge = min((size_t)devattr.max_sge,
++				  (size_t)RPCSVC_MAXPAGES);
++	newxprt->sc_max_requests = min((size_t)devattr.max_qp_wr,
++				   (size_t)svcrdma_max_requests);
++	newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests;
++
++	newxprt->sc_ord =  min((size_t)devattr.max_qp_rd_atom,
++			       (size_t)svcrdma_ord);
++
++	newxprt->sc_pd = ib_alloc_pd(newxprt->sc_cm_id->device);
++	if (IS_ERR(newxprt->sc_pd)) {
++		dprintk("svcrdma: error creating PD for connect request\n");
++		goto errout;
++	}
++	newxprt->sc_sq_cq = ib_create_cq(newxprt->sc_cm_id->device,
++					 sq_comp_handler,
++					 cq_event_handler,
++					 newxprt,
++					 newxprt->sc_sq_depth,
++					 0);
++	if (IS_ERR(newxprt->sc_sq_cq)) {
++		dprintk("svcrdma: error creating SQ CQ for connect request\n");
++		goto errout;
++	}
++	newxprt->sc_rq_cq = ib_create_cq(newxprt->sc_cm_id->device,
++					 rq_comp_handler,
++					 cq_event_handler,
++					 newxprt,
++					 newxprt->sc_max_requests,
++					 0);
++	if (IS_ERR(newxprt->sc_rq_cq)) {
++		dprintk("svcrdma: error creating RQ CQ for connect request\n");
++		goto errout;
++	}
++
++	memset(&qp_attr, 0, sizeof qp_attr);
++	qp_attr.event_handler = qp_event_handler;
++	qp_attr.qp_context = &newxprt->sc_xprt;
++	qp_attr.cap.max_send_wr = newxprt->sc_sq_depth;
++	qp_attr.cap.max_recv_wr = newxprt->sc_max_requests;
++	qp_attr.cap.max_send_sge = newxprt->sc_max_sge;
++	qp_attr.cap.max_recv_sge = newxprt->sc_max_sge;
++	qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
++	qp_attr.qp_type = IB_QPT_RC;
++	qp_attr.send_cq = newxprt->sc_sq_cq;
++	qp_attr.recv_cq = newxprt->sc_rq_cq;
++	dprintk("svcrdma: newxprt->sc_cm_id=%p, newxprt->sc_pd=%p\n"
++		"    cm_id->device=%p, sc_pd->device=%p\n"
++		"    cap.max_send_wr = %d\n"
++		"    cap.max_recv_wr = %d\n"
++		"    cap.max_send_sge = %d\n"
++		"    cap.max_recv_sge = %d\n",
++		newxprt->sc_cm_id, newxprt->sc_pd,
++		newxprt->sc_cm_id->device, newxprt->sc_pd->device,
++		qp_attr.cap.max_send_wr,
++		qp_attr.cap.max_recv_wr,
++		qp_attr.cap.max_send_sge,
++		qp_attr.cap.max_recv_sge);
++
++	ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, &qp_attr);
++	if (ret) {
++		/*
++		 * XXX: This is a hack. We need a xx_request_qp interface
++		 * that will adjust the qp_attr's with a best-effort
++		 * number
++		 */
++		qp_attr.cap.max_send_sge -= 2;
++		qp_attr.cap.max_recv_sge -= 2;
++		ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd,
++				     &qp_attr);
++		if (ret) {
++			dprintk("svcrdma: failed to create QP, ret=%d\n", ret);
++			goto errout;
++		}
++		newxprt->sc_max_sge = qp_attr.cap.max_send_sge;
++		newxprt->sc_max_sge = qp_attr.cap.max_recv_sge;
++		newxprt->sc_sq_depth = qp_attr.cap.max_send_wr;
++		newxprt->sc_max_requests = qp_attr.cap.max_recv_wr;
++	}
++	newxprt->sc_qp = newxprt->sc_cm_id->qp;
++
++	/* Register all of physical memory */
++	newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
++					    IB_ACCESS_LOCAL_WRITE |
++					    IB_ACCESS_REMOTE_WRITE);
++	if (IS_ERR(newxprt->sc_phys_mr)) {
++		dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
++		goto errout;
++	}
++
++	/* Post receive buffers */
++	for (i = 0; i < newxprt->sc_max_requests; i++) {
++		ret = svc_rdma_post_recv(newxprt);
++		if (ret) {
++			dprintk("svcrdma: failure posting receive buffers\n");
++			goto errout;
++		}
++	}
++
++	/* Swap out the handler */
++	newxprt->sc_cm_id->event_handler = rdma_cma_handler;
++
++	/* Accept Connection */
++	set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
++	memset(&conn_param, 0, sizeof conn_param);
++	conn_param.responder_resources = 0;
++	conn_param.initiator_depth = newxprt->sc_ord;
++	ret = rdma_accept(newxprt->sc_cm_id, &conn_param);
++	if (ret) {
++		dprintk("svcrdma: failed to accept new connection, ret=%d\n",
++		       ret);
++		goto errout;
++	}
++
++	dprintk("svcrdma: new connection %p accepted with the following "
++		"attributes:\n"
++		"    local_ip        : %d.%d.%d.%d\n"
++		"    local_port	     : %d\n"
++		"    remote_ip       : %d.%d.%d.%d\n"
++		"    remote_port     : %d\n"
++		"    max_sge         : %d\n"
++		"    sq_depth        : %d\n"
++		"    max_requests    : %d\n"
++		"    ord             : %d\n",
++		newxprt,
++		NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
++			 route.addr.src_addr)->sin_addr.s_addr),
++		ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
++		       route.addr.src_addr)->sin_port),
++		NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
++			 route.addr.dst_addr)->sin_addr.s_addr),
++		ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
++		       route.addr.dst_addr)->sin_port),
++		newxprt->sc_max_sge,
++		newxprt->sc_sq_depth,
++		newxprt->sc_max_requests,
++		newxprt->sc_ord);
++
++	/* Set the local and remote addresses in the transport */
++	sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
++	svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa));
++	sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
++	svc_xprt_set_local(&newxprt->sc_xprt, sa, svc_addr_len(sa));
++
++	ib_req_notify_cq(newxprt->sc_sq_cq, IB_CQ_NEXT_COMP);
++	ib_req_notify_cq(newxprt->sc_rq_cq, IB_CQ_NEXT_COMP);
++	return &newxprt->sc_xprt;
++
++ errout:
++	dprintk("svcrdma: failure accepting new connection rc=%d.\n", ret);
++	rdma_destroy_id(newxprt->sc_cm_id);
++	rdma_destroy_xprt(newxprt);
++	return NULL;
++}
++
++/*
++ * Post an RQ WQE to the RQ when the rqst is being released. This
++ * effectively returns an RQ credit to the client. The rq_xprt_ctxt
++ * will be null if the request is deferred due to an RDMA_READ or the
++ * transport had no data ready (EAGAIN). Note that an RPC deferred in
++ * svc_process will still return the credit, this is because the data
++ * is copied and no longer consume a WQE/WC.
++ */
++static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
++{
++	int err;
++	struct svcxprt_rdma *rdma =
++		container_of(rqstp->rq_xprt, struct svcxprt_rdma, sc_xprt);
++	if (rqstp->rq_xprt_ctxt) {
++		BUG_ON(rqstp->rq_xprt_ctxt != rdma);
++		err = svc_rdma_post_recv(rdma);
++		if (err)
++			dprintk("svcrdma: failed to post an RQ WQE error=%d\n",
++				err);
++	}
++	rqstp->rq_xprt_ctxt = NULL;
++}
++
++/* Disable data ready events for this connection */
++static void svc_rdma_detach(struct svc_xprt *xprt)
++{
++	struct svcxprt_rdma *rdma =
++		container_of(xprt, struct svcxprt_rdma, sc_xprt);
++	unsigned long flags;
++
++	dprintk("svc: svc_rdma_detach(%p)\n", xprt);
++	/*
++	 * Shutdown the connection. This will ensure we don't get any
++	 * more events from the provider.
++	 */
++	rdma_disconnect(rdma->sc_cm_id);
++	rdma_destroy_id(rdma->sc_cm_id);
++
++	/* We may already be on the DTO list */
++	spin_lock_irqsave(&dto_lock, flags);
++	if (!list_empty(&rdma->sc_dto_q))
++		list_del_init(&rdma->sc_dto_q);
++	spin_unlock_irqrestore(&dto_lock, flags);
++}
++
++static void svc_rdma_free(struct svc_xprt *xprt)
++{
++	struct svcxprt_rdma *rdma = (struct svcxprt_rdma *)xprt;
++	dprintk("svcrdma: svc_rdma_free(%p)\n", rdma);
++	rdma_destroy_xprt(rdma);
++	kfree(rdma);
++}
++
++static void rdma_destroy_xprt(struct svcxprt_rdma *xprt)
++{
++	if (xprt->sc_qp && !IS_ERR(xprt->sc_qp))
++		ib_destroy_qp(xprt->sc_qp);
++
++	if (xprt->sc_sq_cq && !IS_ERR(xprt->sc_sq_cq))
++		ib_destroy_cq(xprt->sc_sq_cq);
++
++	if (xprt->sc_rq_cq && !IS_ERR(xprt->sc_rq_cq))
++		ib_destroy_cq(xprt->sc_rq_cq);
++
++	if (xprt->sc_phys_mr && !IS_ERR(xprt->sc_phys_mr))
++		ib_dereg_mr(xprt->sc_phys_mr);
++
++	if (xprt->sc_pd && !IS_ERR(xprt->sc_pd))
++		ib_dealloc_pd(xprt->sc_pd);
++
++	destroy_context_cache(xprt->sc_ctxt_head);
++}
++
++static int svc_rdma_has_wspace(struct svc_xprt *xprt)
++{
++	struct svcxprt_rdma *rdma =
++		container_of(xprt, struct svcxprt_rdma, sc_xprt);
++
++	/*
++	 * If there are fewer SQ WR available than required to send a
++	 * simple response, return false.
++	 */
++	if ((rdma->sc_sq_depth - atomic_read(&rdma->sc_sq_count) < 3))
++		return 0;
++
++	/*
++	 * ...or there are already waiters on the SQ,
++	 * return false.
++	 */
++	if (waitqueue_active(&rdma->sc_send_wait))
++		return 0;
++
++	/* Otherwise return true. */
++	return 1;
++}
++
++int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
++{
++	struct ib_send_wr *bad_wr;
++	int ret;
++
++	if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
++		return 0;
++
++	BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
++	BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
++		wr->opcode);
++	/* If the SQ is full, wait until an SQ entry is available */
++	while (1) {
++		spin_lock_bh(&xprt->sc_lock);
++		if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
++			spin_unlock_bh(&xprt->sc_lock);
++			atomic_inc(&rdma_stat_sq_starve);
++			/* See if we can reap some SQ WR */
++			sq_cq_reap(xprt);
++
++			/* Wait until SQ WR available if SQ still full */
++			wait_event(xprt->sc_send_wait,
++				   atomic_read(&xprt->sc_sq_count) <
++				   xprt->sc_sq_depth);
++			continue;
++		}
++		/* Bumped used SQ WR count and post */
++		ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
++		if (!ret)
++			atomic_inc(&xprt->sc_sq_count);
++		else
++			dprintk("svcrdma: failed to post SQ WR rc=%d, "
++			       "sc_sq_count=%d, sc_sq_depth=%d\n",
++			       ret, atomic_read(&xprt->sc_sq_count),
++			       xprt->sc_sq_depth);
++		spin_unlock_bh(&xprt->sc_lock);
++		break;
++	}
++	return ret;
++}
++
++int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
++			enum rpcrdma_errcode err)
++{
++	struct ib_send_wr err_wr;
++	struct ib_sge sge;
++	struct page *p;
++	struct svc_rdma_op_ctxt *ctxt;
++	u32 *va;
++	int length;
++	int ret;
++
++	p = svc_rdma_get_page();
++	va = page_address(p);
++
++	/* XDR encode error */
++	length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
++
++	/* Prepare SGE for local address */
++	sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
++				   p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
++	sge.lkey = xprt->sc_phys_mr->lkey;
++	sge.length = length;
++
++	ctxt = svc_rdma_get_context(xprt);
++	ctxt->count = 1;
++	ctxt->pages[0] = p;
++
++	/* Prepare SEND WR */
++	memset(&err_wr, 0, sizeof err_wr);
++	ctxt->wr_op = IB_WR_SEND;
++	err_wr.wr_id = (unsigned long)ctxt;
++	err_wr.sg_list = &sge;
++	err_wr.num_sge = 1;
++	err_wr.opcode = IB_WR_SEND;
++	err_wr.send_flags = IB_SEND_SIGNALED;
++
++	/* Post It */
++	ret = svc_rdma_send(xprt, &err_wr);
++	if (ret) {
++		dprintk("svcrdma: Error posting send = %d\n", ret);
++		svc_rdma_put_context(ctxt, 1);
++	}
++
++	return ret;
++}
 diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
 index 6f2112d..02c522c 100644
 --- a/net/sunrpc/xprtrdma/transport.c
@@ -925344,7 +1000109,7 @@
  	if (!skb)
  		return;
 diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
-index 92cfe8e..07fad7c 100644
+index 92cfe8e..339ca4a 100644
 --- a/net/x25/af_x25.c
 +++ b/net/x25/af_x25.c
 @@ -83,9 +83,9 @@ struct compat_x25_subscrip_struct {
@@ -925359,6 +1000124,15 @@
  
  	called_len  = (*p >> 0) & 0x0F;
  	calling_len = (*p >> 4) & 0x0F;
+@@ -1652,7 +1652,7 @@ static int __init x25_init(void)
+ 
+ 	register_netdevice_notifier(&x25_dev_notifier);
+ 
+-	printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");
++	printk(KERN_INFO "X.25 for Linux Version 0.2\n");
+ 
+ #ifdef CONFIG_SYSCTL
+ 	x25_register_sysctl();
 diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
 index a59b77f..6ebda25 100644
 --- a/net/x25/sysctl_net_x25.c
@@ -925607,10 +1000381,198 @@
  obj-$(CONFIG_XFRM_USER) += xfrm_user.o
  
 diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
-index 1686f64..b5c5347 100644
+index 1686f64..6cc1525 100644
 --- a/net/xfrm/xfrm_algo.c
 +++ b/net/xfrm/xfrm_algo.c
-@@ -486,7 +486,6 @@ EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx);
+@@ -28,6 +28,105 @@
+  * that instantiated crypto transforms have correct parameters for IPsec
+  * purposes.
+  */
++static struct xfrm_algo_desc aead_list[] = {
++{
++	.name = "rfc4106(gcm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 64,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++{
++	.name = "rfc4106(gcm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 96,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++{
++	.name = "rfc4106(gcm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 128,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++{
++	.name = "rfc4309(ccm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 64,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++{
++	.name = "rfc4309(ccm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 96,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++{
++	.name = "rfc4309(ccm(aes))",
++
++	.uinfo = {
++		.aead = {
++			.icv_truncbits = 128,
++		}
++	},
++
++	.desc = {
++		.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
++		.sadb_alg_ivlen = 8,
++		.sadb_alg_minbits = 128,
++		.sadb_alg_maxbits = 256
++	}
++},
++};
++
+ static struct xfrm_algo_desc aalg_list[] = {
+ {
+ 	.name = "hmac(digest_null)",
+@@ -332,6 +431,11 @@ static struct xfrm_algo_desc calg_list[] = {
+ },
+ };
+ 
++static inline int aead_entries(void)
++{
++	return ARRAY_SIZE(aead_list);
++}
++
+ static inline int aalg_entries(void)
+ {
+ 	return ARRAY_SIZE(aalg_list);
+@@ -354,25 +458,32 @@ struct xfrm_algo_list {
+ 	u32 mask;
+ };
+ 
++static const struct xfrm_algo_list xfrm_aead_list = {
++	.algs = aead_list,
++	.entries = ARRAY_SIZE(aead_list),
++	.type = CRYPTO_ALG_TYPE_AEAD,
++	.mask = CRYPTO_ALG_TYPE_MASK,
++};
++
+ static const struct xfrm_algo_list xfrm_aalg_list = {
+ 	.algs = aalg_list,
+ 	.entries = ARRAY_SIZE(aalg_list),
+ 	.type = CRYPTO_ALG_TYPE_HASH,
+-	.mask = CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC,
++	.mask = CRYPTO_ALG_TYPE_HASH_MASK,
+ };
+ 
+ static const struct xfrm_algo_list xfrm_ealg_list = {
+ 	.algs = ealg_list,
+ 	.entries = ARRAY_SIZE(ealg_list),
+ 	.type = CRYPTO_ALG_TYPE_BLKCIPHER,
+-	.mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
++	.mask = CRYPTO_ALG_TYPE_BLKCIPHER_MASK,
+ };
+ 
+ static const struct xfrm_algo_list xfrm_calg_list = {
+ 	.algs = calg_list,
+ 	.entries = ARRAY_SIZE(calg_list),
+ 	.type = CRYPTO_ALG_TYPE_COMPRESS,
+-	.mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
++	.mask = CRYPTO_ALG_TYPE_MASK,
+ };
+ 
+ static struct xfrm_algo_desc *xfrm_find_algo(
+@@ -461,6 +572,33 @@ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
+ }
+ EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
+ 
++struct xfrm_aead_name {
++	const char *name;
++	int icvbits;
++};
++
++static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
++				const void *data)
++{
++	const struct xfrm_aead_name *aead = data;
++	const char *name = aead->name;
++
++	return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
++	       !strcmp(name, entry->name);
++}
++
++struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, int probe)
++{
++	struct xfrm_aead_name data = {
++		.name = name,
++		.icvbits = icv_len,
++	};
++
++	return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
++			      probe);
++}
++EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
++
+ struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
+ {
+ 	if (idx >= aalg_entries())
+@@ -486,7 +624,6 @@ EXPORT_SYMBOL_GPL(xfrm_ealg_get_byidx);
   */
  void xfrm_probe_algs(void)
  {
@@ -925618,7 +1000580,7 @@
  	int i, status;
  
  	BUG_ON(in_softirq());
-@@ -511,7 +510,6 @@ void xfrm_probe_algs(void)
+@@ -511,7 +648,6 @@ void xfrm_probe_algs(void)
  		if (calg_list[i].available != status)
  			calg_list[i].available = status;
  	}
@@ -925652,7 +1000614,7 @@
  }
  
 diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
-index cb97fda..039e701 100644
+index cb97fda..4d6ebc6 100644
 --- a/net/xfrm/xfrm_input.c
 +++ b/net/xfrm/xfrm_input.c
 @@ -9,6 +9,8 @@
@@ -925664,10 +1000626,12 @@
  #include <net/ip.h>
  #include <net/xfrm.h>
  
-@@ -81,6 +83,180 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
+@@ -79,7 +81,180 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
+ 	*seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
+ 	return 0;
  }
- EXPORT_SYMBOL(xfrm_parse_spi);
- 
+-EXPORT_SYMBOL(xfrm_parse_spi);
++
 +int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 +{
 +	int err;
@@ -925745,12 +1000709,12 @@
 +		}
 +
 +		if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
-+			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
++			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH);
 +			goto drop_unlock;
 +		}
 +
 +		if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) {
-+			XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW);
++			XFRM_INC_STATS(LINUX_MIB_XFRMINSTATESEQERROR);
 +			goto drop_unlock;
 +		}
 +
@@ -925841,12 +1000805,11 @@
 +	return xfrm_input(skb, nexthdr, 0, -1);
 +}
 +EXPORT_SYMBOL(xfrm_input_resume);
-+
+ 
  void __init xfrm_input_init(void)
  {
- 	secpath_cachep = kmem_cache_create("secpath_cache",
 diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
-index f4bfd6c..f4a1047 100644
+index f4bfd6c..fc69036 100644
 --- a/net/xfrm/xfrm_output.c
 +++ b/net/xfrm/xfrm_output.c
 @@ -12,14 +12,18 @@
@@ -925869,7 +1000832,7 @@
  		- skb_headroom(skb);
  
  	if (nhead > 0)
-@@ -29,54 +33,63 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
+@@ -29,54 +33,64 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
  	return 0;
  }
  
@@ -925923,6 +1000886,7 @@
  		if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
  			XFRM_SKB_CB(skb)->seq = ++x->replay.oseq;
 +			if (unlikely(x->replay.oseq == 0)) {
++				XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR);
 +				x->replay.oseq--;
 +				xfrm_audit_state_replay_overflow(x, skb);
 +				err = -EOVERFLOW;
@@ -925957,7 +1000921,7 @@
  			err = -EHOSTUNREACH;
  			goto error_nolock;
  		}
-@@ -86,10 +99,97 @@ int xfrm_output(struct sk_buff *skb)
+@@ -86,10 +100,97 @@ int xfrm_output(struct sk_buff *skb)
  
  	err = 0;
  
@@ -926836,10 +1001800,10 @@
  }
 diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c
 new file mode 100644
-index 0000000..31d0354
+index 0000000..2b0db13
 --- /dev/null
 +++ b/net/xfrm/xfrm_proc.c
-@@ -0,0 +1,96 @@
+@@ -0,0 +1,97 @@
 +/*
 + * xfrm_proc.c
 + *
@@ -926864,7 +1001828,7 @@
 +	SNMP_MIB_ITEM("XfrmInNoStates", LINUX_MIB_XFRMINNOSTATES),
 +	SNMP_MIB_ITEM("XfrmInStateProtoError", LINUX_MIB_XFRMINSTATEPROTOERROR),
 +	SNMP_MIB_ITEM("XfrmInStateModeError", LINUX_MIB_XFRMINSTATEMODEERROR),
-+	SNMP_MIB_ITEM("XfrmInSeqOutOfWindow", LINUX_MIB_XFRMINSEQOUTOFWINDOW),
++	SNMP_MIB_ITEM("XfrmInStateSeqError", LINUX_MIB_XFRMINSTATESEQERROR),
 +	SNMP_MIB_ITEM("XfrmInStateExpired", LINUX_MIB_XFRMINSTATEEXPIRED),
 +	SNMP_MIB_ITEM("XfrmInStateMismatch", LINUX_MIB_XFRMINSTATEMISMATCH),
 +	SNMP_MIB_ITEM("XfrmInStateInvalid", LINUX_MIB_XFRMINSTATEINVALID),
@@ -926878,6 +1001842,7 @@
 +	SNMP_MIB_ITEM("XfrmOutNoStates", LINUX_MIB_XFRMOUTNOSTATES),
 +	SNMP_MIB_ITEM("XfrmOutStateProtoError", LINUX_MIB_XFRMOUTSTATEPROTOERROR),
 +	SNMP_MIB_ITEM("XfrmOutStateModeError", LINUX_MIB_XFRMOUTSTATEMODEERROR),
++	SNMP_MIB_ITEM("XfrmOutStateSeqError", LINUX_MIB_XFRMOUTSTATESEQERROR),
 +	SNMP_MIB_ITEM("XfrmOutStateExpired", LINUX_MIB_XFRMOUTSTATEEXPIRED),
 +	SNMP_MIB_ITEM("XfrmOutPolBlock", LINUX_MIB_XFRMOUTPOLBLOCK),
 +	SNMP_MIB_ITEM("XfrmOutPolDead", LINUX_MIB_XFRMOUTPOLDEAD),
@@ -926937,7 +1001902,7 @@
 +	goto out;
 +}
 diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
-index f26aaac..3003503 100644
+index f26aaac..7ba65e8 100644
 --- a/net/xfrm/xfrm_state.c
 +++ b/net/xfrm/xfrm_state.c
 @@ -19,6 +19,7 @@
@@ -926962,7 +1001927,7 @@
  static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
  					 xfrm_address_t *saddr,
  					 u32 reqid,
-@@ -203,6 +211,7 @@ static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
+@@ -203,14 +211,15 @@ static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family)
  }
  
  static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
@@ -926970,6 +1001935,62 @@
  {
  	write_unlock_bh(&xfrm_state_afinfo_lock);
  }
+ 
+-int xfrm_register_type(struct xfrm_type *type, unsigned short family)
++int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
+ {
+ 	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+-	struct xfrm_type **typemap;
++	const struct xfrm_type **typemap;
+ 	int err = 0;
+ 
+ 	if (unlikely(afinfo == NULL))
+@@ -226,10 +235,10 @@ int xfrm_register_type(struct xfrm_type *type, unsigned short family)
+ }
+ EXPORT_SYMBOL(xfrm_register_type);
+ 
+-int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
++int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
+ {
+ 	struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
+-	struct xfrm_type **typemap;
++	const struct xfrm_type **typemap;
+ 	int err = 0;
+ 
+ 	if (unlikely(afinfo == NULL))
+@@ -245,11 +254,11 @@ int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
+ }
+ EXPORT_SYMBOL(xfrm_unregister_type);
+ 
+-static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
++static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
+ {
+ 	struct xfrm_state_afinfo *afinfo;
+-	struct xfrm_type **typemap;
+-	struct xfrm_type *type;
++	const struct xfrm_type **typemap;
++	const struct xfrm_type *type;
+ 	int modload_attempted = 0;
+ 
+ retry:
+@@ -272,7 +281,7 @@ retry:
+ 	return type;
+ }
+ 
+-static void xfrm_put_type(struct xfrm_type *type)
++static void xfrm_put_type(const struct xfrm_type *type)
+ {
+ 	module_put(type->owner);
+ }
+@@ -484,7 +493,7 @@ expired:
+ 		km_state_expired(x, 1, 0);
+ 
+ 	xfrm_audit_state_delete(x, err ? 0 : 1,
+-				audit_get_loginuid(current->audit_context), 0);
++				audit_get_loginuid(current), 0);
+ 
+ out:
+ 	spin_unlock(&x->lock);
 @@ -504,12 +513,9 @@ struct xfrm_state *xfrm_state_alloc(void)
  		INIT_HLIST_NODE(&x->bydst);
  		INIT_HLIST_NODE(&x->bysrc);
@@ -927051,7 +1002072,7 @@
  
  	if (likely(seq > x->replay.seq))
  		return 0;
-@@ -1624,14 +1632,18 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
+@@ -1624,16 +1632,19 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
  	if (diff >= min_t(unsigned int, x->props.replay_window,
  			  sizeof(x->replay.bitmap) * 8)) {
  		x->stats.replay_window++;
@@ -927070,18 +1002091,22 @@
 +	xfrm_audit_state_replay(x, skb, net_seq);
 +	return -EINVAL;
  }
- EXPORT_SYMBOL(xfrm_replay_check);
+-EXPORT_SYMBOL(xfrm_replay_check);
  
-@@ -1657,7 +1669,7 @@ void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
+ void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
+ {
+@@ -1655,9 +1666,8 @@ void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
+ 	if (xfrm_aevent_is_on())
+ 		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
  }
- EXPORT_SYMBOL(xfrm_replay_advance);
+-EXPORT_SYMBOL(xfrm_replay_advance);
  
 -static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
 +static LIST_HEAD(xfrm_km_list);
  static DEFINE_RWLOCK(xfrm_km_lock);
  
  void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
-@@ -1897,6 +1909,7 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
+@@ -1897,6 +1907,7 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
  }
  
  static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
@@ -927089,7 +1002114,7 @@
  {
  	read_unlock(&xfrm_state_afinfo_lock);
  }
-@@ -1996,73 +2009,172 @@ void __init xfrm_state_init(void)
+@@ -1996,73 +2007,172 @@ void __init xfrm_state_init(void)
  }
  
  #ifdef CONFIG_AUDITSYSCALL
@@ -927299,10 +1002324,145 @@
 +EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
  #endif /* CONFIG_AUDITSYSCALL */
 diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
-index c4f6419..e0ccdf2 100644
+index c4f6419..7833807 100644
 --- a/net/xfrm/xfrm_user.c
 +++ b/net/xfrm/xfrm_user.c
-@@ -1043,7 +1043,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p,
+@@ -31,6 +31,11 @@
+ #include <linux/in6.h>
+ #endif
+ 
++static inline int aead_len(struct xfrm_algo_aead *alg)
++{
++	return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
++}
++
+ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
+ {
+ 	struct nlattr *rt = attrs[type];
+@@ -68,6 +73,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
+ 	return 0;
+ }
+ 
++static int verify_aead(struct nlattr **attrs)
++{
++	struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
++	struct xfrm_algo_aead *algp;
++
++	if (!rt)
++		return 0;
++
++	algp = nla_data(rt);
++	if (nla_len(rt) < aead_len(algp))
++		return -EINVAL;
++
++	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
++	return 0;
++}
++
+ static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
+ 			   xfrm_address_t **addrp)
+ {
+@@ -119,20 +140,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
+ 	switch (p->id.proto) {
+ 	case IPPROTO_AH:
+ 		if (!attrs[XFRMA_ALG_AUTH]	||
++		    attrs[XFRMA_ALG_AEAD]	||
+ 		    attrs[XFRMA_ALG_CRYPT]	||
+ 		    attrs[XFRMA_ALG_COMP])
+ 			goto out;
+ 		break;
+ 
+ 	case IPPROTO_ESP:
+-		if ((!attrs[XFRMA_ALG_AUTH] &&
+-		     !attrs[XFRMA_ALG_CRYPT])	||
+-		    attrs[XFRMA_ALG_COMP])
++		if (attrs[XFRMA_ALG_COMP])
++			goto out;
++		if (!attrs[XFRMA_ALG_AUTH] &&
++		    !attrs[XFRMA_ALG_CRYPT] &&
++		    !attrs[XFRMA_ALG_AEAD])
++			goto out;
++		if ((attrs[XFRMA_ALG_AUTH] ||
++		     attrs[XFRMA_ALG_CRYPT]) &&
++		    attrs[XFRMA_ALG_AEAD])
+ 			goto out;
+ 		break;
+ 
+ 	case IPPROTO_COMP:
+ 		if (!attrs[XFRMA_ALG_COMP]	||
++		    attrs[XFRMA_ALG_AEAD]	||
+ 		    attrs[XFRMA_ALG_AUTH]	||
+ 		    attrs[XFRMA_ALG_CRYPT])
+ 			goto out;
+@@ -143,6 +172,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
+ 	case IPPROTO_ROUTING:
+ 		if (attrs[XFRMA_ALG_COMP]	||
+ 		    attrs[XFRMA_ALG_AUTH]	||
++		    attrs[XFRMA_ALG_AEAD]	||
+ 		    attrs[XFRMA_ALG_CRYPT]	||
+ 		    attrs[XFRMA_ENCAP]		||
+ 		    attrs[XFRMA_SEC_CTX]	||
+@@ -155,6 +185,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
+ 		goto out;
+ 	}
+ 
++	if ((err = verify_aead(attrs)))
++		goto out;
+ 	if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
+ 		goto out;
+ 	if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
+@@ -208,6 +240,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
+ 	return 0;
+ }
+ 
++static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
++		       struct nlattr *rta)
++{
++	struct xfrm_algo_aead *p, *ualg;
++	struct xfrm_algo_desc *algo;
++
++	if (!rta)
++		return 0;
++
++	ualg = nla_data(rta);
++
++	algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
++	if (!algo)
++		return -ENOSYS;
++	*props = algo->desc.sadb_alg_id;
++
++	p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
++	if (!p)
++		return -ENOMEM;
++
++	strcpy(p->alg_name, algo->name);
++	*algpp = p;
++	return 0;
++}
++
+ static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
+ {
+ 	int len = 0;
+@@ -286,6 +343,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
+ 
+ 	copy_from_user_state(x, p);
+ 
++	if ((err = attach_aead(&x->aead, &x->props.ealgo,
++			       attrs[XFRMA_ALG_AEAD])))
++		goto error;
+ 	if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
+ 				   xfrm_aalg_get_byname,
+ 				   attrs[XFRMA_ALG_AUTH])))
+@@ -510,6 +570,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
+ 	if (x->lastused)
+ 		NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
+ 
++	if (x->aead)
++		NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
+ 	if (x->aalg)
+ 		NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
+ 	if (x->ealg)
+@@ -1043,7 +1105,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p,
  	return xp;
   error:
  	*errp = err;
@@ -927311,7 +1002471,24 @@
  	return NULL;
  }
  
-@@ -1986,8 +1986,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
+@@ -1808,6 +1870,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
+ #undef XMSGSIZE
+ 
+ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
++	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
+ 	[XFRMA_ALG_AUTH]	= { .len = sizeof(struct xfrm_algo) },
+ 	[XFRMA_ALG_CRYPT]	= { .len = sizeof(struct xfrm_algo) },
+ 	[XFRMA_ALG_COMP]	= { .len = sizeof(struct xfrm_algo) },
+@@ -1972,6 +2035,8 @@ static int xfrm_notify_sa_flush(struct km_event *c)
+ static inline size_t xfrm_sa_len(struct xfrm_state *x)
+ {
+ 	size_t l = 0;
++	if (x->aead)
++		l += nla_total_size(aead_len(x->aead));
+ 	if (x->aalg)
+ 		l += nla_total_size(xfrm_alg_len(x->aalg));
+ 	if (x->ealg)
+@@ -1986,8 +2051,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
  	if (x->coaddr)
  		l += nla_total_size(sizeof(*x->coaddr));
  
@@ -927322,7 +1002499,7 @@
  
  	return l;
  }
-@@ -2420,7 +2420,7 @@ static void __exit xfrm_user_exit(void)
+@@ -2420,7 +2485,7 @@ static void __exit xfrm_user_exit(void)
  	xfrm_unregister_km(&netlink_mgr);
  	rcu_assign_pointer(xfrm_nl, NULL);
  	synchronize_rcu();
@@ -930260,6 +1005437,19 @@
  	@:
 +
  EOF
+diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
+index d802b5a..9ddf944 100644
+--- a/scripts/mod/file2alias.c
++++ b/scripts/mod/file2alias.c
+@@ -155,7 +155,7 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
+ 	 * Some modules (visor) have empty slots as placeholder for
+ 	 * run-time specification that results in catch-all alias
+ 	 */
+-	if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
++	if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass))
+ 		return;
+ 
+ 	/* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
 index 93ac52a..f8efc93 100644
 --- a/scripts/mod/modpost.c
@@ -935443,7 +1010633,7 @@
 +
 +__initcall(sel_netnode_init);
 diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
-index 2fa483f..a857405 100644
+index 2fa483f..0341567 100644
 --- a/security/selinux/selinuxfs.c
 +++ b/security/selinux/selinuxfs.c
 @@ -2,6 +2,11 @@
@@ -935496,7 +1010686,33 @@
  
  #define TMPBUFLEN	12
  static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
-@@ -263,6 +277,7 @@ static const struct file_operations sel_policyvers_ops = {
+@@ -158,9 +172,10 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
+ 		if (length)
+ 			goto out;
+ 		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+-			"enforcing=%d old_enforcing=%d auid=%u", new_value, 
+-			selinux_enforcing,
+-			audit_get_loginuid(current->audit_context));
++			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
++			new_value, selinux_enforcing,
++			audit_get_loginuid(current),
++			audit_get_sessionid(current));
+ 		selinux_enforcing = new_value;
+ 		if (selinux_enforcing)
+ 			avc_ss_reset(0);
+@@ -229,8 +244,9 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf,
+ 		if (length < 0)
+ 			goto out;
+ 		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
+-			"selinux=0 auid=%u",
+-			audit_get_loginuid(current->audit_context));
++			"selinux=0 auid=%u ses=%u",
++			audit_get_loginuid(current),
++			audit_get_sessionid(current));
+ 	}
+ 
+ 	length = count;
+@@ -263,6 +279,7 @@ static const struct file_operations sel_policyvers_ops = {
  /* declaration for sel_write_load */
  static int sel_make_bools(void);
  static int sel_make_classes(void);
@@ -935504,7 +1010720,7 @@
  
  /* declaration for sel_make_class_dirs */
  static int sel_make_dir(struct inode *dir, struct dentry *dentry,
-@@ -323,6 +338,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
+@@ -323,6 +340,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
  	}
  
  	ret = sel_make_classes();
@@ -935517,7 +1010733,19 @@
  	if (ret)
  		length = ret;
  	else
-@@ -1222,7 +1243,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
+@@ -335,8 +358,9 @@ out1:
+ 		(security_get_allow_unknown() ? "allow" : "deny")));
+ 
+ 	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
+-		"policy loaded auid=%u",
+-		audit_get_loginuid(current->audit_context));
++		"policy loaded auid=%u ses=%u",
++		audit_get_loginuid(current),
++		audit_get_sessionid(current));
+ out:
+ 	mutex_unlock(&sel_mutex);
+ 	vfree(data);
+@@ -1222,7 +1246,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
  static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
  { }
  
@@ -935526,7 +1010754,7 @@
  	.start		= sel_avc_stats_seq_start,
  	.next		= sel_avc_stats_seq_next,
  	.show		= sel_avc_stats_seq_show,
-@@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = {
+@@ -1399,6 +1423,24 @@ static const struct file_operations sel_perm_ops = {
  	.read		= sel_read_perm,
  };
  
@@ -935551,7 +1010779,7 @@
  static int sel_make_perm_files(char *objclass, int classvalue,
  				struct dentry *dir)
  {
-@@ -1545,6 +1584,36 @@ out:
+@@ -1545,6 +1587,36 @@ out:
  	return rc;
  }
  
@@ -935588,7 +1010816,7 @@
  static int sel_make_dir(struct inode *dir, struct dentry *dentry,
  			unsigned long *ino)
  {
-@@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
+@@ -1673,6 +1745,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
  
  	class_dir = dentry;
  
@@ -935752,7 +1010980,7 @@
  
  	unsigned int reject_unknown : 1;
 diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
-index f83b19d..f96dec1 100644
+index f83b19d..fced6bc 100644
 --- a/security/selinux/ss/services.c
 +++ b/security/selinux/ss/services.c
 @@ -16,12 +16,13 @@
@@ -935844,7 +1011072,22 @@
  	POLICY_RDLOCK;
  
  	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
-@@ -2046,6 +2054,91 @@ out:
+@@ -1897,11 +1905,12 @@ int security_set_bools(int len, int *values)
+ 		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
+ 			audit_log(current->audit_context, GFP_ATOMIC,
+ 				AUDIT_MAC_CONFIG_CHANGE,
+-				"bool=%s val=%d old_val=%d auid=%u",
++				"bool=%s val=%d old_val=%d auid=%u ses=%u",
+ 				policydb.p_bool_val_to_name[i],
+ 				!!values[i],
+ 				policydb.bool_val_to_struct[i]->state,
+-				audit_get_loginuid(current->audit_context));
++				audit_get_loginuid(current),
++				audit_get_sessionid(current));
+ 		}
+ 		if (values[i]) {
+ 			policydb.bool_val_to_struct[i]->state = 1;
+@@ -2046,6 +2055,91 @@ out:
  	return rc;
  }
  
@@ -935936,7 +1011179,7 @@
  static int get_classes_callback(void *k, void *d, void *args)
  {
  	struct class_datum *datum = d;
-@@ -2151,6 +2244,60 @@ int security_get_allow_unknown(void)
+@@ -2151,6 +2245,60 @@ int security_get_allow_unknown(void)
  	return policydb.allow_unknown;
  }
  
@@ -935997,7 +1011240,7 @@
  struct selinux_audit_rule {
  	u32 au_seqno;
  	struct context au_ctxt;
-@@ -2400,50 +2547,10 @@ void selinux_audit_set_callback(int (*callback)(void))
+@@ -2400,50 +2548,10 @@ void selinux_audit_set_callback(int (*callback)(void))
  }
  
  #ifdef CONFIG_NETLABEL
@@ -936049,7 +1011292,7 @@
   *
   * Description:
   * Attempt to cache the context in @ctx, which was derived from the packet in
-@@ -2452,60 +2559,46 @@ static void security_netlbl_cache_free(const void *data)
+@@ -2452,60 +2560,46 @@ static void security_netlbl_cache_free(const void *data)
   *
   */
  static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
@@ -936125,7 +1011368,7 @@
  
  	if (!ss_initialized) {
  		*sid = SECSID_NULL;
-@@ -2515,40 +2608,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+@@ -2515,40 +2609,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
  	POLICY_RDLOCK;
  
  	if (secattr->flags & NETLBL_SECATTR_CACHE) {
@@ -936172,7 +1011415,7 @@
  		if (ctx == NULL)
  			goto netlbl_secattr_to_sid_return;
  
-@@ -2558,7 +2624,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+@@ -2558,7 +2625,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
  		mls_import_netlbl_lvl(&ctx_new, secattr);
  		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
  			if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
@@ -936181,7 +1011424,7 @@
  				goto netlbl_secattr_to_sid_return;
  			ctx_new.range.level[1].cat.highbit =
  				ctx_new.range.level[0].cat.highbit;
-@@ -2575,7 +2641,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+@@ -2575,7 +2642,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
  		if (rc != 0)
  			goto netlbl_secattr_to_sid_return_cleanup;
  
@@ -936190,6 +1011433,14 @@
  
  		ebitmap_destroy(&ctx_new.range.level[0].cat);
  	} else {
+@@ -2626,7 +2693,6 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
+ 
+ netlbl_sid_to_secattr_failure:
+ 	POLICY_RDUNLOCK;
+-	netlbl_secattr_destroy(secattr);
+ 	return rc;
+ }
+ #endif /* CONFIG_NETLABEL */
 diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
 index e076039..7e15820 100644
 --- a/security/selinux/xfrm.c

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	Sat Feb  2 12:37:43 2008
@@ -1,4 +1,4 @@
-+ bugfix/all/patch-2.6.24-git10
++ bugfix/all/patch-2.6.24-git12
 + debian/version.patch
 + debian/kernelvariables.patch
 + debian/doc-build-parallel.patch

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra	Sat Feb  2 12:37:43 2008
@@ -32,10 +32,10 @@
 + bugfix/m68k/2.6.24/152-pci.diff m68k
 #+ bugfix/m68k/2.6.24/448-ide.diff m68k
 + bugfix/m68k/2.6.24/478-serial.diff m68k
-+ bugfix/m68k/2.6.24/atari-rom-isa.diff m68k
+#+ bugfix/m68k/2.6.24/atari-rom-isa.diff m68k
 + bugfix/m68k/2.6.24/atari-ethernec.diff m68k
 + bugfix/m68k/2.6.24/atari-aranym.diff m68k
-+ bugfix/m68k/2.6.24/atari-ethernat.diff m68k
+#+ bugfix/m68k/2.6.24/atari-ethernat.diff m68k
 
 + bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff m68k
 + bugfix/m68k/2.6.24/zorro-module-device-table.diff m68k



More information about the Kernel-svn-changes mailing list