[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(¤t->thread, 6);
+ loaddebug(¤t->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, ®54);
pci_read_config_byte(dev, 0x55, ®55);
@@ -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, ®42h);
++ pci_read_config_byte(dev, 0x42, ®42h);
+
+ 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, ®40);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44);
+- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48);
+- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a);
+- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54);
+- *
+- * 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, ®54);
pci_read_config_byte(dev, 0x55, ®55);
@@ -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, ®) &&
+ !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, ®);
-@@ -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, ®);
++ pci_read_config_dword(dev, basereg + 4, ®);
+ 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, ®54);
+@@ -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, ®dw);
++
++ 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, ®);
++
++ /* 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, ®dw);
-+
-+ 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, ®);
-+
-+ /* 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, ®w);
++ pci_read_config_word(pdev, reg_addr, ®w);
+ 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, ®48h);
++ pci_read_config_byte(pdev, 0x48, ®48h);
+ 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, ®48);
pci_read_config_word(dev, 0x4a, ®4a);
@@ -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, ®47);
++ pci_read_config_byte(dev, 0x47, ®47);
+
+ 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], ®, 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(¶m_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, ®);
- rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
-- rt2x00_set_field32(®, CSR14_TBCN, 1);
-+ rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
- rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
- rt2x00_set_field32(®, 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(®, LEDCSR_ON_PERIOD, 70);
- rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
--
-- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
-- rt2x00_set_field32(®, LEDCSR_LINK, 1);
-- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0);
-- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
-- rt2x00_set_field32(®, LEDCSR_LINK, 0);
-- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1);
-- } else {
-- rt2x00_set_field32(®, LEDCSR_LINK, 1);
-- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1);
-- }
--
-+ rt2x00_set_field32(®, LEDCSR_LINK,
-+ (rt2x00dev->led_mode != LED_MODE_ASUS));
-+ rt2x00_set_field32(®, 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, ®);
-- 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, ®);
-
-- 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, ®);
-@@ -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, ®);
-- if (queue == IEEE80211_TX_QUEUE_DATA0)
-- rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1);
-- else if (queue == IEEE80211_TX_QUEUE_DATA1)
-- rt2x00_set_field32(®, TXCSR0_KICK_TX, 1);
-- else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
-- rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1);
-+ rt2x00_set_field32(®, TXCSR0_KICK_PRIO,
-+ (queue == IEEE80211_TX_QUEUE_DATA0));
-+ rt2x00_set_field32(®, TXCSR0_KICK_TX,
-+ (queue == IEEE80211_TX_QUEUE_DATA1));
-+ rt2x00_set_field32(®, 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, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+- rt2x00_set_field32(®, CSR14_TBCN, 1);
++ rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(®, 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(®, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30);
+-
+- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+- rt2x00_set_field32(®, LEDCSR_LINK, 1);
+- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0);
+- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+- rt2x00_set_field32(®, LEDCSR_LINK, 0);
+- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1);
+- } else {
+- rt2x00_set_field32(®, LEDCSR_LINK, 1);
+- rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1);
+- }
+-
++ rt2x00_set_field32(®, LEDCSR_LINK,
++ (rt2x00dev->led_mode != LED_MODE_ASUS));
++ rt2x00_set_field32(®, 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, ®);
+- 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, ®);
+
+- 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, ®);
+@@ -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, ®);
+- if (queue == IEEE80211_TX_QUEUE_DATA0)
+- rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1);
+- else if (queue == IEEE80211_TX_QUEUE_DATA1)
+- rt2x00_set_field32(®, TXCSR0_KICK_TX, 1);
+- else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+- rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1);
++ rt2x00_set_field32(®, TXCSR0_KICK_PRIO,
++ (queue == IEEE80211_TX_QUEUE_DATA0));
++ rt2x00_set_field32(®, TXCSR0_KICK_TX,
++ (queue == IEEE80211_TX_QUEUE_DATA1));
++ rt2x00_set_field32(®, 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, ®);
++ 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, ®);
++ 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, ®32);
+- 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, ®16);
++ 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, ®16);
++ 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, ®32);
++ if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) {
++ capable = 0;
++ enabled = 0;
++ break;
++ }
++ pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16);
++ 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, ®16);
++ 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, ®16);
++ 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,
++ ®16);
++ 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, ®16);
++ 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, ®16);
++ 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, ®32);
++ *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, ®16);
++ *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, ®32);
++ 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, ®16);
++ 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, ®ion);
+ 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, ®ion);
+ 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, ®ion);
+ 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, ®);
+ 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, ®ion, 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, ®ion, 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, ®ion, 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, ®ion, 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, ®ion, 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(¤t_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, ®s->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, ®s->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 = ¤t->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(®ion->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, ©_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, ¶m);
-@@ -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