[linux-next] LinuxNextTracking branch, master, updated. next-20110624

batman at open-mesh.org batman at open-mesh.org
Fri Jun 24 16:09:33 CEST 2011


The following commit has been merged in the master branch:
commit 06f4e926d256d902dd9a53dcb400fd74974ce087
Merge: 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 d93515611bbc70c2fe4db232e5feb448ed8e4cc9
Author: Linus Torvalds <torvalds at linux-foundation.org>
Date:   Fri May 20 13:43:21 2011 -0700

    Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
    
    * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
      macvlan: fix panic if lowerdev in a bond
      tg3: Add braces around 5906 workaround.
      tg3: Fix NETIF_F_LOOPBACK error
      macvlan: remove one synchronize_rcu() call
      networking: NET_CLS_ROUTE4 depends on INET
      irda: Fix error propagation in ircomm_lmp_connect_response()
      irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
      irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
      rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
      be2net: Kill set but unused variable 'req' in lancer_fw_download()
      irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
      atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
      rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
      rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
      rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
      rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
      pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
      isdn: capi: Use pr_debug() instead of ifdefs.
      tg3: Update version to 3.119
      tg3: Apply rx_discards fix to 5719/5720
      ...
    
    Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
    as per Davem.

diff --combined Documentation/feature-removal-schedule.txt
index f6a24e8,46679e4..4cba260
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@@ -35,17 -35,6 +35,6 @@@ Who:	Luis R. Rodriguez <lrodriguez at athe
  
  ---------------------------
  
- What:	AR9170USB
- When:	2.6.40
- 
- Why:	This driver is deprecated and the firmware is no longer
- 	maintained. The replacement driver "carl9170" has been
- 	around for a while, so the devices are still supported.
- 
- Who:	Christian Lamparter <chunkeey at googlemail.com>
- 
- ---------------------------
- 
  What:	IRQF_SAMPLE_RANDOM
  Check:	IRQF_SAMPLE_RANDOM
  When:	July 2009
@@@ -387,6 -376,26 +376,6 @@@ Who:	Tejun Heo <tj at kernel.org
  
  ----------------------------
  
 -What:	Support for lcd_switch and display_get in asus-laptop driver
 -When:	March 2010
 -Why:	These two features use non-standard interfaces. There are the
 -	only features that really need multiple path to guess what's
 -	the right method name on a specific laptop.
 -
 -	Removing them will allow to remove a lot of code an significantly
 -	clean the drivers.
 -
 -	This will affect the backlight code which won't be able to know
 -	if the backlight is on or off. The platform display file will also be
 -	write only (like the one in eeepc-laptop).
 -
 -	This should'nt affect a lot of user because they usually know
 -	when their display is on or off.
 -
 -Who:	Corentin Chary <corentin.chary at gmail.com>
 -
 -----------------------------
 -
  What:	sysfs-class-rfkill state file
  When:	Feb 2014
  Files:	net/rfkill/core.c
@@@ -405,16 -414,6 +394,6 @@@ Who: 	anybody or Florian Mickler <flori
  
  ----------------------------
  
- What:	capifs
- When:	February 2011
- Files:	drivers/isdn/capi/capifs.*
- Why:	udev fully replaces this special file system that only contains CAPI
- 	NCCI TTY device nodes. User space (pppdcapiplugin) works without
- 	noticing the difference.
- Who:	Jan Kiszka <jan.kiszka at web.de>
- 
- ----------------------------
- 
  What:	KVM paravirt mmu host support
  When:	January 2011
  Why:	The paravirt mmu host support is slower than non-paravirt mmu, both
@@@ -460,6 -459,14 +439,6 @@@ Who:	Thomas Gleixner <tglx at linutronix.d
  
  ----------------------------
  
 -What:	The acpi_sleep=s4_nonvs command line option
 -When:	2.6.37
 -Files:	arch/x86/kernel/acpi/sleep.c
 -Why:	superseded by acpi_sleep=nonvs
 -Who:	Rafael J. Wysocki <rjw at sisk.pl>
 -
 -----------------------------
 -
  What: 	PCI DMA unmap state API
  When:	August 2012
  Why:	PCI DMA unmap state API (include/linux/pci-dma.h) was replaced
diff --combined MAINTAINERS
index d76d63a,e23cbd1..49a0bf3
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@@ -185,9 -185,10 +185,9 @@@ F:	Documentation/filesystems/9p.tx
  F:	fs/9p/
  
  A2232 SERIAL BOARD DRIVER
 -M:	Enver Haase <A2232 at gmx.net>
  L:	linux-m68k at lists.linux-m68k.org
 -S:	Maintained
 -F:	drivers/char/ser_a2232*
 +S:	Orphan
 +F:	drivers/staging/generic_serial/ser_a2232*
  
  AACRAID SCSI RAID DRIVER
  M:	Adaptec OEM Raid Solutions <aacraid at adaptec.com>
@@@ -405,8 -406,8 +405,8 @@@ S:	Maintaine
  F:	sound/oss/aedsp16.c
  
  AFFS FILE SYSTEM
 -M:	Roman Zippel <zippel at linux-m68k.org>
 -S:	Maintained
 +L:	linux-fsdevel at vger.kernel.org
 +S:	Orphan
  F:	Documentation/filesystems/affs.txt
  F:	fs/affs/
  
@@@ -877,13 -878,6 +877,13 @@@ F:	arch/arm/mach-mv78xx0
  F:	arch/arm/mach-orion5x/
  F:	arch/arm/plat-orion/
  
 +ARM/Orion SoC/Technologic Systems TS-78xx platform support
 +M:	Alexander Clouter <alex at digriz.org.uk>
 +L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
 +W:	http://www.digriz.org.uk/ts78xx/kernel
 +S:	Maintained
 +F:	arch/arm/mach-orion5x/ts78xx-*
 +
  ARM/MIOA701 MACHINE SUPPORT
  M:	Robert Jarzmik <robert.jarzmik at free.fr>
  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
@@@ -1032,13 -1026,12 +1032,13 @@@ W:	http://www.fluff.org/ben/linux
  S:	Maintained
  F:	arch/arm/mach-s3c64xx/
  
 -ARM/S5P ARM ARCHITECTURES
 +ARM/S5P EXYNOS ARM ARCHITECTURES
  M:	Kukjin Kim <kgene.kim at samsung.com>
  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
  L:	linux-samsung-soc at vger.kernel.org (moderated for non-subscribers)
  S:	Maintained
  F:	arch/arm/mach-s5p*/
 +F:	arch/arm/mach-exynos*/
  
  ARM/SAMSUNG MOBILE MACHINE SUPPORT
  M:	Kyungmin Park <kyungmin.park at samsung.com>
@@@ -1071,7 -1064,7 +1071,7 @@@ F:	arch/arm/mach-shmobile
  F:	drivers/sh/
  
  ARM/TELECHIPS ARM ARCHITECTURE
 -M:	"Hans J. Koch" <hjk at linutronix.de>
 +M:	"Hans J. Koch" <hjk at hansjkoch.de>
  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
  S:	Maintained
  F:	arch/arm/plat-tcc/
@@@ -1232,13 -1225,6 +1232,6 @@@ W:	http://wireless.kernel.org/en/users/
  S:	Supported
  F:	drivers/net/wireless/ath/ath9k/
  
- ATHEROS AR9170 WIRELESS DRIVER
- M:	Christian Lamparter <chunkeey at web.de>
- L:	linux-wireless at vger.kernel.org
- W:	http://wireless.kernel.org/en/users/Drivers/ar9170
- S:	Obsolete
- F:	drivers/net/wireless/ath/ar9170/
- 
  CARL9170 LINUX COMMUNITY WIRELESS DRIVER
  M:	Christian Lamparter <chunkeey at googlemail.com>
  L:	linux-wireless at vger.kernel.org
@@@ -1831,10 -1817,11 +1824,10 @@@ S:	Maintaine
  F:	drivers/platform/x86/compal-laptop.c
  
  COMPUTONE INTELLIPORT MULTIPORT CARD
 -M:	"Michael H. Warfield" <mhw at wittsend.com>
  W:	http://www.wittsend.com/computone.html
 -S:	Maintained
 +S:	Orphan
  F:	Documentation/serial/computone.txt
 -F:	drivers/char/ip2/
 +F:	drivers/staging/tty/ip2/
  
  CONEXANT ACCESSRUNNER USB DRIVER
  M:	Simon Arlott <cxacru at fire.lp0.eu>
@@@ -2017,7 -2004,7 +2010,7 @@@ F:	drivers/net/wan/cycx
  CYCLADES ASYNC MUX DRIVER
  W:	http://www.cyclades.com/
  S:	Orphan
 -F:	drivers/char/cyclades.c
 +F:	drivers/tty/cyclades.c
  F:	include/linux/cyclades.h
  
  CYCLADES PC300 DRIVER
@@@ -2131,8 -2118,8 +2124,8 @@@ L:	Eng.Linux at digi.co
  W:	http://www.digi.com
  S:	Orphan
  F:	Documentation/serial/digiepca.txt
 -F:	drivers/char/epca*
 -F:	drivers/char/digi*
 +F:	drivers/staging/tty/epca*
 +F:	drivers/staging/tty/digi*
  
  DIOLAN U2C-12 I2C DRIVER
  M:	Guenter Roeck <guenter.roeck at ericsson.com>
@@@ -2809,23 -2796,42 +2802,23 @@@ GPIO SUBSYSTE
  M:	Grant Likely <grant.likely at secretlab.ca>
  S:	Maintained
  T:	git git://git.secretlab.ca/git/linux-2.6.git
 -F:	Documentation/gpio/gpio.txt
 +F:	Documentation/gpio.txt
  F:	drivers/gpio/
  F:	include/linux/gpio*
  
 +GRE DEMULTIPLEXER DRIVER
 +M:	Dmitry Kozlov <xeb at mail.ru>
 +L:	netdev at vger.kernel.org
 +S:	Maintained
 +F:	net/ipv4/gre.c
 +F:	include/net/gre.h
 +
  GRETH 10/100/1G Ethernet MAC device driver
  M:	Kristoffer Glembo <kristoffer at gaisler.com>
  L:	netdev at vger.kernel.org
  S:	Maintained
  F:	drivers/net/greth*
  
 -HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 -M:	Frank Seidel <frank at f-seidel.de>
 -L:	platform-driver-x86 at vger.kernel.org
 -W:	http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 -S:	Maintained
 -F:	drivers/platform/x86/hdaps.c
 -
 -HWPOISON MEMORY FAILURE HANDLING
 -M:	Andi Kleen <andi at firstfloor.org>
 -L:	linux-mm at kvack.org
 -T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
 -S:	Maintained
 -F:	mm/memory-failure.c
 -F:	mm/hwpoison-inject.c
 -
 -HYPERVISOR VIRTUAL CONSOLE DRIVER
 -L:	linuxppc-dev at lists.ozlabs.org
 -S:	Odd Fixes
 -F:	drivers/tty/hvc/
 -
 -iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
 -M:	Peter Jones <pjones at redhat.com>
 -M:	Konrad Rzeszutek Wilk <konrad at kernel.org>
 -S:	Maintained
 -F:	drivers/firmware/iscsi_ibft*
 -
  GSPCA FINEPIX SUBDRIVER
  M:	Frank Zago <frank at zago.net>
  L:	linux-media at vger.kernel.org
@@@ -2876,26 -2882,6 +2869,26 @@@ T:	git git://git.kernel.org/pub/scm/lin
  S:	Maintained
  F:	drivers/media/video/gspca/
  
 +HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
 +M:	Frank Seidel <frank at f-seidel.de>
 +L:	platform-driver-x86 at vger.kernel.org
 +W:	http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 +S:	Maintained
 +F:	drivers/platform/x86/hdaps.c
 +
 +HWPOISON MEMORY FAILURE HANDLING
 +M:	Andi Kleen <andi at firstfloor.org>
 +L:	linux-mm at kvack.org
 +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
 +S:	Maintained
 +F:	mm/memory-failure.c
 +F:	mm/hwpoison-inject.c
 +
 +HYPERVISOR VIRTUAL CONSOLE DRIVER
 +L:	linuxppc-dev at lists.ozlabs.org
 +S:	Odd Fixes
 +F:	drivers/tty/hvc/
 +
  HARDWARE MONITORING
  M:	Jean Delvare <khali at linux-fr.org>
  M:	Guenter Roeck <guenter.roeck at ericsson.com>
@@@ -2946,8 -2932,8 +2939,8 @@@ F:	drivers/block/cciss
  F:	include/linux/cciss_ioctl.h
  
  HFS FILESYSTEM
 -M:	Roman Zippel <zippel at linux-m68k.org>
 -S:	Maintained
 +L:	linux-fsdevel at vger.kernel.org
 +S:	Orphan
  F:	Documentation/filesystems/hfs.txt
  F:	fs/hfs/
  
@@@ -3363,6 -3349,12 +3356,12 @@@ F:	Documentation/wimax/README.i2400
  F:	drivers/net/wimax/i2400m/
  F:	include/linux/wimax/i2400m.h
  
+ INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
+ M:	Stanislaw Gruszka <sgruszka at redhat.com>
+ L:	linux-wireless at vger.kernel.org
+ S:	Supported
+ F:	drivers/net/wireless/iwlegacy/
+ 
  INTEL WIRELESS WIFI LINK (iwlwifi)
  M:	Wey-Yi Guy <wey-yi.w.guy at intel.com>
  M:	Intel Linux Wireless <ilw at linux.intel.com>
@@@ -3479,12 -3471,6 +3478,12 @@@ F:	Documentation/isapnp.tx
  F:	drivers/pnp/isapnp/
  F:	include/linux/isapnp.h
  
 +iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER
 +M:	Peter Jones <pjones at redhat.com>
 +M:	Konrad Rzeszutek Wilk <konrad at kernel.org>
 +S:	Maintained
 +F:	drivers/firmware/iscsi_ibft*
 +
  ISCSI
  M:	Mike Christie <michaelc at cs.wisc.edu>
  L:	open-iscsi at googlegroups.com
@@@ -3814,7 -3800,7 +3813,7 @@@ M:	Rusty Russell <rusty at rustcorp.com.au
  L:	lguest at lists.ozlabs.org
  W:	http://lguest.ozlabs.org/
  S:	Odd Fixes
 -F:	Documentation/lguest/
 +F:	Documentation/virtual/lguest/
  F:	arch/x86/lguest/
  F:	drivers/lguest/
  F:	include/linux/lguest*.h
@@@ -4001,6 -3987,7 +4000,6 @@@ F:	arch/m32r
  
  M68K ARCHITECTURE
  M:	Geert Uytterhoeven <geert at linux-m68k.org>
 -M:	Roman Zippel <zippel at linux-m68k.org>
  L:	linux-m68k at lists.linux-m68k.org
  W:	http://www.linux-m68k.org/
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
@@@ -4090,7 -4077,7 +4089,7 @@@ F:	drivers/video/matrox/matroxfb_
  F:	include/linux/matroxfb.h
  
  MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 -M:	"Hans J. Koch" <hjk at linutronix.de>
 +M:	"Hans J. Koch" <hjk at hansjkoch.de>
  L:	lm-sensors at lm-sensors.org
  S:	Maintained
  F:	Documentation/hwmon/max6650
@@@ -4205,7 -4192,7 +4204,7 @@@ MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL C
  M:	Jiri Slaby <jirislaby at gmail.com>
  S:	Maintained
  F:	Documentation/serial/moxa-smartio
 -F:	drivers/char/mxser.*
 +F:	drivers/tty/mxser.*
  
  MSI LAPTOP SUPPORT
  M:	"Lee, Chun-Yi" <jlee at novell.com>
@@@ -4247,7 -4234,7 +4246,7 @@@ F:	sound/oss/msnd
  
  MULTITECH MULTIPORT CARD (ISICOM)
  S:	Orphan
 -F:	drivers/char/isicom.c
 +F:	drivers/tty/isicom.c
  F:	include/linux/isicom.h
  
  MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
@@@ -4385,6 -4372,7 +4384,7 @@@ S:	Maintaine
  F:	net/ipv4/
  F:	net/ipv6/
  F:	include/net/ip*
+ F:	arch/x86/net/*
  
  NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
  M:	Paul Moore <paul.moore at hp.com>
@@@ -4995,13 -4983,6 +4995,13 @@@ F:	Documentation/pps
  F:	drivers/pps/
  F:	include/linux/pps*.h
  
 +PPTP DRIVER
 +M:	Dmitry Kozlov <xeb at mail.ru>
 +L:	netdev at vger.kernel.org
 +S:	Maintained
 +F:	drivers/net/pptp.c
 +W:	http://sourceforge.net/projects/accel-pptp
 +
  PREEMPTIBLE KERNEL
  M:	Robert Love <rml at tech9.net>
  L:	kpreempt-tech at lists.sourceforge.net
@@@ -5293,14 -5274,14 +5293,14 @@@ F:	drivers/memstick/host/r592.
  RISCOM8 DRIVER
  S:	Orphan
  F:	Documentation/serial/riscom8.txt
 -F:	drivers/char/riscom8*
 +F:	drivers/staging/tty/riscom8*
  
  ROCKETPORT DRIVER
  P:	Comtrol Corp.
  W:	http://www.comtrol.com
  S:	Maintained
  F:	Documentation/serial/rocket.txt
 -F:	drivers/char/rocket*
 +F:	drivers/tty/rocket*
  
  ROSE NETWORK LAYER
  M:	Ralf Baechle <ralf at linux-mips.org>
@@@ -5410,7 -5391,7 +5410,7 @@@ F:	drivers/media/video/*7146
  F:	include/media/*7146*
  
  SAMSUNG AUDIO (ASoC) DRIVERS
 -M:	Jassi Brar <jassi.brar at samsung.com>
 +M:	Jassi Brar <jassisinghbrar at gmail.com>
  L:	alsa-devel at alsa-project.org (moderated for non-subscribers)
  S:	Supported
  F:	sound/soc/samsung
@@@ -5431,7 -5412,6 +5431,7 @@@ F:	include/linux/timex.
  F:	kernel/time/clocksource.c
  F:	kernel/time/time*.c
  F:	kernel/time/ntp.c
 +F:	drivers/clocksource
  
  TLG2300 VIDEO4LINUX-2 DRIVER
  M:	Huang Shijie <shijie8 at gmail.com>
@@@ -5612,9 -5592,9 +5612,9 @@@ F:	include/linux/ata.
  F:	include/linux/libata.h
  
  SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
 -M:	Jayamohan Kallickal <jayamohank at serverengines.com>
 +M:	Jayamohan Kallickal <jayamohan.kallickal at emulex.com>
  L:	linux-scsi at vger.kernel.org
 -W:	http://www.serverengines.com
 +W:	http://www.emulex.com
  S:	Supported
  F:	drivers/scsi/be2iscsi/
  
@@@ -5832,6 -5812,13 +5832,13 @@@ S:	Maintaine
  F:	drivers/ssb/
  F:	include/linux/ssb/
  
+ BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+ M:	Rafał Miłecki <zajec5 at gmail.com>
+ L:	linux-wireless at vger.kernel.org
+ S:	Maintained
+ F:	drivers/bcma/
+ F:	include/linux/bcma/
+ 
  SONY VAIO CONTROL DEVICE DRIVER
  M:	Mattia Dongili <malattia at linux.it>
  L:	platform-driver-x86 at vger.kernel.org
@@@ -5937,9 -5924,10 +5944,9 @@@ F:	arch/arm/mach-spear6xx/spear600.
  F:	arch/arm/mach-spear6xx/spear600_evb.c
  
  SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 -M:	Roger Wolff <R.E.Wolff at BitWizard.nl>
 -S:	Supported
 +S:	Orphan
  F:	Documentation/serial/specialix.txt
 -F:	drivers/char/specialix*
 +F:	drivers/staging/tty/specialix*
  
  SPI SUBSYSTEM
  M:	David Brownell <dbrownell at users.sourceforge.net>
@@@ -5984,6 -5972,7 +5991,6 @@@ F:	arch/alpha/kernel/srm_env.
  
  STABLE BRANCH
  M:	Greg Kroah-Hartman <greg at kroah.com>
 -M:	Chris Wright <chrisw at sous-sol.org>
  L:	stable at kernel.org
  S:	Maintained
  
@@@ -6267,8 -6256,7 +6274,8 @@@ M:	Greg Ungerer <gerg at uclinux.org
  W:	http://www.uclinux.org/
  L:	uclinux-dev at uclinux.org  (subscribers-only)
  S:	Maintained
 -F:	arch/m68knommu/
 +F:	arch/m68k/*/*_no.*
 +F:	arch/m68k/include/asm/*_no.*
  
  UCLINUX FOR RENESAS H8/300 (H8300)
  M:	Yoshinori Sato <ysato at users.sourceforge.jp>
@@@ -6632,13 -6620,13 +6639,13 @@@ L:	user-mode-linux-devel at lists.sourcefo
  L:	user-mode-linux-user at lists.sourceforge.net
  W:	http://user-mode-linux.sourceforge.net
  S:	Maintained
 -F:	Documentation/uml/
 +F:	Documentation/virtual/uml/
  F:	arch/um/
  F:	fs/hostfs/
  F:	fs/hppfs/
  
  USERSPACE I/O (UIO)
 -M:	"Hans J. Koch" <hjk at linutronix.de>
 +M:	"Hans J. Koch" <hjk at hansjkoch.de>
  M:	Greg Kroah-Hartman <gregkh at suse.de>
  S:	Maintained
  F:	Documentation/DocBook/uio-howto.tmpl
@@@ -6936,18 -6924,6 +6943,18 @@@ T:	git git://git.kernel.org/pub/scm/lin
  S:	Maintained
  F:	drivers/platform/x86
  
 +XEN HYPERVISOR INTERFACE
 +M:	Jeremy Fitzhardinge <jeremy.fitzhardinge at citrix.com>
 +M:	Konrad Rzeszutek Wilk <konrad.wilk at oracle.com>
 +L:	xen-devel at lists.xensource.com (moderated for non-subscribers)
 +L:	virtualization at lists.linux-foundation.org
 +S:	Supported
 +F:	arch/x86/xen/
 +F:	drivers/*/xen-*front.c
 +F:	drivers/xen/
 +F:	arch/x86/include/asm/xen/
 +F:	include/xen/
 +
  XEN NETWORK BACKEND DRIVER
  M:	Ian Campbell <ian.campbell at citrix.com>
  L:	xen-devel at lists.xensource.com (moderated for non-subscribers)
@@@ -6969,6 -6945,18 +6976,6 @@@ S:	Supporte
  F:	arch/x86/xen/*swiotlb*
  F:	drivers/xen/*swiotlb*
  
 -XEN HYPERVISOR INTERFACE
 -M:	Jeremy Fitzhardinge <jeremy.fitzhardinge at citrix.com>
 -M:	Konrad Rzeszutek Wilk <konrad.wilk at oracle.com>
 -L:	xen-devel at lists.xensource.com (moderated for non-subscribers)
 -L:	virtualization at lists.linux-foundation.org
 -S:	Supported
 -F:	arch/x86/xen/
 -F:	drivers/*/xen-*front.c
 -F:	drivers/xen/
 -F:	arch/x86/include/asm/xen/
 -F:	include/xen/
 -
  XFS FILESYSTEM
  P:	Silicon Graphics Inc
  M:	Alex Elder <aelder at sgi.com>
@@@ -7038,6 -7026,20 +7045,6 @@@ M:	"Maciej W. Rozycki" <macro at linux-mip
  S:	Maintained
  F:	drivers/tty/serial/zs.*
  
 -GRE DEMULTIPLEXER DRIVER
 -M:	Dmitry Kozlov <xeb at mail.ru>
 -L:	netdev at vger.kernel.org
 -S:	Maintained
 -F:	net/ipv4/gre.c
 -F:	include/net/gre.h
 -
 -PPTP DRIVER
 -M:	Dmitry Kozlov <xeb at mail.ru>
 -L:	netdev at vger.kernel.org
 -S:	Maintained
 -F:	drivers/net/pptp.c
 -W:	http://sourceforge.net/projects/accel-pptp
 -
  THE REST
  M:	Linus Torvalds <torvalds at linux-foundation.org>
  L:	linux-kernel at vger.kernel.org
diff --combined arch/x86/Kconfig
index 4168e5d,2096cf1..880fcb6
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@@ -8,7 -8,6 +8,7 @@@ config 64BI
  
  config X86_32
  	def_bool !64BIT
 +	select CLKSRC_I8253
  
  config X86_64
  	def_bool 64BIT
@@@ -72,6 -71,8 +72,7 @@@ config X8
  	select GENERIC_IRQ_SHOW
  	select IRQ_FORCED_THREADING
  	select USE_GENERIC_SMP_HELPERS if SMP
 -	select ARCH_NO_SYSDEV_OPS
+ 	select HAVE_BPF_JIT if (X86_64 && NET)
  
  config INSTRUCTION_DECODER
  	def_bool (KPROBES || PERF_EVENTS)
@@@ -112,14 -113,7 +113,14 @@@ config MM
  	def_bool y
  
  config ZONE_DMA
 -	def_bool y
 +	bool "DMA memory allocation support" if EXPERT
 +	default y
 +	help
 +	  DMA memory allocation support allows devices with less than 32-bit
 +	  addressing to allocate within the first 16MB of address space.
 +	  Disable if no such devices will be used.
 +
 +	  If unsure, say Y.
  
  config SBUS
  	bool
@@@ -372,6 -366,17 +373,6 @@@ config X86_U
  # Following is an alphabetically sorted list of 32 bit extended platforms
  # Please maintain the alphabetic order if and when there are additions
  
 -config X86_ELAN
 -	bool "AMD Elan"
 -	depends on X86_32
 -	depends on X86_EXTENDED_PLATFORM
 -	---help---
 -	  Select this for an AMD Elan processor.
 -
 -	  Do not use this option for K6/Athlon/Opteron processors!
 -
 -	  If unsure, choose "PC-compatible" instead.
 -
  config X86_INTEL_CE
  	bool "CE4100 TV platform"
  	depends on PCI
@@@ -686,7 -691,6 +687,7 @@@ config AMD_IOMM
  	bool "AMD IOMMU support"
  	select SWIOTLB
  	select PCI_MSI
 +	select PCI_IOV
  	depends on X86_64 && PCI && ACPI
  	---help---
  	  With this option you can enable support for AMD IOMMU hardware in
@@@ -1171,7 -1175,7 +1172,7 @@@ comment "NUMA (Summit) requires SMP, 64
  config AMD_NUMA
  	def_bool y
  	prompt "Old style AMD Opteron NUMA detection"
 -	depends on X86_64 && NUMA && PCI
 +	depends on NUMA && PCI
  	---help---
  	  Enable AMD NUMA node topology detection.  You should say Y here if
  	  you have a multi processor AMD system. This uses an old method to
@@@ -1198,7 -1202,7 +1199,7 @@@ config NODES_SPAN_OTHER_NODE
  
  config NUMA_EMU
  	bool "NUMA emulation"
 -	depends on X86_64 && NUMA
 +	depends on NUMA
  	---help---
  	  Enable NUMA emulation. A flat machine will be split
  	  into virtual nodes when booted with "numa=fake=N", where N is the
@@@ -1220,10 -1224,6 +1221,10 @@@ config HAVE_ARCH_BOOTME
  	def_bool y
  	depends on X86_32 && NUMA
  
 +config HAVE_ARCH_ALLOC_REMAP
 +	def_bool y
 +	depends on X86_32 && NUMA
 +
  config ARCH_HAVE_MEMORY_PRESENT
  	def_bool y
  	depends on X86_32 && DISCONTIGMEM
@@@ -1232,9 -1232,13 +1233,9 @@@ config NEED_NODE_MEMMAP_SIZ
  	def_bool y
  	depends on X86_32 && (DISCONTIGMEM || SPARSEMEM)
  
 -config HAVE_ARCH_ALLOC_REMAP
 -	def_bool y
 -	depends on X86_32 && NUMA
 -
  config ARCH_FLATMEM_ENABLE
  	def_bool y
 -	depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA
 +	depends on X86_32 && !NUMA
  
  config ARCH_DISCONTIGMEM_ENABLE
  	def_bool y
@@@ -1244,16 -1248,20 +1245,16 @@@ config ARCH_DISCONTIGMEM_DEFAUL
  	def_bool y
  	depends on NUMA && X86_32
  
 -config ARCH_PROC_KCORE_TEXT
 -	def_bool y
 -	depends on X86_64 && PROC_KCORE
 -
 -config ARCH_SPARSEMEM_DEFAULT
 -	def_bool y
 -	depends on X86_64
 -
  config ARCH_SPARSEMEM_ENABLE
  	def_bool y
  	depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD
  	select SPARSEMEM_STATIC if X86_32
  	select SPARSEMEM_VMEMMAP_ENABLE if X86_64
  
 +config ARCH_SPARSEMEM_DEFAULT
 +	def_bool y
 +	depends on X86_64
 +
  config ARCH_SELECT_MEMORY_MODEL
  	def_bool y
  	depends on ARCH_SPARSEMEM_ENABLE
@@@ -1262,10 -1270,6 +1263,10 @@@ config ARCH_MEMORY_PROB
  	def_bool X86_64
  	depends on MEMORY_HOTPLUG
  
 +config ARCH_PROC_KCORE_TEXT
 +	def_bool y
 +	depends on X86_64 && PROC_KCORE
 +
  config ILLEGAL_POINTER_VALUE
         hex
         default 0 if X86_32
@@@ -1700,6 -1704,10 +1701,6 @@@ config ARCH_ENABLE_MEMORY_HOTREMOV
  	def_bool y
  	depends on MEMORY_HOTPLUG
  
 -config HAVE_ARCH_EARLY_PFN_TO_NID
 -	def_bool X86_64
 -	depends on NUMA
 -
  config USE_PERCPU_NUMA_NODE_ID
  	def_bool y
  	depends on NUMA
@@@ -1841,7 -1849,7 +1842,7 @@@ config APM_ALLOW_INT
  
  endif # APM
  
 -source "arch/x86/kernel/cpu/cpufreq/Kconfig"
 +source "drivers/cpufreq/Kconfig"
  
  source "drivers/cpuidle/Kconfig"
  
@@@ -2069,7 -2077,7 +2070,7 @@@ config OLP
  	depends on !X86_PAE
  	select GPIOLIB
  	select OF
 -	select OF_PROMTREE if PROC_DEVICETREE
 +	select OF_PROMTREE
  	---help---
  	  Add support for detecting the unique features of the OLPC
  	  XO hardware.
diff --combined drivers/Kconfig
index 557a469,aca7067..61631ed
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@@ -68,6 -68,8 +68,8 @@@ source "drivers/watchdog/Kconfig
  
  source "drivers/ssb/Kconfig"
  
+ source "drivers/bcma/Kconfig"
+ 
  source "drivers/mfd/Kconfig"
  
  source "drivers/regulator/Kconfig"
@@@ -119,7 -121,4 +121,7 @@@ source "drivers/platform/Kconfig
  source "drivers/clk/Kconfig"
  
  source "drivers/hwspinlock/Kconfig"
 +
 +source "drivers/clocksource/Kconfig"
 +
  endmenu
diff --combined drivers/infiniband/hw/cxgb4/cm.c
index d7ee70f,6aa53cd..f660cd0
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@@ -315,8 -315,9 +315,9 @@@ static struct rtable *find_route(struc
  				 __be16 peer_port, u8 tos)
  {
  	struct rtable *rt;
+ 	struct flowi4 fl4;
  
- 	rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip,
+ 	rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
  				   peer_port, local_port, IPPROTO_TCP,
  				   tos, 0);
  	if (IS_ERR(rt))
@@@ -1198,7 -1199,9 +1199,7 @@@ static int pass_open_rpl(struct c4iw_de
  	}
  	PDBG("%s ep %p status %d error %d\n", __func__, ep,
  	     rpl->status, status2errno(rpl->status));
 -	ep->com.wr_wait.ret = status2errno(rpl->status);
 -	ep->com.wr_wait.done = 1;
 -	wake_up(&ep->com.wr_wait.wait);
 +	c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
  
  	return 0;
  }
@@@ -1232,7 -1235,9 +1233,7 @@@ static int close_listsrv_rpl(struct c4i
  	struct c4iw_listen_ep *ep = lookup_stid(t, stid);
  
  	PDBG("%s ep %p\n", __func__, ep);
 -	ep->com.wr_wait.ret = status2errno(rpl->status);
 -	ep->com.wr_wait.done = 1;
 -	wake_up(&ep->com.wr_wait.wait);
 +	c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
  	return 0;
  }
  
@@@ -1462,7 -1467,7 +1463,7 @@@ static int peer_close(struct c4iw_dev *
  	struct c4iw_qp_attributes attrs;
  	int disconnect = 1;
  	int release = 0;
 -	int closing = 0;
 +	int abort = 0;
  	struct tid_info *t = dev->rdev.lldi.tids;
  	unsigned int tid = GET_TID(hdr);
  
@@@ -1488,22 -1493,23 +1489,22 @@@
  		 * in rdma connection migration (see c4iw_accept_cr()).
  		 */
  		__state_set(&ep->com, CLOSING);
 -		ep->com.wr_wait.done = 1;
 -		ep->com.wr_wait.ret = -ECONNRESET;
  		PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
 -		wake_up(&ep->com.wr_wait.wait);
 +		c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
  		break;
  	case MPA_REP_SENT:
  		__state_set(&ep->com, CLOSING);
 -		ep->com.wr_wait.done = 1;
 -		ep->com.wr_wait.ret = -ECONNRESET;
  		PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
 -		wake_up(&ep->com.wr_wait.wait);
 +		c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
  		break;
  	case FPDU_MODE:
  		start_ep_timer(ep);
  		__state_set(&ep->com, CLOSING);
 -		closing = 1;
 +		attrs.next_state = C4IW_QP_STATE_CLOSING;
 +		abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
 +				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
  		peer_close_upcall(ep);
 +		disconnect = 1;
  		break;
  	case ABORTING:
  		disconnect = 0;
@@@ -1531,6 -1537,11 +1532,6 @@@
  		BUG_ON(1);
  	}
  	mutex_unlock(&ep->com.mutex);
 -	if (closing) {
 -		attrs.next_state = C4IW_QP_STATE_CLOSING;
 -		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
 -			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
 -	}
  	if (disconnect)
  		c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
  	if (release)
@@@ -1571,7 -1582,9 +1572,7 @@@ static int peer_abort(struct c4iw_dev *
  	/*
  	 * Wake up any threads in rdma_init() or rdma_fini().
  	 */
 -	ep->com.wr_wait.done = 1;
 -	ep->com.wr_wait.ret = -ECONNRESET;
 -	wake_up(&ep->com.wr_wait.wait);
 +	c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
  
  	mutex_lock(&ep->com.mutex);
  	switch (ep->com.state) {
@@@ -1698,14 -1711,14 +1699,14 @@@ static int terminate(struct c4iw_dev *d
  	ep = lookup_tid(t, tid);
  	BUG_ON(!ep);
  
 -	if (ep->com.qp) {
 +	if (ep && ep->com.qp) {
  		printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
  		       ep->com.qp->wq.sq.qid);
  		attrs.next_state = C4IW_QP_STATE_TERMINATE;
  		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
  			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
  	} else
 -		printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
 +		printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
  
  	return 0;
  }
@@@ -2284,8 -2297,14 +2285,8 @@@ static int fw6_msg(struct c4iw_dev *dev
  		ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
  		wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
  		PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
 -		if (wr_waitp) {
 -			if (ret)
 -				wr_waitp->ret = -ret;
 -			else
 -				wr_waitp->ret = 0;
 -			wr_waitp->done = 1;
 -			wake_up(&wr_waitp->wait);
 -		}
 +		if (wr_waitp)
 +			c4iw_wake_up(wr_waitp, ret ? -ret : 0);
  		kfree_skb(skb);
  		break;
  	case 2:
diff --combined drivers/net/acenic.c
index 01560bb,82260ca..d7c1bfe4
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@@ -68,7 -68,6 +68,7 @@@
  #include <linux/sockios.h>
  #include <linux/firmware.h>
  #include <linux/slab.h>
 +#include <linux/prefetch.h>
  
  #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
  #include <linux/if_vlan.h>
@@@ -2659,15 -2658,15 +2659,15 @@@ static int ace_get_settings(struct net_
  
  	link = readl(&regs->GigLnkState);
  	if (link & LNK_1000MB)
- 		ecmd->speed = SPEED_1000;
+ 		ethtool_cmd_speed_set(ecmd, SPEED_1000);
  	else {
  		link = readl(&regs->FastLnkState);
  		if (link & LNK_100MB)
- 			ecmd->speed = SPEED_100;
+ 			ethtool_cmd_speed_set(ecmd, SPEED_100);
  		else if (link & LNK_10MB)
- 			ecmd->speed = SPEED_10;
+ 			ethtool_cmd_speed_set(ecmd, SPEED_10);
  		else
- 			ecmd->speed = 0;
+ 			ethtool_cmd_speed_set(ecmd, 0);
  	}
  	if (link & LNK_FULL_DUPLEX)
  		ecmd->duplex = DUPLEX_FULL;
@@@ -2719,9 -2718,9 +2719,9 @@@ static int ace_set_settings(struct net_
  		link |= LNK_TX_FLOW_CTL_Y;
  	if (ecmd->autoneg == AUTONEG_ENABLE)
  		link |= LNK_NEGOTIATE;
- 	if (ecmd->speed != speed) {
+ 	if (ethtool_cmd_speed(ecmd) != speed) {
  		link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB);
- 		switch (speed) {
+ 		switch (ethtool_cmd_speed(ecmd)) {
  		case SPEED_1000:
  			link |= LNK_1000MB;
  			break;
diff --combined drivers/net/arm/etherh.c
index fbfb5b4,e252cd5..03e217a
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@@ -527,7 -527,7 +527,7 @@@ static void __init etherh_banner(void
   * Read the ethernet address string from the on board rom.
   * This is an ascii string...
   */
 -static int __init etherh_addr(char *addr, struct expansion_card *ec)
 +static int __devinit etherh_addr(char *addr, struct expansion_card *ec)
  {
  	struct in_chunk_dir cd;
  	char *s;
@@@ -591,10 -591,11 +591,11 @@@ static void etherh_get_drvinfo(struct n
  static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
  	cmd->supported	= etherh_priv(dev)->supported;
- 	cmd->speed	= SPEED_10;
+ 	ethtool_cmd_speed_set(cmd, SPEED_10);
  	cmd->duplex	= DUPLEX_HALF;
  	cmd->port	= dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC;
- 	cmd->autoneg	= dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ 	cmd->autoneg	= (dev->flags & IFF_AUTOMEDIA ?
+ 			   AUTONEG_ENABLE : AUTONEG_DISABLE);
  	return 0;
  }
  
@@@ -655,7 -656,7 +656,7 @@@ static const struct net_device_ops ethe
  static u32 etherh_regoffsets[16];
  static u32 etherm_regoffsets[16];
  
 -static int __init
 +static int __devinit
  etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
  {
  	const struct etherh_data *data = id->data;
diff --combined drivers/net/ehea/ehea_main.c
index 2c60435,ba763e0..6a0a8fc
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@@ -41,7 -41,6 +41,7 @@@
  #include <linux/memory.h>
  #include <asm/kexec.h>
  #include <linux/mutex.h>
 +#include <linux/prefetch.h>
  
  #include <net/ip.h>
  
@@@ -3263,10 -3262,12 +3263,12 @@@ struct ehea_port *ehea_setup_single_por
  	dev->netdev_ops = &ehea_netdev_ops;
  	ehea_set_ethtool_ops(dev);
  
+ 	dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+ 		      | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
  	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
  		      | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
  		      | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
- 		      | NETIF_F_LLTX;
+ 		      | NETIF_F_LLTX | NETIF_F_RXCSUM;
  	dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
  
  	if (use_lro)
diff --combined drivers/net/fs_enet/fs_enet-main.c
index 5131e61,a938894..21abb5c
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@@ -956,8 -956,6 +956,6 @@@ static const struct ethtool_ops fs_etht
  	.get_link = ethtool_op_get_link,
  	.get_msglevel = fs_get_msglevel,
  	.set_msglevel = fs_set_msglevel,
- 	.set_tx_csum = ethtool_op_set_tx_csum,	/* local! */
- 	.set_sg = ethtool_op_set_sg,
  	.get_regs = fs_get_regs,
  };
  
@@@ -998,10 -996,8 +996,10 @@@ static const struct net_device_ops fs_e
  #endif
  };
  
 +static struct of_device_id fs_enet_match[];
  static int __devinit fs_enet_probe(struct platform_device *ofdev)
  {
 +	const struct of_device_id *match;
  	struct net_device *ndev;
  	struct fs_enet_private *fep;
  	struct fs_platform_info *fpi;
@@@ -1009,15 -1005,14 +1007,15 @@@
  	const u8 *mac_addr;
  	int privsize, len, ret = -ENODEV;
  
 -	if (!ofdev->dev.of_match)
 +	match = of_match_device(fs_enet_match, &ofdev->dev);
 +	if (!match)
  		return -EINVAL;
  
  	fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
  	if (!fpi)
  		return -ENOMEM;
  
 -	if (!IS_FEC(ofdev->dev.of_match)) {
 +	if (!IS_FEC(match)) {
  		data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
  		if (!data || len != 4)
  			goto out_free_fpi;
@@@ -1052,7 -1047,7 +1050,7 @@@
  	fep->dev = &ofdev->dev;
  	fep->ndev = ndev;
  	fep->fpi = fpi;
 -	fep->ops = ofdev->dev.of_match->data;
 +	fep->ops = match->data;
  
  	ret = fep->ops->setup_data(ndev);
  	if (ret)
diff --combined drivers/net/ixgbe/ixgbe_main.c
index e145f2c,2dce3d0..fa01b0b
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@@ -51,8 -51,12 +51,12 @@@
  char ixgbe_driver_name[] = "ixgbe";
  static const char ixgbe_driver_string[] =
  			      "Intel(R) 10 Gigabit PCI Express Network Driver";
- 
- #define DRV_VERSION "3.2.9-k2"
+ #define MAJ 3
+ #define MIN 3
+ #define BUILD 8
+ #define KFIX 2
+ #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
+ 	__stringify(BUILD) "-k" __stringify(KFIX)
  const char ixgbe_driver_version[] = DRV_VERSION;
  static const char ixgbe_copyright[] =
  				"Copyright (c) 1999-2011 Intel Corporation.";
@@@ -120,6 -124,10 +124,10 @@@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pc
  	 board_82599 },
  	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T),
  	 board_X540 },
+ 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2),
+ 	 board_82599 },
+ 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS),
+ 	 board_82599 },
  
  	/* required last entry */
  	{0, }
@@@ -185,6 -193,22 +193,22 @@@ static inline void ixgbe_disable_sriov(
  	adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
  }
  
+ static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
+ {
+ 	if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
+ 	    !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
+ 		schedule_work(&adapter->service_task);
+ }
+ 
+ static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
+ {
+ 	BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
+ 
+ 	/* flush memory to make sure state is correct before next watchog */
+ 	smp_mb__before_clear_bit();
+ 	clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
+ }
+ 
  struct ixgbe_reg_info {
  	u32 ofs;
  	char *name;
@@@ -811,7 -835,19 +835,19 @@@ static inline bool ixgbe_check_tx_hang(
  #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
  	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
  
- static void ixgbe_tx_timeout(struct net_device *netdev);
+ /**
+  * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout
+  * @adapter: driver private struct
+  **/
+ static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter)
+ {
+ 
+ 	/* Do the reset outside of interrupt context */
+ 	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ 		adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ 		ixgbe_service_event_schedule(adapter);
+ 	}
+ }
  
  /**
   * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
@@@ -893,7 -929,7 +929,7 @@@ static bool ixgbe_clean_tx_irq(struct i
  			adapter->tx_timeout_count + 1, tx_ring->queue_index);
  
  		/* schedule immediate reset if we believe we hung */
- 		ixgbe_tx_timeout(adapter->netdev);
+ 		ixgbe_tx_timeout_reset(adapter);
  
  		/* the adapter is about to reset, no point in enabling stuff */
  		return true;
@@@ -943,8 -979,6 +979,6 @@@ static void ixgbe_update_rx_dca(struct 
  	rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
  	rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
  	rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
- 	rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
- 		    IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
  	IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl);
  }
  
@@@ -962,7 -996,6 +996,6 @@@ static void ixgbe_update_tx_dca(struct 
  		txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
  		txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
  		txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
  		IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl);
  		break;
  	case ixgbe_mac_82599EB:
@@@ -972,7 -1005,6 +1005,6 @@@
  		txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
  			   IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
  		txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- 		txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
  		IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl);
  		break;
  	default:
@@@ -1061,8 -1093,14 +1093,14 @@@ static int __ixgbe_notify_dca(struct de
  
  	return 0;
  }
- 
  #endif /* CONFIG_IXGBE_DCA */
+ 
+ static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc,
+ 				 struct sk_buff *skb)
+ {
+ 	skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+ }
+ 
  /**
   * ixgbe_receive_skb - Send a completed packet up the stack
   * @adapter: board private structure
@@@ -1454,6 -1492,8 +1492,8 @@@ static void ixgbe_clean_rx_irq(struct i
  		}
  
  		ixgbe_rx_checksum(adapter, rx_desc, skb);
+ 		if (adapter->netdev->features & NETIF_F_RXHASH)
+ 			ixgbe_rx_hash(rx_desc, skb);
  
  		/* probably a little skewed due to removing CRC */
  		total_rx_bytes += skb->len;
@@@ -1787,35 -1827,51 +1827,51 @@@ static void ixgbe_set_itr_msix(struct i
  }
  
  /**
-  * ixgbe_check_overtemp_task - worker thread to check over tempurature
-  * @work: pointer to work_struct containing our data
+  * ixgbe_check_overtemp_subtask - check for over tempurature
+  * @adapter: pointer to adapter
   **/
- static void ixgbe_check_overtemp_task(struct work_struct *work)
+ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
  {
  	struct ixgbe_hw *hw = &adapter->hw;
  	u32 eicr = adapter->interrupt_event;
  
- 	if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
  		return;
  
+ 	if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+ 	    !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT))
+ 		return;
+ 
+ 	adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ 
  	switch (hw->device_id) {
- 	case IXGBE_DEV_ID_82599_T3_LOM: {
- 		u32 autoneg;
- 		bool link_up = false;
+ 	case IXGBE_DEV_ID_82599_T3_LOM:
+ 		/*
+ 		 * Since the warning interrupt is for both ports
+ 		 * we don't have to check if:
+ 		 *  - This interrupt wasn't for our port.
+ 		 *  - We may have missed the interrupt so always have to
+ 		 *    check if we  got a LSC
+ 		 */
+ 		if (!(eicr & IXGBE_EICR_GPI_SDP0) &&
+ 		    !(eicr & IXGBE_EICR_LSC))
+ 			return;
+ 
+ 		if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) {
+ 			u32 autoneg;
+ 			bool link_up = false;
  
- 		if (hw->mac.ops.check_link)
  			hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
  
- 		if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
- 		    (eicr & IXGBE_EICR_LSC))
- 			/* Check if this is due to overtemp */
- 			if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
- 				break;
- 		return;
- 	}
+ 			if (link_up)
+ 				return;
+ 		}
+ 
+ 		/* Check if this is not due to overtemp */
+ 		if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP)
+ 			return;
+ 
+ 		break;
  	default:
  		if (!(eicr & IXGBE_EICR_GPI_SDP0))
  			return;
@@@ -1825,8 -1881,8 +1881,8 @@@
  	       "Network adapter has been stopped because it has over heated. "
  	       "Restart the computer. If the problem persists, "
  	       "power off the system and replace the adapter\n");
- 	/* write to clear the interrupt */
- 	IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+ 
+ 	adapter->interrupt_event = 0;
  }
  
  static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@@ -1848,15 -1904,19 +1904,19 @@@ static void ixgbe_check_sfp_event(struc
  	if (eicr & IXGBE_EICR_GPI_SDP2) {
  		/* Clear the interrupt */
  		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
- 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
- 			schedule_work(&adapter->sfp_config_module_task);
+ 		if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ 			adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
+ 			ixgbe_service_event_schedule(adapter);
+ 		}
  	}
  
  	if (eicr & IXGBE_EICR_GPI_SDP1) {
  		/* Clear the interrupt */
  		IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
- 		if (!test_bit(__IXGBE_DOWN, &adapter->state))
- 			schedule_work(&adapter->multispeed_fiber_task);
+ 		if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ 			adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+ 			ixgbe_service_event_schedule(adapter);
+ 		}
  	}
  }
  
@@@ -1870,7 -1930,7 +1930,7 @@@ static void ixgbe_check_lsc(struct ixgb
  	if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
  		IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
  		IXGBE_WRITE_FLUSH(hw);
- 		schedule_work(&adapter->watchdog_task);
+ 		ixgbe_service_event_schedule(adapter);
  	}
  }
  
@@@ -1898,26 -1958,32 +1958,32 @@@ static irqreturn_t ixgbe_msix_lsc(int i
  
  	switch (hw->mac.type) {
  	case ixgbe_mac_82599EB:
  	case ixgbe_mac_X540:
  		/* Handle Flow Director Full threshold interrupt */
  		if (eicr & IXGBE_EICR_FLOW_DIR) {
+ 			int reinit_count = 0;
  			int i;
- 			IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR);
- 			/* Disable transmits before FDIR Re-initialization */
- 			netif_tx_stop_all_queues(netdev);
  			for (i = 0; i < adapter->num_tx_queues; i++) {
- 				struct ixgbe_ring *tx_ring =
- 							    adapter->tx_ring[i];
+ 				struct ixgbe_ring *ring = adapter->tx_ring[i];
  				if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
- 						       &tx_ring->state))
- 					schedule_work(&adapter->fdir_reinit_task);
+ 						       &ring->state))
+ 					reinit_count++;
+ 			}
+ 			if (reinit_count) {
+ 				/* no more flow director interrupts until after init */
+ 				IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
+ 				eicr &= ~IXGBE_EICR_FLOW_DIR;
+ 				adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+ 				ixgbe_service_event_schedule(adapter);
+ 			}
+ 		}
+ 		ixgbe_check_sfp_event(adapter, eicr);
+ 		if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+ 		    ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
+ 			if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ 				adapter->interrupt_event = eicr;
+ 				adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ 				ixgbe_service_event_schedule(adapter);
  			}
  		}
  		break;
@@@ -1927,8 -1993,10 +1993,10 @@@
  
  	ixgbe_check_fan_failure(adapter, eicr);
  
+ 	/* re-enable the original interrupt state, no lsc, no queues */
  	if (!test_bit(__IXGBE_DOWN, &adapter->state))
- 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+ 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
+ 		                ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
  
  	return IRQ_HANDLED;
  }
@@@ -2513,8 -2581,11 +2581,11 @@@ static irqreturn_t ixgbe_intr(int irq, 
  		ixgbe_check_sfp_event(adapter, eicr);
  		if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
  		    ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
- 			adapter->interrupt_event = eicr;
- 			schedule_work(&adapter->check_overtemp_task);
+ 			if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ 				adapter->interrupt_event = eicr;
+ 				adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ 				ixgbe_service_event_schedule(adapter);
+ 			}
  		}
  		break;
  	default:
@@@ -2731,7 -2802,7 +2802,7 @@@ void ixgbe_configure_tx_ring(struct ixg
  
  	/* poll to verify queue is enabled */
  	do {
- 		msleep(1);
+ 		usleep_range(1000, 2000);
  		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
  	} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
  	if (!wait_loop)
@@@ -3023,7 -3094,7 +3094,7 @@@ static void ixgbe_rx_desc_queue_enable(
  		return;
  
  	do {
- 		msleep(1);
+ 		usleep_range(1000, 2000);
  		rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
  	} while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
  
@@@ -3178,7 -3249,9 +3249,9 @@@ static void ixgbe_configure_virtualizat
  	/* enable Tx loopback for VF/PF communication */
  	IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
  	/* Enable MAC Anti-Spoofing */
- 	hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0),
+ 	hw->mac.ops.set_mac_anti_spoofing(hw,
+ 					  (adapter->antispoofing_enabled =
+ 					   (adapter->num_vfs != 0)),
  					  adapter->num_vfs);
  }
  
@@@ -3487,7 -3560,7 +3560,7 @@@ static int ixgbe_write_uc_addr_list(str
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  	struct ixgbe_hw *hw = &adapter->hw;
  	unsigned int vfn = adapter->num_vfs;
- 	unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+ 	unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS;
  	int count = 0;
  
  	/* return ENOMEM indicating insufficient memory for addresses */
@@@ -3760,31 -3833,16 +3833,16 @@@ static inline bool ixgbe_is_sfp(struct 
   **/
  static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
  {
- 	struct ixgbe_hw *hw = &adapter->hw;
+ 	/*
+ 	 * We are assuming the worst case scenerio here, and that
+ 	 * is that an SFP was inserted/removed after the reset
+ 	 * but before SFP detection was enabled.  As such the best
+ 	 * solution is to just start searching as soon as we start
+ 	 */
+ 	if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ 		adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
  
- 		if (hw->phy.multispeed_fiber) {
- 			/*
- 			 * In multispeed fiber setups, the device may not have
- 			 * had a physical connection when the driver loaded.
- 			 * If that's the case, the initial link configuration
- 			 * couldn't get the MAC into 10G or 1G mode, so we'll
- 			 * never have a link status change interrupt fire.
- 			 * We need to try and force an autonegotiation
- 			 * session, then bring up link.
- 			 */
- 			if (hw->mac.ops.setup_sfp)
- 				hw->mac.ops.setup_sfp(hw);
- 			if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
- 				schedule_work(&adapter->multispeed_fiber_task);
- 		} else {
- 			/*
- 			 * Direct Attach Cu and non-multispeed fiber modules
- 			 * still need to be configured properly prior to
- 			 * attempting link.
- 			 */
- 			if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
- 				schedule_work(&adapter->sfp_config_module_task);
- 		}
+ 	adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
  }
  
  /**
@@@ -3860,9 -3918,10 +3918,10 @@@ static void ixgbe_setup_gpie(struct ixg
  	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
  		gpie |= IXGBE_SDP1_GPIEN;
  
- 	if (hw->mac.type == ixgbe_mac_82599EB)
+ 	if (hw->mac.type == ixgbe_mac_82599EB) {
  		gpie |= IXGBE_SDP1_GPIEN;
  		gpie |= IXGBE_SDP2_GPIEN;
+ 	}
  
  	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
  }
@@@ -3913,17 -3972,6 +3972,6 @@@ static int ixgbe_up_complete(struct ixg
  			e_crit(drv, "Fan has stopped, replace the adapter\n");
  	}
  
- 	/*
- 	 * For hot-pluggable SFP+ devices, a new SFP+ module may have
- 	 * arrived before interrupts were enabled but after probe.  Such
- 	 * devices wouldn't have their type identified yet. We need to
- 	 * kick off the SFP+ module setup first, then try to bring up link.
- 	 * If we're not hot-pluggable SFP+, we just need to configure link
- 	 * and bring it up.
- 	 */
- 	if (hw->phy.type == ixgbe_phy_none)
- 		schedule_work(&adapter->sfp_config_module_task);
- 
  	/* enable transmits */
  	netif_tx_start_all_queues(adapter->netdev);
  
@@@ -3931,7 -3979,7 +3979,7 @@@
  	 * link up interrupt but shouldn't be a problem */
  	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
  	adapter->link_check_timeout = jiffies;
- 	mod_timer(&adapter->watchdog_timer, jiffies);
+ 	mod_timer(&adapter->service_timer, jiffies);
  
  	/* Set PF Reset Done bit so PF/VF Mail Ops can work */
  	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
@@@ -3944,8 -3992,11 +3992,11 @@@
  void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
  {
  	WARN_ON(in_interrupt());
+ 	/* put off any impending NetWatchDogTimeout */
+ 	adapter->netdev->trans_start = jiffies;
+ 
  	while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
- 		msleep(1);
+ 		usleep_range(1000, 2000);
  	ixgbe_down(adapter);
  	/*
  	 * If SR-IOV enabled then wait a bit before bringing the adapter
@@@ -3972,10 -4023,20 +4023,20 @@@ void ixgbe_reset(struct ixgbe_adapter *
  	struct ixgbe_hw *hw = &adapter->hw;
  	int err;
  
+ 	/* lock SFP init bit to prevent race conditions with the watchdog */
+ 	while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ 		usleep_range(1000, 2000);
+ 
+ 	/* clear all SFP and link config related flags while holding SFP_INIT */
+ 	adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP |
+ 			     IXGBE_FLAG2_SFP_NEEDS_RESET);
+ 	adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+ 
  	err = hw->mac.ops.init_hw(hw);
  	switch (err) {
  	case 0:
  	case IXGBE_ERR_SFP_NOT_PRESENT:
+ 	case IXGBE_ERR_SFP_NOT_SUPPORTED:
  		break;
  	case IXGBE_ERR_MASTER_REQUESTS_PENDING:
  		e_dev_err("master disable timed out\n");
@@@ -3993,6 -4054,8 +4054,8 @@@
  		e_dev_err("Hardware Error: %d\n", err);
  	}
  
+ 	clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+ 
  	/* reprogram the RAR[0] in case user changed it. */
  	hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
  			    IXGBE_RAH_AV);
@@@ -4121,26 -4184,12 +4184,12 @@@ void ixgbe_down(struct ixgbe_adapter *a
  	struct net_device *netdev = adapter->netdev;
  	struct ixgbe_hw *hw = &adapter->hw;
  	u32 rxctrl;
- 	u32 txdctl;
  	int i;
  	int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
  
  	/* signal that we are down to the interrupt handler */
  	set_bit(__IXGBE_DOWN, &adapter->state);
  
- 	/* disable receive for all VFs and wait one second */
- 	if (adapter->num_vfs) {
- 		/* ping all the active vfs to let them know we are going down */
- 		ixgbe_ping_all_vfs(adapter);
- 
- 		/* Disable all VFTE/VFRE TX/RX */
- 		ixgbe_disable_tx_rx(adapter);
- 
- 		/* Mark all the VFs as inactive */
- 		for (i = 0 ; i < adapter->num_vfs; i++)
- 			adapter->vfinfo[i].clear_to_send = 0;
- 	}
- 
  	/* disable receives */
  	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
  	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
@@@ -4150,15 -4199,11 +4199,11 @@@
  		/* this call also flushes the previous write */
  		ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
  
- 	msleep(10);
+ 	usleep_range(10000, 20000);
  
  	netif_tx_stop_all_queues(netdev);
  
- 	clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- 	del_timer_sync(&adapter->sfp_timer);
- 	del_timer_sync(&adapter->watchdog_timer);
- 	cancel_work_sync(&adapter->watchdog_task);
- 
+ 	/* call carrier off first to avoid false dev_watchdog timeouts */
  	netif_carrier_off(netdev);
  	netif_tx_disable(netdev);
  
@@@ -4166,6 -4211,25 +4211,25 @@@
  
  	ixgbe_napi_disable_all(adapter);
  
+ 	adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
+ 			     IXGBE_FLAG2_RESET_REQUESTED);
+ 	adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+ 
+ 	del_timer_sync(&adapter->service_timer);
+ 
+ 	/* disable receive for all VFs and wait one second */
+ 	if (adapter->num_vfs) {
+ 		/* ping all the active vfs to let them know we are going down */
+ 		ixgbe_ping_all_vfs(adapter);
+ 
+ 		/* Disable all VFTE/VFRE TX/RX */
+ 		ixgbe_disable_tx_rx(adapter);
+ 
+ 		/* Mark all the VFs as inactive */
+ 		for (i = 0 ; i < adapter->num_vfs; i++)
+ 			adapter->vfinfo[i].clear_to_send = 0;
+ 	}
+ 
  	/* Cleanup the affinity_hint CPU mask memory and callback */
  	for (i = 0; i < num_q_vectors; i++) {
  		struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
@@@ -4175,21 -4239,13 +4239,13 @@@
  		free_cpumask_var(q_vector->affinity_mask);
  	}
  
  	/* disable transmits in the hardware now that interrupts are off */
  	for (i = 0; i < adapter->num_tx_queues; i++) {
  		u8 reg_idx = adapter->tx_ring[i]->reg_idx;
- 		txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
- 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
- 				(txdctl & ~IXGBE_TXDCTL_ENABLE));
+ 		IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH);
  	}
- 	/* Disable the Tx DMA engine on 82599 */
+ 
+ 	/* Disable the Tx DMA engine on 82599 and X540 */
  	switch (hw->mac.type) {
  	case ixgbe_mac_82599EB:
  	case ixgbe_mac_X540:
@@@ -4201,9 -4257,6 +4257,6 @@@
  		break;
  	}
  
- 	/* clear n-tuple filters that are cached */
- 	ethtool_ntuple_flush(netdev);
- 
  	if (!pci_channel_offline(adapter->pdev))
  		ixgbe_reset(adapter);
  
@@@ -4267,25 -4320,8 +4320,8 @@@ static void ixgbe_tx_timeout(struct net
  {
  	struct ixgbe_adapter *adapter = netdev_priv(netdev);
  
- 	adapter->tx_timeout_count++;
- 
  	/* Do the reset outside of interrupt context */
- 	schedule_work(&adapter->reset_task);
- }
- 
- static void ixgbe_reset_task(struct work_struct *work)
- {
- 	struct ixgbe_adapter *adapter;
- 	adapter = container_of(work, struct ixgbe_adapter, reset_task);
- 
- 	/* If we're already down or resetting, just bail */
- 	if (test_bit(__IXGBE_DOWN, &adapter->state) ||
- 	    test_bit(__IXGBE_RESETTING, &adapter->state))
- 		return;
- 
- 	ixgbe_dump(adapter);
- 	netdev_err(adapter->netdev, "Reset adapter\n");
- 	ixgbe_reinit_locked(adapter);
+ 	ixgbe_tx_timeout_reset(adapter);
  }
  
  /**
@@@ -4567,8 -4603,8 +4603,8 @@@ static inline bool ixgbe_cache_ring_rss
  #ifdef CONFIG_IXGBE_DCB
  
  /* ixgbe_get_first_reg_idx - Return first register index associated with ring */
- void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
- 			     unsigned int *tx, unsigned int *rx)
+ static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
+ 				    unsigned int *tx, unsigned int *rx)
  {
  	struct net_device *dev = adapter->netdev;
  	struct ixgbe_hw *hw = &adapter->hw;
@@@ -5100,6 -5136,11 +5136,6 @@@ err_set_interrupt
  	return err;
  }
  
 -static void ring_free_rcu(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct ixgbe_ring, rcu));
 -}
 -
  /**
   * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
   * @adapter: board private structure to clear interrupt scheme on
@@@ -5121,7 -5162,7 +5157,7 @@@ void ixgbe_clear_interrupt_scheme(struc
  		/* ixgbe_get_stats64() might access this ring, we must wait
  		 * a grace period before freeing it.
  		 */
 -		call_rcu(&ring->rcu, ring_free_rcu);
 +		kfree_rcu(ring, rcu);
  		adapter->rx_ring[i] = NULL;
  	}
  
@@@ -5133,57 -5174,6 +5169,6 @@@
  }
  
  /**
-  * ixgbe_sfp_timer - worker thread to find a missing module
-  * @data: pointer to our adapter struct
-  **/
- static void ixgbe_sfp_timer(unsigned long data)
- {
- 	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
- 
- 	/*
- 	 * Do the sfp_timer outside of interrupt context due to the
- 	 * delays that sfp+ detection requires
- 	 */
- 	schedule_work(&adapter->sfp_task);
- }
- 
- /**
-  * ixgbe_sfp_task - worker thread to find a missing module
-  * @work: pointer to work_struct containing our data
-  **/
- static void ixgbe_sfp_task(struct work_struct *work)
- {
- 	struct ixgbe_adapter *adapter = container_of(work,
- 						     struct ixgbe_adapter,
- 						     sfp_task);
- 	struct ixgbe_hw *hw = &adapter->hw;
- 
- 	if ((hw->phy.type == ixgbe_phy_nl) &&
- 	    (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
- 		s32 ret = hw->phy.ops.identify_sfp(hw);
- 		if (ret == IXGBE_ERR_SFP_NOT_PRESENT)
- 			goto reschedule;
- 		ret = hw->phy.ops.reset(hw);
- 		if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- 			e_dev_err("failed to initialize because an unsupported "
- 				  "SFP+ module type was detected.\n");
- 			e_dev_err("Reload the driver after installing a "
- 				  "supported module.\n");
- 			unregister_netdev(adapter->netdev);
- 		} else {
- 			e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
- 		}
- 		/* don't need this routine any more */
- 		clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- 	}
- 	return;
- reschedule:
- 	if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
- 		mod_timer(&adapter->sfp_timer,
- 			  round_jiffies(jiffies + (2 * HZ)));
- }
- 
- /**
   * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
   * @adapter: board private structure to initialize
   *
@@@ -5899,8 -5889,13 +5884,13 @@@ void ixgbe_update_stats(struct ixgbe_ad
  		hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
  		hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
  		break;
- 	case ixgbe_mac_82599EB:
  	case ixgbe_mac_X540:
+ 		/* OS2BMC stats are X540 only*/
+ 		hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
+ 		hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
+ 		hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC);
+ 		hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC);
+ 	case ixgbe_mac_82599EB:
  		hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
  		IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
  		hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
@@@ -5974,23 -5969,66 +5964,66 @@@
  }
  
  /**
-  * ixgbe_watchdog - Timer Call-back
-  * @data: pointer to adapter cast into an unsigned long
+  * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table
+  * @adapter - pointer to the device adapter structure
   **/
- static void ixgbe_watchdog(unsigned long data)
+ static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter)
  {
- 	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
  	struct ixgbe_hw *hw = &adapter->hw;
- 	u64 eics = 0;
  	int i;
  
- 	/*
- 	 *  Do the watchdog outside of interrupt context due to the lovely
- 	 * delays that some of the newer hardware requires
- 	 */
+ 	if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+ 		return;
+ 
+ 	adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
  
+ 	/* if interface is down do nothing */
  	if (test_bit(__IXGBE_DOWN, &adapter->state))
- 		goto watchdog_short_circuit;
+ 		return;
+ 
+ 	/* do nothing if we are not using signature filters */
+ 	if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE))
+ 		return;
+ 
+ 	adapter->fdir_overflow++;
+ 
+ 	if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
+ 		for (i = 0; i < adapter->num_tx_queues; i++)
+ 			set_bit(__IXGBE_TX_FDIR_INIT_DONE,
+ 			        &(adapter->tx_ring[i]->state));
+ 		/* re-enable flow director interrupts */
+ 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
+ 	} else {
+ 		e_err(probe, "failed to finish FDIR re-initialization, "
+ 		      "ignored adding FDIR ATR filters\n");
+ 	}
+ }
+ 
+ /**
+  * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts
+  * @adapter - pointer to the device adapter structure
+  *
+  * This function serves two purposes.  First it strobes the interrupt lines
+  * in order to make certain interrupts are occuring.  Secondly it sets the
+  * bits needed to check for TX hangs.  As a result we should immediately
+  * determine if a hang has occured.
+  */
+ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
+ {
+ 	struct ixgbe_hw *hw = &adapter->hw;
+ 	u64 eics = 0;
+ 	int i;
+ 
+ 	/* If we're down or resetting, just bail */
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ 	    test_bit(__IXGBE_RESETTING, &adapter->state))
+ 		return;
+ 
+ 	/* Force detection of hung controller */
+ 	if (netif_carrier_ok(adapter->netdev)) {
+ 		for (i = 0; i < adapter->num_tx_queues; i++)
+ 			set_check_for_tx_hang(adapter->tx_ring[i]);
+ 	}
  
  	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
  		/*
@@@ -6000,108 -6038,172 +6033,172 @@@
  		 */
  		IXGBE_WRITE_REG(hw, IXGBE_EICS,
  			(IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
- 		goto watchdog_reschedule;
- 	}
- 
- 	/* get one bit for every active tx/rx interrupt vector */
- 	for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
- 		struct ixgbe_q_vector *qv = adapter->q_vector[i];
- 		if (qv->rxr_count || qv->txr_count)
- 			eics |= ((u64)1 << i);
+ 	} else {
+ 		/* get one bit for every active tx/rx interrupt vector */
+ 		for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+ 			struct ixgbe_q_vector *qv = adapter->q_vector[i];
+ 			if (qv->rxr_count || qv->txr_count)
+ 				eics |= ((u64)1 << i);
+ 		}
  	}
  
- 	/* Cause software interrupt to ensure rx rings are cleaned */
+ 	/* Cause software interrupt to ensure rings are cleaned */
  	ixgbe_irq_rearm_queues(adapter, eics);
  
  }
  
  /**
-  * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_update_link - update the link status
+  * @adapter - pointer to the device adapter structure
+  * @link_speed - pointer to a u32 to store the link_speed
   **/
- static void ixgbe_multispeed_fiber_task(struct work_struct *work)
+ static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter)
  {
- 	struct ixgbe_adapter *adapter = container_of(work,
- 						     struct ixgbe_adapter,
- 						     multispeed_fiber_task);
  	struct ixgbe_hw *hw = &adapter->hw;
- 	u32 autoneg;
- 	bool negotiation;
+ 	u32 link_speed = adapter->link_speed;
+ 	bool link_up = adapter->link_up;
+ 	int i;
  
- 	adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
- 	autoneg = hw->phy.autoneg_advertised;
- 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
- 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
- 	hw->mac.autotry_restart = false;
- 	if (hw->mac.ops.setup_link)
- 		hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
- 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
- 	adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
+ 	if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE))
+ 		return;
+ 
+ 	if (hw->mac.ops.check_link) {
+ 		hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+ 	} else {
+ 		/* always assume link is up, if no check link function */
+ 		link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ 		link_up = true;
+ 	}
+ 	if (link_up) {
+ 		if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ 			for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+ 				hw->mac.ops.fc_enable(hw, i);
+ 		} else {
+ 			hw->mac.ops.fc_enable(hw, 0);
+ 		}
+ 	}
+ 
+ 	if (link_up ||
+ 	    time_after(jiffies, (adapter->link_check_timeout +
+ 				 IXGBE_TRY_LINK_TIMEOUT))) {
+ 		adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+ 		IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
+ 		IXGBE_WRITE_FLUSH(hw);
+ 	}
+ 
+ 	adapter->link_up = link_up;
+ 	adapter->link_speed = link_speed;
  }
  
  /**
-  * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_link_is_up - update netif_carrier status and
+  *                             print link up message
+  * @adapter - pointer to the device adapter structure
   **/
- static void ixgbe_sfp_config_module_task(struct work_struct *work)
+ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
  {
- 	struct ixgbe_adapter *adapter = container_of(work,
- 						     struct ixgbe_adapter,
- 						     sfp_config_module_task);
+ 	struct net_device *netdev = adapter->netdev;
  	struct ixgbe_hw *hw = &adapter->hw;
- 	u32 err;
+ 	u32 link_speed = adapter->link_speed;
+ 	bool flow_rx, flow_tx;
  
- 	adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
+ 	/* only continue if link was previously down */
+ 	if (netif_carrier_ok(netdev))
+ 		return;
  
- 	/* Time for electrical oscillations to settle down */
- 	msleep(100);
- 	err = hw->phy.ops.identify_sfp(hw);
+ 	adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
  
- 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- 		e_dev_err("failed to initialize because an unsupported SFP+ "
- 			  "module type was detected.\n");
- 		e_dev_err("Reload the driver after installing a supported "
- 			  "module.\n");
- 		unregister_netdev(adapter->netdev);
- 		return;
+ 	switch (hw->mac.type) {
+ 	case ixgbe_mac_82598EB: {
+ 		u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ 		u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ 		flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+ 		flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
+ 	}
+ 		break;
+ 	case ixgbe_mac_X540:
+ 	case ixgbe_mac_82599EB: {
+ 		u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+ 		u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+ 		flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ 		flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
+ 	}
+ 		break;
+ 	default:
+ 		flow_tx = false;
+ 		flow_rx = false;
+ 		break;
  	}
- 	if (hw->mac.ops.setup_sfp)
- 		hw->mac.ops.setup_sfp(hw);
+ 	e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
+ 	       (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+ 	       "10 Gbps" :
+ 	       (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+ 	       "1 Gbps" :
+ 	       (link_speed == IXGBE_LINK_SPEED_100_FULL ?
+ 	       "100 Mbps" :
+ 	       "unknown speed"))),
+ 	       ((flow_rx && flow_tx) ? "RX/TX" :
+ 	       (flow_rx ? "RX" :
+ 	       (flow_tx ? "TX" : "None"))));
  
- 	if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
- 		/* This will also work for DA Twinax connections */
- 		schedule_work(&adapter->multispeed_fiber_task);
- 	adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
+ 	netif_carrier_on(netdev);
+ #ifdef HAVE_IPLINK_VF_CONFIG
+ 	ixgbe_check_vf_rate_limit(adapter);
+ #endif /* HAVE_IPLINK_VF_CONFIG */
  }
  
  /**
-  * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table
-  * @work: pointer to work_struct containing our data
+  * ixgbe_watchdog_link_is_down - update netif_carrier status and
+  *                               print link down message
+  * @adapter - pointer to the adapter structure
   **/
- static void ixgbe_fdir_reinit_task(struct work_struct *work)
+ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter)
  {
- 	struct ixgbe_adapter *adapter = container_of(work,
- 						     struct ixgbe_adapter,
- 						     fdir_reinit_task);
+ 	struct net_device *netdev = adapter->netdev;
  	struct ixgbe_hw *hw = &adapter->hw;
+ 
+ 	adapter->link_up = false;
+ 	adapter->link_speed = 0;
+ 
+ 	/* only continue if link was up previously */
+ 	if (!netif_carrier_ok(netdev))
+ 		return;
+ 
+ 	/* poll for SFP+ cable when link is down */
+ 	if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB)
+ 		adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
+ 
+ 	e_info(drv, "NIC Link is Down\n");
+ 	netif_carrier_off(netdev);
+ }
+ 
+ /**
+  * ixgbe_watchdog_flush_tx - flush queues on link down
+  * @adapter - pointer to the device adapter structure
+  **/
+ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
+ {
  	int i;
+ 	int some_tx_pending = 0;
  
- 	if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
- 		for (i = 0; i < adapter->num_tx_queues; i++)
- 			set_bit(__IXGBE_TX_FDIR_INIT_DONE,
- 				&(adapter->tx_ring[i]->state));
- 	} else {
- 		e_err(probe, "failed to finish FDIR re-initialization, "
- 		      "ignored adding FDIR ATR filters\n");
+ 	if (!netif_carrier_ok(adapter->netdev)) {
+ 		for (i = 0; i < adapter->num_tx_queues; i++) {
+ 			struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+ 			if (tx_ring->next_to_use != tx_ring->next_to_clean) {
+ 				some_tx_pending = 1;
+ 				break;
+ 			}
+ 		}
+ 
+ 		if (some_tx_pending) {
+ 			/* We've lost link, so the controller stops DMA,
+ 			 * but we've got queued Tx work that's never going
+ 			 * to get done, so reset controller to flush Tx.
+ 			 * (Do the reset outside of interrupt context).
+ 			 */
+ 			adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ 		}
  	}
- 	/* Done FDIR Re-initialization, enable transmits */
- 	netif_tx_start_all_queues(adapter->netdev);
  }
  
  static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
@@@ -6124,133 -6226,186 +6221,186 @@@
  	e_warn(drv, "%d Spoofed packets detected\n", ssvpc);
  }
  
- static DEFINE_MUTEX(ixgbe_watchdog_lock);
+ /**
+  * ixgbe_watchdog_subtask - check and bring link up
+  * @adapter - pointer to the device adapter structure
+  **/
+ static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
+ {
+ 	/* if interface is down do nothing */
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state))
+ 		return;
+ 
+ 	ixgbe_watchdog_update_link(adapter);
+ 
+ 	if (adapter->link_up)
+ 		ixgbe_watchdog_link_is_up(adapter);
+ 	else
+ 		ixgbe_watchdog_link_is_down(adapter);
+ 
+ 	ixgbe_spoof_check(adapter);
+ 	ixgbe_update_stats(adapter);
+ 
+ 	ixgbe_watchdog_flush_tx(adapter);
+ }
  
  /**
-  * ixgbe_watchdog_task - worker thread to bring link up
-  * @work: pointer to work_struct containing our data
+  * ixgbe_sfp_detection_subtask - poll for SFP+ cable
+  * @adapter - the ixgbe adapter structure
   **/
- static void ixgbe_watchdog_task(struct work_struct *work)
+ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
  {
- 	struct ixgbe_adapter *adapter = container_of(work,
- 						     struct ixgbe_adapter,
- 						     watchdog_task);
- 	struct net_device *netdev = adapter->netdev;
  	struct ixgbe_hw *hw = &adapter->hw;
- 	u32 link_speed;
- 	bool link_up;
- 	int i;
- 	struct ixgbe_ring *tx_ring;
- 	int some_tx_pending = 0;
+ 	s32 err;
  
- 	mutex_lock(&ixgbe_watchdog_lock);
+ 	/* not searching for SFP so there is nothing to do here */
+ 	if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) &&
+ 	    !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+ 		return;
  
- 	link_up = adapter->link_up;
- 	link_speed = adapter->link_speed;
+ 	/* someone else is in init, wait until next service event */
+ 	if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ 		return;
  
- 	if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
- 		hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
- 		if (link_up) {
- #ifdef CONFIG_DCB
- 			if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- 				for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
- 					hw->mac.ops.fc_enable(hw, i);
- 			} else {
- 				hw->mac.ops.fc_enable(hw, 0);
- 			}
- #else
- 			hw->mac.ops.fc_enable(hw, 0);
- #endif
- 		}
+ 	err = hw->phy.ops.identify_sfp(hw);
+ 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ 		goto sfp_out;
  
- 		if (link_up ||
- 		    time_after(jiffies, (adapter->link_check_timeout +
- 					 IXGBE_TRY_LINK_TIMEOUT))) {
- 			adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
- 			IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
- 		}
- 		adapter->link_up = link_up;
- 		adapter->link_speed = link_speed;
+ 	if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+ 		/* If no cable is present, then we need to reset
+ 		 * the next time we find a good cable. */
+ 		adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
  	}
  
- 	if (link_up) {
- 		if (!netif_carrier_ok(netdev)) {
- 			bool flow_rx, flow_tx;
- 
- 			switch (hw->mac.type) {
- 			case ixgbe_mac_82598EB: {
- 				u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
- 				u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
- 				flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
- 				flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
- 			}
- 				break;
- 			case ixgbe_mac_82599EB:
- 			case ixgbe_mac_X540: {
- 				u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
- 				u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- 				flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
- 				flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
- 			}
- 				break;
- 			default:
- 				flow_tx = false;
- 				flow_rx = false;
- 				break;
- 			}
+ 	/* exit on error */
+ 	if (err)
+ 		goto sfp_out;
  
- 			e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
- 			       (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
- 			       "10 Gbps" :
- 			       (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
- 			       "1 Gbps" :
- 			       (link_speed == IXGBE_LINK_SPEED_100_FULL ?
- 			       "100 Mbps" :
- 			       "unknown speed"))),
- 			       ((flow_rx && flow_tx) ? "RX/TX" :
- 			       (flow_rx ? "RX" :
- 			       (flow_tx ? "TX" : "None"))));
- 
- 			netif_carrier_on(netdev);
- 			ixgbe_check_vf_rate_limit(adapter);
- 		} else {
- 			/* Force detection of hung controller */
- 			for (i = 0; i < adapter->num_tx_queues; i++) {
- 				tx_ring = adapter->tx_ring[i];
- 				set_check_for_tx_hang(tx_ring);
- 			}
- 		}
- 	} else {
- 		adapter->link_up = false;
- 		adapter->link_speed = 0;
- 		if (netif_carrier_ok(netdev)) {
- 			e_info(drv, "NIC Link is Down\n");
- 			netif_carrier_off(netdev);
- 		}
- 	}
+ 	/* exit if reset not needed */
+ 	if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+ 		goto sfp_out;
  
- 	if (!netif_carrier_ok(netdev)) {
- 		for (i = 0; i < adapter->num_tx_queues; i++) {
- 			tx_ring = adapter->tx_ring[i];
- 			if (tx_ring->next_to_use != tx_ring->next_to_clean) {
- 				some_tx_pending = 1;
- 				break;
- 			}
- 		}
+ 	adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET;
  
- 		if (some_tx_pending) {
- 			/* We've lost link, so the controller stops DMA,
- 			 * but we've got queued Tx work that's never going
- 			 * to get done, so reset controller to flush Tx.
- 			 * (Do the reset outside of interrupt context).
- 			 */
- 			 schedule_work(&adapter->reset_task);
- 		}
+ 	/*
+ 	 * A module may be identified correctly, but the EEPROM may not have
+ 	 * support for that module.  setup_sfp() will fail in that case, so
+ 	 * we should not allow that module to load.
+ 	 */
+ 	if (hw->mac.type == ixgbe_mac_82598EB)
+ 		err = hw->phy.ops.reset(hw);
+ 	else
+ 		err = hw->mac.ops.setup_sfp(hw);
+ 
+ 	if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ 		goto sfp_out;
+ 
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+ 	e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
+ 
+ sfp_out:
+ 	clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+ 
+ 	if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
+ 	    (adapter->netdev->reg_state == NETREG_REGISTERED)) {
+ 		e_dev_err("failed to initialize because an unsupported "
+ 			  "SFP+ module type was detected.\n");
+ 		e_dev_err("Reload the driver after installing a "
+ 			  "supported module.\n");
+ 		unregister_netdev(adapter->netdev);
  	}
+ }
  
- 	ixgbe_spoof_check(adapter);
- 	ixgbe_update_stats(adapter);
- 	mutex_unlock(&ixgbe_watchdog_lock);
+ /**
+  * ixgbe_sfp_link_config_subtask - set up link SFP after module install
+  * @adapter - the ixgbe adapter structure
+  **/
+ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
+ {
+ 	struct ixgbe_hw *hw = &adapter->hw;
+ 	u32 autoneg;
+ 	bool negotiation;
+ 
+ 	if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
+ 		return;
+ 
+ 	/* someone else is in init, wait until next service event */
+ 	if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ 		return;
+ 
+ 	adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+ 
+ 	autoneg = hw->phy.autoneg_advertised;
+ 	if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
+ 		hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+ 	hw->mac.autotry_restart = false;
+ 	if (hw->mac.ops.setup_link)
+ 		hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
+ 
+ 	adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+ 	adapter->link_check_timeout = jiffies;
+ 	clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+ }
+ 
+ /**
+  * ixgbe_service_timer - Timer Call-back
+  * @data: pointer to adapter cast into an unsigned long
+  **/
+ static void ixgbe_service_timer(unsigned long data)
+ {
+ 	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+ 	unsigned long next_event_offset;
+ 
+ 	/* poll faster when waiting for link */
+ 	if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
+ 		next_event_offset = HZ / 10;
+ 	else
+ 		next_event_offset = HZ * 2;
+ 
+ 	/* Reset the timer */
+ 	mod_timer(&adapter->service_timer, next_event_offset + jiffies);
+ 
+ 	ixgbe_service_event_schedule(adapter);
+ }
+ 
+ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
+ {
+ 	if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED))
+ 		return;
+ 
+ 	adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED;
+ 
+ 	/* If we're already down or resetting, just bail */
+ 	if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ 	    test_bit(__IXGBE_RESETTING, &adapter->state))
+ 		return;
+ 
+ 	ixgbe_dump(adapter);
+ 	netdev_err(adapter->netdev, "Reset adapter\n");
+ 	adapter->tx_timeout_count++;
+ 
+ 	ixgbe_reinit_locked(adapter);
+ }
+ 
+ /**
+  * ixgbe_service_task - manages and runs subtasks
+  * @work: pointer to work_struct containing our data
+  **/
+ static void ixgbe_service_task(struct work_struct *work)
+ {
+ 	struct ixgbe_adapter *adapter = container_of(work,
+ 						     struct ixgbe_adapter,
+ 						     service_task);
+ 
+ 	ixgbe_reset_subtask(adapter);
+ 	ixgbe_sfp_detection_subtask(adapter);
+ 	ixgbe_sfp_link_config_subtask(adapter);
+ 	ixgbe_check_overtemp_subtask(adapter);
+ 	ixgbe_watchdog_subtask(adapter);
+ 	ixgbe_fdir_reinit_subtask(adapter);
+ 	ixgbe_check_hang_subtask(adapter);
+ 
+ 	ixgbe_service_event_complete(adapter);
  }
  
  static int ixgbe_tso(struct ixgbe_adapter *adapter,
@@@ -7089,6 -7244,8 +7239,8 @@@ static void __devinit ixgbe_probe_vf(st
  #ifdef CONFIG_PCI_IOV
  	struct ixgbe_hw *hw = &adapter->hw;
  	int err;
+ 	int num_vf_macvlans, i;
+ 	struct vf_macvlans *mv_list;
  
  	if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs)
  		return;
@@@ -7105,6 -7262,26 +7257,26 @@@
  		e_err(probe, "Failed to enable PCI sriov: %d\n", err);
  		goto err_novfs;
  	}
+ 
+ 	num_vf_macvlans = hw->mac.num_rar_entries -
+ 		(IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
+ 
+ 	adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
+ 					     sizeof(struct vf_macvlans),
+ 					     GFP_KERNEL);
+ 	if (mv_list) {
+ 		/* Initialize list of VF macvlans */
+ 		INIT_LIST_HEAD(&adapter->vf_mvs.l);
+ 		for (i = 0; i < num_vf_macvlans; i++) {
+ 			mv_list->vf = -1;
+ 			mv_list->free = true;
+ 			mv_list->rar_entry = hw->mac.num_rar_entries -
+ 				(i + adapter->num_vfs + 1);
+ 			list_add(&mv_list->l, &adapter->vf_mvs.l);
+ 			mv_list++;
+ 		}
+ 	}
+ 
  	/* If call to enable VFs succeeded then allocate memory
  	 * for per VF control structures.
  	 */
@@@ -7275,22 -7452,6 +7447,6 @@@ static int __devinit ixgbe_probe(struc
  	hw->phy.mdio.mdio_read = ixgbe_mdio_read;
  	hw->phy.mdio.mdio_write = ixgbe_mdio_write;
  
- 	/* set up this timer and work struct before calling get_invariants
- 	 * which might start the timer
- 	 */
- 	init_timer(&adapter->sfp_timer);
- 	adapter->sfp_timer.function = ixgbe_sfp_timer;
- 	adapter->sfp_timer.data = (unsigned long) adapter;
- 
- 	INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
- 
- 	/* multispeed fiber has its own tasklet, called from GPI SDP1 context */
- 	INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
- 
- 	/* a new SFP+ module arrival, called from GPI SDP2 context */
- 	INIT_WORK(&adapter->sfp_config_module_task,
- 		  ixgbe_sfp_config_module_task);
- 
  	ii->get_invariants(hw);
  
  	/* setup the private structure */
@@@ -7324,17 -7485,9 +7480,9 @@@
  	hw->phy.reset_if_overtemp = false;
  	if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
  	    hw->mac.type == ixgbe_mac_82598EB) {
- 		/*
- 		 * Start a kernel thread to watch for a module to arrive.
- 		 * Only do this for 82598, since 82599 will generate
- 		 * interrupts on module arrival.
- 		 */
- 		set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- 		mod_timer(&adapter->sfp_timer,
- 			  round_jiffies(jiffies + (2 * HZ)));
  		err = 0;
  	} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- 		e_dev_err("failed to initialize because an unsupported SFP+ "
+ 		e_dev_err("failed to load because an unsupported SFP+ "
  			  "module type was detected.\n");
  		e_dev_err("Reload the driver after installing a supported "
  			  "module.\n");
@@@ -7356,9 -7509,16 +7504,16 @@@
  	netdev->features |= NETIF_F_TSO;
  	netdev->features |= NETIF_F_TSO6;
  	netdev->features |= NETIF_F_GRO;
+ 	netdev->features |= NETIF_F_RXHASH;
  
- 	if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ 	switch (adapter->hw.mac.type) {
+ 	case ixgbe_mac_82599EB:
+ 	case ixgbe_mac_X540:
  		netdev->features |= NETIF_F_SCTP_CSUM;
+ 		break;
+ 	default:
+ 		break;
+ 	}
  
  	netdev->vlan_features |= NETIF_F_TSO;
  	netdev->vlan_features |= NETIF_F_TSO6;
@@@ -7419,17 -7579,19 +7574,19 @@@
  	      (hw->mac.type == ixgbe_mac_82599EB))))
  		hw->mac.ops.disable_tx_laser(hw);
  
- 	init_timer(&adapter->watchdog_timer);
- 	adapter->watchdog_timer.function = ixgbe_watchdog;
- 	adapter->watchdog_timer.data = (unsigned long)adapter;
+ 	setup_timer(&adapter->service_timer, &ixgbe_service_timer,
+ 	            (unsigned long) adapter);
  
- 	INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
- 	INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task);
+ 	INIT_WORK(&adapter->service_task, ixgbe_service_task);
+ 	clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
  
  	err = ixgbe_init_interrupt_scheme(adapter);
  	if (err)
  		goto err_sw_init;
  
+ 	if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
+ 		netdev->features &= ~NETIF_F_RXHASH;
+ 
  	switch (pdev->device) {
  	case IXGBE_DEV_ID_82599_SFP:
  		/* Only this subdevice supports WOL */
@@@ -7458,8 -7620,8 +7615,8 @@@
  
  	/* print bus type/speed/width info */
  	e_dev_info("(PCI Express:%s:%s) %pM\n",
- 		   (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" :
- 		    hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" :
+ 		   (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
+ 		    hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" :
  		    "Unknown"),
  		   (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
  		    hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
@@@ -7508,13 -7670,6 +7665,6 @@@
  	/* carrier off reporting is important to ethtool even BEFORE open */
  	netif_carrier_off(netdev);
  
- 	if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
- 	    adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- 		INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
- 
- 	if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- 		INIT_WORK(&adapter->check_overtemp_task,
- 			  ixgbe_check_overtemp_task);
  #ifdef CONFIG_IXGBE_DCA
  	if (dca_add_requester(&pdev->dev) == 0) {
  		adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@@ -7541,11 -7696,7 +7691,7 @@@ err_sw_init
  err_eeprom:
  	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
  		ixgbe_disable_sriov(adapter);
- 	clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- 	del_timer_sync(&adapter->sfp_timer);
- 	cancel_work_sync(&adapter->sfp_task);
- 	cancel_work_sync(&adapter->multispeed_fiber_task);
- 	cancel_work_sync(&adapter->sfp_config_module_task);
+ 	adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
  	iounmap(hw->hw_addr);
  err_ioremap:
  	free_netdev(netdev);
@@@ -7573,24 -7724,7 +7719,7 @@@ static void __devexit ixgbe_remove(stru
  	struct net_device *netdev = adapter->netdev;
  
  	set_bit(__IXGBE_DOWN, &adapter->state);
- 
- 	/*
- 	 * The timers may be rescheduled, so explicitly disable them
- 	 * from being rescheduled.
- 	 */
- 	clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- 	del_timer_sync(&adapter->watchdog_timer);
- 	del_timer_sync(&adapter->sfp_timer);
- 
- 	cancel_work_sync(&adapter->watchdog_task);
- 	cancel_work_sync(&adapter->sfp_task);
- 	cancel_work_sync(&adapter->multispeed_fiber_task);
- 	cancel_work_sync(&adapter->sfp_config_module_task);
- 	if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
- 	    adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- 		cancel_work_sync(&adapter->fdir_reinit_task);
- 	if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- 		cancel_work_sync(&adapter->check_overtemp_task);
+ 	cancel_work_sync(&adapter->service_task);
  
  #ifdef CONFIG_IXGBE_DCA
  	if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
diff --combined drivers/net/macvlan.c
index d8e4e69,bbcf80a..d72a706
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@@ -70,16 -70,17 +70,17 @@@ static void macvlan_hash_add(struct mac
  	hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
  }
  
- static void macvlan_hash_del(struct macvlan_dev *vlan)
+ static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
  {
  	hlist_del_rcu(&vlan->hlist);
- 	synchronize_rcu();
+ 	if (sync)
+ 		synchronize_rcu();
  }
  
  static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
  					const unsigned char *addr)
  {
- 	macvlan_hash_del(vlan);
+ 	macvlan_hash_del(vlan, true);
  	/* Now that we are unhashed it is safe to change the device
  	 * address without confusing packet delivery.
  	 */
@@@ -345,7 -346,7 +346,7 @@@ static int macvlan_stop(struct net_devi
  	dev_uc_del(lowerdev, dev->dev_addr);
  
  hash_del:
- 	macvlan_hash_del(vlan);
+ 	macvlan_hash_del(vlan, !dev->dismantle);
  	return 0;
  }
  
@@@ -415,7 -416,7 +416,7 @@@ static struct lock_class_key macvlan_ne
  #define MACVLAN_FEATURES \
  	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
  	 NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
- 	 NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
+ 	 NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
  
  #define MACVLAN_STATE_MASK \
  	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@@ -517,12 -518,6 +518,6 @@@ static void macvlan_ethtool_get_drvinfo
  	snprintf(drvinfo->version, 32, "0.1");
  }
  
- static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
- {
- 	const struct macvlan_dev *vlan = netdev_priv(dev);
- 	return dev_ethtool_get_rx_csum(vlan->lowerdev);
- }
- 
  static int macvlan_ethtool_get_settings(struct net_device *dev,
  					struct ethtool_cmd *cmd)
  {
@@@ -530,18 -525,10 +525,10 @@@
  	return dev_ethtool_get_settings(vlan->lowerdev, cmd);
  }
  
  static const struct ethtool_ops macvlan_ethtool_ops = {
  	.get_link		= ethtool_op_get_link,
  	.get_settings		= macvlan_ethtool_get_settings,
- 	.get_rx_csum		= macvlan_ethtool_get_rx_csum,
  	.get_drvinfo		= macvlan_ethtool_get_drvinfo,
- 	.get_flags		= macvlan_ethtool_get_flags,
  };
  
  static const struct net_device_ops macvlan_netdev_ops = {
@@@ -598,18 -585,26 +585,18 @@@ static int macvlan_port_create(struct n
  	err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
  	if (err)
  		kfree(port);
- 
- 	dev->priv_flags |= IFF_MACVLAN_PORT;
+ 	else
+ 		dev->priv_flags |= IFF_MACVLAN_PORT;
  	return err;
  }
  
 -static void macvlan_port_rcu_free(struct rcu_head *head)
 -{
 -	struct macvlan_port *port;
 -
 -	port = container_of(head, struct macvlan_port, rcu);
 -	kfree(port);
 -}
 -
  static void macvlan_port_destroy(struct net_device *dev)
  {
  	struct macvlan_port *port = macvlan_port_get(dev);
  
  	dev->priv_flags &= ~IFF_MACVLAN_PORT;
  	netdev_rx_handler_unregister(dev);
 -	call_rcu(&port->rcu, macvlan_port_rcu_free);
 +	kfree_rcu(port, rcu);
  }
  
  static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@@ -791,6 -786,7 +778,7 @@@ static int macvlan_device_event(struct 
  	struct net_device *dev = ptr;
  	struct macvlan_dev *vlan, *next;
  	struct macvlan_port *port;
+ 	LIST_HEAD(list_kill);
  
  	if (!macvlan_port_exists(dev))
  		return NOTIFY_DONE;
@@@ -816,7 -812,9 +804,9 @@@
  			break;
  
  		list_for_each_entry_safe(vlan, next, &port->vlans, list)
- 			vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
+ 			vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
+ 		unregister_netdevice_many(&list_kill);
+ 		list_del(&list_kill);
  		break;
  	case NETDEV_PRE_TYPE_CHANGE:
  		/* Forbid underlaying device to change its type. */
diff --combined drivers/net/sunhme.c
index bff2f79,d381a0f..30aad54
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@@ -1383,7 -1383,7 +1383,7 @@@ force_link
  		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
  			hp->sw_bmcr = BMCR_SPEED100;
  		} else {
- 			if (ep->speed == SPEED_100)
+ 			if (ethtool_cmd_speed(ep) == SPEED_100)
  				hp->sw_bmcr = BMCR_SPEED100;
  			else
  				hp->sw_bmcr = 0;
@@@ -2401,6 -2401,7 +2401,7 @@@ static void happy_meal_set_multicast(st
  static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
  {
  	struct happy_meal *hp = netdev_priv(dev);
+ 	u32 speed;
  
  	cmd->supported =
  		(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
@@@ -2420,10 -2421,9 +2421,9 @@@
  
  	if (hp->sw_bmcr & BMCR_ANENABLE) {
  		cmd->autoneg = AUTONEG_ENABLE;
- 		cmd->speed =
- 			(hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
- 			SPEED_100 : SPEED_10;
- 		if (cmd->speed == SPEED_100)
+ 		speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
+ 			 SPEED_100 : SPEED_10);
+ 		if (speed == SPEED_100)
  			cmd->duplex =
  				(hp->sw_lpa & (LPA_100FULL)) ?
  				DUPLEX_FULL : DUPLEX_HALF;
@@@ -2433,13 -2433,12 +2433,12 @@@
  				DUPLEX_FULL : DUPLEX_HALF;
  	} else {
  		cmd->autoneg = AUTONEG_DISABLE;
- 		cmd->speed =
- 			(hp->sw_bmcr & BMCR_SPEED100) ?
- 			SPEED_100 : SPEED_10;
+ 		speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
  		cmd->duplex =
  			(hp->sw_bmcr & BMCR_FULLDPLX) ?
  			DUPLEX_FULL : DUPLEX_HALF;
  	}
+ 	ethtool_cmd_speed_set(cmd, speed);
  	return 0;
  }
  
@@@ -2452,8 -2451,8 +2451,8 @@@ static int hme_set_settings(struct net_
  	    cmd->autoneg != AUTONEG_DISABLE)
  		return -EINVAL;
  	if (cmd->autoneg == AUTONEG_DISABLE &&
- 	    ((cmd->speed != SPEED_100 &&
- 	      cmd->speed != SPEED_10) ||
+ 	    ((ethtool_cmd_speed(cmd) != SPEED_100 &&
+ 	      ethtool_cmd_speed(cmd) != SPEED_10) ||
  	     (cmd->duplex != DUPLEX_HALF &&
  	      cmd->duplex != DUPLEX_FULL)))
  		return -EINVAL;
@@@ -2788,7 -2787,8 +2787,8 @@@ static int __devinit happy_meal_sbus_pr
  	dev->ethtool_ops = &hme_ethtool_ops;
  
  	/* Happy Meal can do it all... */
- 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ 	dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+ 	dev->features |= dev->hw_features | NETIF_F_RXCSUM;
  
  	dev->irq = op->archdata.irqs[0];
  
@@@ -3113,7 -3113,8 +3113,8 @@@ static int __devinit happy_meal_pci_pro
  	dev->dma = 0;
  
  	/* Happy Meal can do it all... */
- 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ 	dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+ 	dev->features |= dev->hw_features | NETIF_F_RXCSUM;
  
  #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
  	/* Hook up PCI register/descriptor accessors. */
@@@ -3237,18 -3238,15 +3238,18 @@@ static void happy_meal_pci_exit(void
  #endif
  
  #ifdef CONFIG_SBUS
 +static const struct of_device_id hme_sbus_match[];
  static int __devinit hme_sbus_probe(struct platform_device *op)
  {
 +	const struct of_device_id *match;
  	struct device_node *dp = op->dev.of_node;
  	const char *model = of_get_property(dp, "model", NULL);
  	int is_qfe;
  
 -	if (!op->dev.of_match)
 +	match = of_match_device(hme_sbus_match, &op->dev);
 +	if (!match)
  		return -EINVAL;
 -	is_qfe = (op->dev.of_match->data != NULL);
 +	is_qfe = (match->data != NULL);
  
  	if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
  		is_qfe = 1;
diff --combined drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 6623656,cd05019..ab255fb
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@@ -664,7 -664,7 +664,7 @@@ static void bnx2fc_link_speed_update(st
  	struct fcoe_port *port = lport_priv(lport);
  	struct bnx2fc_hba *hba = port->priv;
  	struct net_device *netdev = hba->netdev;
- 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ 	struct ethtool_cmd ecmd;
  
  	if (!dev_ethtool_get_settings(netdev, &ecmd)) {
  		lport->link_supported_speeds &=
@@@ -675,12 -675,15 +675,15 @@@
  		if (ecmd.supported & SUPPORTED_10000baseT_Full)
  			lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
  
- 		if (ecmd.speed == SPEED_1000)
+ 		switch (ethtool_cmd_speed(&ecmd)) {
+ 		case SPEED_1000:
  			lport->link_speed = FC_PORTSPEED_1GBIT;
- 		if (ecmd.speed == SPEED_10000)
+ 			break;
+ 		case SPEED_10000:
  			lport->link_speed = FC_PORTSPEED_10GBIT;
+ 			break;
+ 		}
  	}
- 	return;
  }
  static int bnx2fc_link_ok(struct fc_lport *lport)
  {
@@@ -1130,7 -1133,7 +1133,7 @@@ static void bnx2fc_interface_release(st
  	struct net_device *phys_dev;
  
  	hba = container_of(kref, struct bnx2fc_hba, kref);
 -	BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n");
 +	BNX2FC_MISC_DBG("Interface is being released\n");
  
  	netdev = hba->netdev;
  	phys_dev = hba->phys_dev;
@@@ -1254,17 -1257,20 +1257,17 @@@ setup_err
  static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
  				  struct device *parent, int npiv)
  {
 -	struct fc_lport		*lport = NULL;
 +	struct fc_lport		*lport, *n_port;
  	struct fcoe_port	*port;
  	struct Scsi_Host	*shost;
  	struct fc_vport		*vport = dev_to_vport(parent);
  	int			rc = 0;
  
  	/* Allocate Scsi_Host structure */
 -	if (!npiv) {
 -		lport = libfc_host_alloc(&bnx2fc_shost_template,
 -					  sizeof(struct fcoe_port));
 -	} else {
 -		lport = libfc_vport_create(vport,
 -					   sizeof(struct fcoe_port));
 -	}
 +	if (!npiv)
 +		lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
 +	else
 +		lport = libfc_vport_create(vport, sizeof(*port));
  
  	if (!lport) {
  		printk(KERN_ERR PFX "could not allocate scsi host structure\n");
@@@ -1282,6 -1288,7 +1285,6 @@@
  		goto lp_config_err;
  
  	if (npiv) {
 -		vport = dev_to_vport(parent);
  		printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n",
  			vport->node_name, vport->port_name);
  		fc_set_wwnn(lport, vport->node_name);
@@@ -1310,17 -1317,12 +1313,17 @@@
  	fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
  
  	/* Allocate exchange manager */
 -	if (!npiv) {
 +	if (!npiv)
  		rc = bnx2fc_em_config(lport);
 -		if (rc) {
 -			printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
 -			goto shost_err;
 -		}
 +	else {
 +		shost = vport_to_shost(vport);
 +		n_port = shost_priv(shost);
 +		rc = fc_exch_mgr_list_clone(n_port, lport);
 +	}
 +
 +	if (rc) {
 +		printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
 +		goto shost_err;
  	}
  
  	bnx2fc_interface_get(hba);
@@@ -1353,6 -1355,8 +1356,6 @@@ static void bnx2fc_if_destroy(struct fc
  	/* Free existing transmit skbs */
  	fcoe_clean_pending_queue(lport);
  
 -	bnx2fc_interface_put(hba);
 -
  	/* Free queued packets for the receive thread */
  	bnx2fc_clean_rx_queue(lport);
  
@@@ -1371,8 -1375,6 +1374,8 @@@
  
  	/* Release Scsi_Host */
  	scsi_host_put(lport->host);
 +
 +	bnx2fc_interface_put(hba);
  }
  
  /**
diff --combined drivers/scsi/fcoe/fcoe.c
index 5d3700d,04f346b..cc23bd9
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@@ -381,42 -381,6 +381,42 @@@ out
  }
  
  /**
 + * fcoe_interface_release() - fcoe_port kref release function
 + * @kref: Embedded reference count in an fcoe_interface struct
 + */
 +static void fcoe_interface_release(struct kref *kref)
 +{
 +	struct fcoe_interface *fcoe;
 +	struct net_device *netdev;
 +
 +	fcoe = container_of(kref, struct fcoe_interface, kref);
 +	netdev = fcoe->netdev;
 +	/* tear-down the FCoE controller */
 +	fcoe_ctlr_destroy(&fcoe->ctlr);
 +	kfree(fcoe);
 +	dev_put(netdev);
 +	module_put(THIS_MODULE);
 +}
 +
 +/**
 + * fcoe_interface_get() - Get a reference to a FCoE interface
 + * @fcoe: The FCoE interface to be held
 + */
 +static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
 +{
 +	kref_get(&fcoe->kref);
 +}
 +
 +/**
 + * fcoe_interface_put() - Put a reference to a FCoE interface
 + * @fcoe: The FCoE interface to be released
 + */
 +static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
 +{
 +	kref_put(&fcoe->kref, fcoe_interface_release);
 +}
 +
 +/**
   * fcoe_interface_cleanup() - Clean up a FCoE interface
   * @fcoe: The FCoE interface to be cleaned up
   *
@@@ -428,21 -392,6 +428,21 @@@ void fcoe_interface_cleanup(struct fcoe
  	struct fcoe_ctlr *fip = &fcoe->ctlr;
  	u8 flogi_maddr[ETH_ALEN];
  	const struct net_device_ops *ops;
 +	struct fcoe_port *port = lport_priv(fcoe->ctlr.lp);
 +
 +	FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
 +
 +	/* Logout of the fabric */
 +	fc_fabric_logoff(fcoe->ctlr.lp);
 +
 +	/* Cleanup the fc_lport */
 +	fc_lport_destroy(fcoe->ctlr.lp);
 +
 +	/* Stop the transmit retry timer */
 +	del_timer_sync(&port->timer);
 +
 +	/* Free existing transmit skbs */
 +	fcoe_clean_pending_queue(fcoe->ctlr.lp);
  
  	/*
  	 * Don't listen for Ethernet packets anymore.
@@@ -465,9 -414,6 +465,9 @@@
  	} else
  		dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
  
 +	if (!is_zero_ether_addr(port->data_src_addr))
 +		dev_uc_del(netdev, port->data_src_addr);
 +
  	/* Tell the LLD we are done w/ FCoE */
  	ops = netdev->netdev_ops;
  	if (ops->ndo_fcoe_disable) {
@@@ -475,7 -421,42 +475,7 @@@
  			FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
  					" specific feature for LLD.\n");
  	}
 -}
 -
 -/**
 - * fcoe_interface_release() - fcoe_port kref release function
 - * @kref: Embedded reference count in an fcoe_interface struct
 - */
 -static void fcoe_interface_release(struct kref *kref)
 -{
 -	struct fcoe_interface *fcoe;
 -	struct net_device *netdev;
 -
 -	fcoe = container_of(kref, struct fcoe_interface, kref);
 -	netdev = fcoe->netdev;
 -	/* tear-down the FCoE controller */
 -	fcoe_ctlr_destroy(&fcoe->ctlr);
 -	kfree(fcoe);
 -	dev_put(netdev);
 -	module_put(THIS_MODULE);
 -}
 -
 -/**
 - * fcoe_interface_get() - Get a reference to a FCoE interface
 - * @fcoe: The FCoE interface to be held
 - */
 -static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
 -{
 -	kref_get(&fcoe->kref);
 -}
 -
 -/**
 - * fcoe_interface_put() - Put a reference to a FCoE interface
 - * @fcoe: The FCoE interface to be released
 - */
 -static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
 -{
 -	kref_put(&fcoe->kref, fcoe_interface_release);
 +	fcoe_interface_put(fcoe);
  }
  
  /**
@@@ -840,9 -821,39 +840,9 @@@ skip_oem
   * fcoe_if_destroy() - Tear down a SW FCoE instance
   * @lport: The local port to be destroyed
   *
   */
  static void fcoe_if_destroy(struct fc_lport *lport)
  {
 -	struct fcoe_port *port = lport_priv(lport);
 -	struct fcoe_interface *fcoe = port->priv;
 -	struct net_device *netdev = fcoe->netdev;
 -
 -	FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
 -
 -	/* Logout of the fabric */
 -	fc_fabric_logoff(lport);
 -
 -	/* Cleanup the fc_lport */
 -	fc_lport_destroy(lport);
 -
 -	/* Stop the transmit retry timer */
 -	del_timer_sync(&port->timer);
 -
 -	/* Free existing transmit skbs */
 -	fcoe_clean_pending_queue(lport);
 -
 -	if (!is_zero_ether_addr(port->data_src_addr))
 -		dev_uc_del(netdev, port->data_src_addr);
 -	rtnl_unlock();
 -
 -	/* receives may not be stopped until after this */
 -	fcoe_interface_put(fcoe);
 -
  	/* Free queued packets for the per-CPU receive threads */
  	fcoe_percpu_clean(lport);
  
@@@ -1772,8 -1783,23 +1772,8 @@@ static int fcoe_disable(struct net_devi
  	int rc = 0;
  
  	mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -	/*
 -	 * Make sure the module has been initialized, and is not about to be
 -	 * removed.  Module paramter sysfs files are writable before the
 -	 * module_init function is called and after module_exit.
 -	 */
 -	if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -		rc = -ENODEV;
 -		goto out_nodev;
 -	}
 -#endif
 -
 -	if (!rtnl_trylock()) {
 -		mutex_unlock(&fcoe_config_mutex);
 -		return -ERESTARTSYS;
 -	}
  
 +	rtnl_lock();
  	fcoe = fcoe_hostlist_lookup_port(netdev);
  	rtnl_unlock();
  
@@@ -1783,6 -1809,7 +1783,6 @@@
  	} else
  		rc = -ENODEV;
  
 -out_nodev:
  	mutex_unlock(&fcoe_config_mutex);
  	return rc;
  }
@@@ -1801,7 -1828,22 +1801,7 @@@ static int fcoe_enable(struct net_devic
  	int rc = 0;
  
  	mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -	/*
 -	 * Make sure the module has been initialized, and is not about to be
 -	 * removed.  Module paramter sysfs files are writable before the
 -	 * module_init function is called and after module_exit.
 -	 */
 -	if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -		rc = -ENODEV;
 -		goto out_nodev;
 -	}
 -#endif
 -	if (!rtnl_trylock()) {
 -		mutex_unlock(&fcoe_config_mutex);
 -		return -ERESTARTSYS;
 -	}
 -
 +	rtnl_lock();
  	fcoe = fcoe_hostlist_lookup_port(netdev);
  	rtnl_unlock();
  
@@@ -1810,6 -1852,7 +1810,6 @@@
  	else if (!fcoe_link_ok(fcoe->ctlr.lp))
  		fcoe_ctlr_link_up(&fcoe->ctlr);
  
 -out_nodev:
  	mutex_unlock(&fcoe_config_mutex);
  	return rc;
  }
@@@ -1825,22 -1868,35 +1825,22 @@@
  static int fcoe_destroy(struct net_device *netdev)
  {
  	struct fcoe_interface *fcoe;
 +	struct fc_lport *lport;
  	int rc = 0;
  
  	mutex_lock(&fcoe_config_mutex);
 -#ifdef CONFIG_FCOE_MODULE
 -	/*
 -	 * Make sure the module has been initialized, and is not about to be
 -	 * removed.  Module paramter sysfs files are writable before the
 -	 * module_init function is called and after module_exit.
 -	 */
 -	if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -		rc = -ENODEV;
 -		goto out_nodev;
 -	}
 -#endif
 -	if (!rtnl_trylock()) {
 -		mutex_unlock(&fcoe_config_mutex);
 -		return -ERESTARTSYS;
 -	}
 -
 +	rtnl_lock();
  	fcoe = fcoe_hostlist_lookup_port(netdev);
  	if (!fcoe) {
  		rtnl_unlock();
  		rc = -ENODEV;
  		goto out_nodev;
  	}
 -	fcoe_interface_cleanup(fcoe);
 +	lport = fcoe->ctlr.lp;
  	list_del(&fcoe->list);
 -	/* RTNL mutex is dropped by fcoe_if_destroy */
 -	fcoe_if_destroy(fcoe->ctlr.lp);
 +	fcoe_interface_cleanup(fcoe);
 +	rtnl_unlock();
 +	fcoe_if_destroy(lport);
  out_nodev:
  	mutex_unlock(&fcoe_config_mutex);
  	return rc;
@@@ -1856,6 -1912,8 +1856,6 @@@ static void fcoe_destroy_work(struct wo
  
  	port = container_of(work, struct fcoe_port, destroy_work);
  	mutex_lock(&fcoe_config_mutex);
 -	rtnl_lock();
 -	/* RTNL mutex is dropped by fcoe_if_destroy */
  	fcoe_if_destroy(port->lport);
  	mutex_unlock(&fcoe_config_mutex);
  }
@@@ -1890,7 -1948,23 +1890,7 @@@ static int fcoe_create(struct net_devic
  	struct fc_lport *lport;
  
  	mutex_lock(&fcoe_config_mutex);
 -
 -	if (!rtnl_trylock()) {
 -		mutex_unlock(&fcoe_config_mutex);
 -		return -ERESTARTSYS;
 -	}
 -
 -#ifdef CONFIG_FCOE_MODULE
 -	/*
 -	 * Make sure the module has been initialized, and is not about to be
 -	 * removed.  Module paramter sysfs files are writable before the
 -	 * module_init function is called and after module_exit.
 -	 */
 -	if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 -		rc = -ENODEV;
 -		goto out_nodev;
 -	}
 -#endif
 +	rtnl_lock();
  
  	/* look for existing lport */
  	if (fcoe_hostlist_lookup(netdev)) {
@@@ -1952,7 -2026,7 +1952,7 @@@ out_nodev
  int fcoe_link_speed_update(struct fc_lport *lport)
  {
  	struct net_device *netdev = fcoe_netdev(lport);
- 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ 	struct ethtool_cmd ecmd;
  
  	if (!dev_ethtool_get_settings(netdev, &ecmd)) {
  		lport->link_supported_speeds &=
@@@ -1963,11 -2037,14 +1963,14 @@@
  		if (ecmd.supported & SUPPORTED_10000baseT_Full)
  			lport->link_supported_speeds |=
  				FC_PORTSPEED_10GBIT;
- 		if (ecmd.speed == SPEED_1000)
+ 		switch (ethtool_cmd_speed(&ecmd)) {
+ 		case SPEED_1000:
  			lport->link_speed = FC_PORTSPEED_1GBIT;
- 		if (ecmd.speed == SPEED_10000)
+ 			break;
+ 		case SPEED_10000:
  			lport->link_speed = FC_PORTSPEED_10GBIT;
- 
+ 			break;
+ 		}
  		return 0;
  	}
  	return -1;
diff --combined include/linux/ssb/ssb.h
index 045f72a,f017b89..252e4482
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@@ -308,7 -308,7 +308,7 @@@ struct ssb_bus 
  
  	/* ID information about the Chip. */
  	u16 chip_id;
- 	u16 chip_rev;
+ 	u8 chip_rev;
  	u16 sprom_offset;
  	u16 sprom_size;		/* number of words in sprom */
  	u8 chip_package;
@@@ -404,9 -404,7 +404,9 @@@ extern bool ssb_is_sprom_available(stru
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
 -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
 +extern int ssb_arch_register_fallback_sprom(
 +		int (*sprom_callback)(struct ssb_bus *bus,
 +		struct ssb_sprom *out));
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
@@@ -520,6 -518,7 +520,7 @@@ extern int ssb_bus_may_powerdown(struc
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
+ extern void ssb_commit_settings(struct ssb_bus *bus);
  
  /* Various helper functions */
  extern u32 ssb_admatch_base(u32 adm);
diff --combined include/net/sctp/sctp.h
index 01e094c,7e8e34c..b2c2366
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@@ -115,6 -115,7 +115,6 @@@
   * sctp/protocol.c
   */
  extern struct sock *sctp_get_ctl_sock(void);
 -extern void sctp_local_addr_free(struct rcu_head *head);
  extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
  				     sctp_scope_t, gfp_t gfp,
  				     int flags);
@@@ -530,7 -531,6 +530,6 @@@ _sctp_walk_params((pos), (chunk), ntohs
  
  #define _sctp_walk_params(pos, chunk, end, member)\
  for (pos.v = chunk->member;\
-      pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
       pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
       ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
       pos.v += WORD_ROUND(ntohs(pos.p->length)))
@@@ -541,7 -541,6 +540,6 @@@ _sctp_walk_errors((err), (chunk_hdr), n
  #define _sctp_walk_errors(err, chunk_hdr, end)\
  for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
  	    sizeof(sctp_chunkhdr_t));\
-      (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
       (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
       ntohs(err->length) >= sizeof(sctp_errhdr_t); \
       err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
diff --combined net/9p/client.c
index a9aa2dd,0ce9592..ceab943
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@@ -614,7 -614,7 +614,7 @@@ p9_client_rpc(struct p9_client *c, int8
  
  	err = c->trans_mod->request(c, req);
  	if (err < 0) {
 -		if (err != -ERESTARTSYS)
 +		if (err != -ERESTARTSYS && err != -EFAULT)
  			c->status = Disconnected;
  		goto reterr;
  	}
@@@ -929,15 -929,15 +929,15 @@@ error
  }
  EXPORT_SYMBOL(p9_client_attach);
  
 -struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
 -	int clone)
 +struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
 +		char **wnames, int clone)
  {
  	int err;
  	struct p9_client *clnt;
  	struct p9_fid *fid;
  	struct p9_qid *wqids;
  	struct p9_req_t *req;
 -	int16_t nwqids, count;
 +	uint16_t nwqids, count;
  
  	err = 0;
  	wqids = NULL;
@@@ -955,7 -955,7 +955,7 @@@
  		fid = oldfid;
  
  
 -	P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n",
 +	P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
  		oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
  
  	req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
@@@ -1220,6 -1220,27 +1220,6 @@@ error
  }
  EXPORT_SYMBOL(p9_client_fsync);
  
 -int p9_client_sync_fs(struct p9_fid *fid)
 -{
 -	int err = 0;
 -	struct p9_req_t *req;
 -	struct p9_client *clnt;
 -
 -	P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid);
 -
 -	clnt = fid->clnt;
 -	req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid);
 -	if (IS_ERR(req)) {
 -		err = PTR_ERR(req);
 -		goto error;
 -	}
 -	P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid);
 -	p9_free_req(clnt, req);
 -error:
 -	return err;
 -}
 -EXPORT_SYMBOL(p9_client_sync_fs);
 -
  int p9_client_clunk(struct p9_fid *fid)
  {
  	int err;
@@@ -1281,7 -1302,7 +1281,7 @@@ in
  p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
  								u32 count)
  {
- 	int err, rsize, total;
+ 	int err, rsize;
  	struct p9_client *clnt;
  	struct p9_req_t *req;
  	char *dataptr;
@@@ -1290,7 -1311,6 +1290,6 @@@
  					(long long unsigned) offset, count);
  	err = 0;
  	clnt = fid->clnt;
- 	total = 0;
  
  	rsize = fid->iounit;
  	if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@@ -1346,7 -1366,7 +1345,7 @@@ in
  p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
  							u64 offset, u32 count)
  {
- 	int err, rsize, total;
+ 	int err, rsize;
  	struct p9_client *clnt;
  	struct p9_req_t *req;
  
@@@ -1354,7 -1374,6 +1353,6 @@@
  				fid->fid, (long long unsigned) offset, count);
  	err = 0;
  	clnt = fid->clnt;
- 	total = 0;
  
  	rsize = fid->iounit;
  	if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
@@@ -1745,7 -1764,7 +1743,7 @@@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate
  
  int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
  {
- 	int err, rsize, total;
+ 	int err, rsize;
  	struct p9_client *clnt;
  	struct p9_req_t *req;
  	char *dataptr;
@@@ -1755,7 -1774,6 +1753,6 @@@
  
  	err = 0;
  	clnt = fid->clnt;
- 	total = 0;
  
  	rsize = fid->iounit;
  	if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
diff --combined net/batman-adv/gateway_client.c
index 150b6ce,65f3953..61605a0
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@@ -23,72 -23,96 +23,88 @@@
  #include "gateway_client.h"
  #include "gateway_common.h"
  #include "hard-interface.h"
+ #include "originator.h"
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include <linux/udp.h>
  #include <linux/if_vlan.h>
  
  static void gw_node_free_ref(struct gw_node *gw_node)
  {
  	if (atomic_dec_and_test(&gw_node->refcount))
 -		call_rcu(&gw_node->rcu, gw_node_free_rcu);
 +		kfree_rcu(gw_node, rcu);
  }
  
- void *gw_get_selected(struct bat_priv *bat_priv)
+ static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
  {
- 	struct gw_node *curr_gateway_tmp;
- 	struct orig_node *orig_node = NULL;
+ 	struct gw_node *gw_node;
  
  	rcu_read_lock();
- 	curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
- 	if (!curr_gateway_tmp)
- 		goto out;
- 
- 	orig_node = curr_gateway_tmp->orig_node;
- 	if (!orig_node)
+ 	gw_node = rcu_dereference(bat_priv->curr_gw);
+ 	if (!gw_node)
  		goto out;
  
- 	if (!atomic_inc_not_zero(&orig_node->refcount))
- 		orig_node = NULL;
+ 	if (!atomic_inc_not_zero(&gw_node->refcount))
+ 		gw_node = NULL;
  
  out:
  	rcu_read_unlock();
- 	return orig_node;
+ 	return gw_node;
  }
  
- void gw_deselect(struct bat_priv *bat_priv)
+ struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
  {
  	struct gw_node *gw_node;
+ 	struct orig_node *orig_node = NULL;
  
- 	spin_lock_bh(&bat_priv->gw_list_lock);
- 	gw_node = rcu_dereference(bat_priv->curr_gw);
- 	rcu_assign_pointer(bat_priv->curr_gw, NULL);
- 	spin_unlock_bh(&bat_priv->gw_list_lock);
+ 	gw_node = gw_get_selected_gw_node(bat_priv);
+ 	if (!gw_node)
+ 		goto out;
+ 
+ 	rcu_read_lock();
+ 	orig_node = gw_node->orig_node;
+ 	if (!orig_node)
+ 		goto unlock;
+ 
+ 	if (!atomic_inc_not_zero(&orig_node->refcount))
+ 		orig_node = NULL;
  
+ unlock:
+ 	rcu_read_unlock();
+ out:
  	if (gw_node)
  		gw_node_free_ref(gw_node);
+ 	return orig_node;
  }
  
  static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
  {
  	struct gw_node *curr_gw_node;
  
+ 	spin_lock_bh(&bat_priv->gw_list_lock);
+ 
  	if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
  		new_gw_node = NULL;
  
- 	spin_lock_bh(&bat_priv->gw_list_lock);
- 	curr_gw_node = rcu_dereference(bat_priv->curr_gw);
+ 	curr_gw_node = bat_priv->curr_gw;
  	rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
  
  	if (curr_gw_node)
  		gw_node_free_ref(curr_gw_node);
+ 
+ 	spin_unlock_bh(&bat_priv->gw_list_lock);
+ }
+ 
+ void gw_deselect(struct bat_priv *bat_priv)
+ {
+ 	gw_select(bat_priv, NULL);
  }
  
  void gw_election(struct bat_priv *bat_priv)
  {
  	struct hlist_node *node;
- 	struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL;
+ 	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
+ 	struct neigh_node *router;
  	uint8_t max_tq = 0;
  	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
  	int down, up;
@@@ -102,32 -126,25 +118,25 @@@
  	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
  		return;
  
- 	rcu_read_lock();
- 	curr_gw = rcu_dereference(bat_priv->curr_gw);
- 	if (curr_gw) {
- 		rcu_read_unlock();
- 		return;
- 	}
+ 	curr_gw = gw_get_selected_gw_node(bat_priv);
+ 	if (curr_gw)
+ 		goto out;
  
+ 	rcu_read_lock();
  	if (hlist_empty(&bat_priv->gw_list)) {
- 
- 		if (curr_gw) {
- 			rcu_read_unlock();
- 			bat_dbg(DBG_BATMAN, bat_priv,
- 				"Removing selected gateway - "
- 				"no gateway in range\n");
- 			gw_deselect(bat_priv);
- 		} else
- 			rcu_read_unlock();
- 
- 		return;
+ 		bat_dbg(DBG_BATMAN, bat_priv,
+ 			"Removing selected gateway - "
+ 			"no gateway in range\n");
+ 		gw_deselect(bat_priv);
+ 		goto unlock;
  	}
  
  	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
- 		if (!gw_node->orig_node->router)
+ 		if (gw_node->deleted)
  			continue;
  
- 		if (gw_node->deleted)
+ 		router = orig_node_get_router(gw_node->orig_node);
+ 		if (!router)
  			continue;
  
  		switch (atomic_read(&bat_priv->gw_sel_class)) {
@@@ -135,15 -152,14 +144,14 @@@
  			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
  					     &down, &up);
  
- 			tmp_gw_factor = (gw_node->orig_node->router->tq_avg *
- 					 gw_node->orig_node->router->tq_avg *
+ 			tmp_gw_factor = (router->tq_avg * router->tq_avg *
  					 down * 100 * 100) /
  					 (TQ_LOCAL_WINDOW_SIZE *
  					 TQ_LOCAL_WINDOW_SIZE * 64);
  
  			if ((tmp_gw_factor > max_gw_factor) ||
  			    ((tmp_gw_factor == max_gw_factor) &&
- 			     (gw_node->orig_node->router->tq_avg > max_tq)))
+ 			     (router->tq_avg > max_tq)))
  				curr_gw_tmp = gw_node;
  			break;
  
@@@ -155,19 -171,25 +163,25 @@@
  			  *     soon as a better gateway appears which has
  			  *     $routing_class more tq points)
  			  **/
- 			if (gw_node->orig_node->router->tq_avg > max_tq)
+ 			if (router->tq_avg > max_tq)
  				curr_gw_tmp = gw_node;
  			break;
  		}
  
- 		if (gw_node->orig_node->router->tq_avg > max_tq)
- 			max_tq = gw_node->orig_node->router->tq_avg;
+ 		if (router->tq_avg > max_tq)
+ 			max_tq = router->tq_avg;
  
  		if (tmp_gw_factor > max_gw_factor)
  			max_gw_factor = tmp_gw_factor;
+ 
+ 		neigh_node_free_ref(router);
  	}
  
  	if (curr_gw != curr_gw_tmp) {
+ 		router = orig_node_get_router(curr_gw_tmp->orig_node);
+ 		if (!router)
+ 			goto unlock;
+ 
  		if ((curr_gw) && (!curr_gw_tmp))
  			bat_dbg(DBG_BATMAN, bat_priv,
  				"Removing selected gateway - "
@@@ -178,48 -200,50 +192,50 @@@
  				"(gw_flags: %i, tq: %i)\n",
  				curr_gw_tmp->orig_node->orig,
  				curr_gw_tmp->orig_node->gw_flags,
- 				curr_gw_tmp->orig_node->router->tq_avg);
+ 				router->tq_avg);
  		else
  			bat_dbg(DBG_BATMAN, bat_priv,
  				"Changing route to gateway %pM "
  				"(gw_flags: %i, tq: %i)\n",
  				curr_gw_tmp->orig_node->orig,
  				curr_gw_tmp->orig_node->gw_flags,
- 				curr_gw_tmp->orig_node->router->tq_avg);
+ 				router->tq_avg);
  
+ 		neigh_node_free_ref(router);
  		gw_select(bat_priv, curr_gw_tmp);
  	}
  
+ unlock:
  	rcu_read_unlock();
+ out:
+ 	if (curr_gw)
+ 		gw_node_free_ref(curr_gw);
  }
  
  void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
  {
- 	struct gw_node *curr_gateway_tmp;
+ 	struct orig_node *curr_gw_orig;
+ 	struct neigh_node *router_gw = NULL, *router_orig = NULL;
  	uint8_t gw_tq_avg, orig_tq_avg;
  
- 	rcu_read_lock();
- 	curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
- 	if (!curr_gateway_tmp)
- 		goto out_rcu;
- 
- 	if (!curr_gateway_tmp->orig_node)
- 		goto deselect_rcu;
+ 	curr_gw_orig = gw_get_selected_orig(bat_priv);
+ 	if (!curr_gw_orig)
+ 		goto deselect;
  
- 	if (!curr_gateway_tmp->orig_node->router)
- 		goto deselect_rcu;
+ 	router_gw = orig_node_get_router(curr_gw_orig);
+ 	if (!router_gw)
+ 		goto deselect;
  
  	/* this node already is the gateway */
- 	if (curr_gateway_tmp->orig_node == orig_node)
- 		goto out_rcu;
- 
- 	if (!orig_node->router)
- 		goto out_rcu;
+ 	if (curr_gw_orig == orig_node)
+ 		goto out;
  
- 	gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
- 	rcu_read_unlock();
+ 	router_orig = orig_node_get_router(orig_node);
+ 	if (!router_orig)
+ 		goto out;
  
- 	orig_tq_avg = orig_node->router->tq_avg;
+ 	gw_tq_avg = router_gw->tq_avg;
+ 	orig_tq_avg = router_orig->tq_avg;
  
  	/* the TQ value has to be better */
  	if (orig_tq_avg < gw_tq_avg)
@@@ -237,16 -261,17 +253,17 @@@
  		"Restarting gateway selection: better gateway found (tq curr: "
  		"%i, tq new: %i)\n",
  		gw_tq_avg, orig_tq_avg);
- 	goto deselect;
  
  deselect:
  	gw_deselect(bat_priv);
  out:
+ 	if (curr_gw_orig)
+ 		orig_node_free_ref(curr_gw_orig);
+ 	if (router_gw)
+ 		neigh_node_free_ref(router_gw);
+ 	if (router_orig)
+ 		neigh_node_free_ref(router_orig);
+ 
  	return;
  }
  
@@@ -283,7 -308,15 +300,15 @@@ void gw_node_update(struct bat_priv *ba
  		    struct orig_node *orig_node, uint8_t new_gwflags)
  {
  	struct hlist_node *node;
- 	struct gw_node *gw_node;
+ 	struct gw_node *gw_node, *curr_gw;
+ 
+ 	/**
+ 	 * Note: We don't need a NULL check here, since curr_gw never gets
+ 	 * dereferenced. If curr_gw is NULL we also should not exit as we may
+ 	 * have this gateway in our list (duplication check!) even though we
+ 	 * have no currently selected gateway.
+ 	 */
+ 	curr_gw = gw_get_selected_gw_node(bat_priv);
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
@@@ -304,22 -337,26 +329,26 @@@
  				"Gateway %pM removed from gateway list\n",
  				orig_node->orig);
  
- 			if (gw_node == rcu_dereference(bat_priv->curr_gw)) {
- 				rcu_read_unlock();
- 				gw_deselect(bat_priv);
- 				return;
- 			}
+ 			if (gw_node == curr_gw)
+ 				goto deselect;
  		}
  
- 		rcu_read_unlock();
- 		return;
+ 		goto unlock;
  	}
- 	rcu_read_unlock();
  
  	if (new_gwflags == 0)
- 		return;
+ 		goto unlock;
  
  	gw_node_add(bat_priv, orig_node, new_gwflags);
+ 	goto unlock;
+ 
+ deselect:
+ 	gw_deselect(bat_priv);
+ unlock:
+ 	rcu_read_unlock();
+ 
+ 	if (curr_gw)
+ 		gw_node_free_ref(curr_gw);
  }
  
  void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@@ -329,9 -366,12 +358,12 @@@
  
  void gw_node_purge(struct bat_priv *bat_priv)
  {
- 	struct gw_node *gw_node;
+ 	struct gw_node *gw_node, *curr_gw;
  	struct hlist_node *node, *node_tmp;
  	unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
+ 	char do_deselect = 0;
+ 
+ 	curr_gw = gw_get_selected_gw_node(bat_priv);
  
  	spin_lock_bh(&bat_priv->gw_list_lock);
  
@@@ -342,41 -382,56 +374,56 @@@
  		    atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
  			continue;
  
- 		if (rcu_dereference(bat_priv->curr_gw) == gw_node)
- 			gw_deselect(bat_priv);
+ 		if (curr_gw == gw_node)
+ 			do_deselect = 1;
  
  		hlist_del_rcu(&gw_node->list);
  		gw_node_free_ref(gw_node);
  	}
  
- 
  	spin_unlock_bh(&bat_priv->gw_list_lock);
+ 
+ 	/* gw_deselect() needs to acquire the gw_list_lock */
+ 	if (do_deselect)
+ 		gw_deselect(bat_priv);
+ 
+ 	if (curr_gw)
+ 		gw_node_free_ref(curr_gw);
  }
  
+ /**
+  * fails if orig_node has no router
+  */
  static int _write_buffer_text(struct bat_priv *bat_priv,
  			      struct seq_file *seq, struct gw_node *gw_node)
  {
  	struct gw_node *curr_gw;
- 	int down, up, ret;
+ 	struct neigh_node *router;
+ 	int down, up, ret = -1;
  
  	gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
  
- 	rcu_read_lock();
- 	curr_gw = rcu_dereference(bat_priv->curr_gw);
+ 	router = orig_node_get_router(gw_node->orig_node);
+ 	if (!router)
+ 		goto out;
  
- 	ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
- 		       (curr_gw == gw_node ? "=>" : "  "),
- 		       gw_node->orig_node->orig,
- 		       gw_node->orig_node->router->tq_avg,
- 		       gw_node->orig_node->router->addr,
- 		       gw_node->orig_node->router->if_incoming->net_dev->name,
- 		       gw_node->orig_node->gw_flags,
- 		       (down > 2048 ? down / 1024 : down),
- 		       (down > 2048 ? "MBit" : "KBit"),
- 		       (up > 2048 ? up / 1024 : up),
- 		       (up > 2048 ? "MBit" : "KBit"));
+ 	curr_gw = gw_get_selected_gw_node(bat_priv);
  
- 	rcu_read_unlock();
+ 	ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
+ 			 (curr_gw == gw_node ? "=>" : "  "),
+ 			 gw_node->orig_node->orig,
+ 			 router->tq_avg, router->addr,
+ 			 router->if_incoming->net_dev->name,
+ 			 gw_node->orig_node->gw_flags,
+ 			 (down > 2048 ? down / 1024 : down),
+ 			 (down > 2048 ? "MBit" : "KBit"),
+ 			 (up > 2048 ? up / 1024 : up),
+ 			 (up > 2048 ? "MBit" : "KBit"));
+ 
+ 	neigh_node_free_ref(router);
+ 	if (curr_gw)
+ 		gw_node_free_ref(curr_gw);
+ out:
  	return ret;
  }
  
@@@ -384,40 -439,42 +431,42 @@@ int gw_client_seq_print_text(struct seq
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct bat_priv *bat_priv = netdev_priv(net_dev);
+ 	struct hard_iface *primary_if;
  	struct gw_node *gw_node;
  	struct hlist_node *node;
- 	int gw_count = 0;
- 
- 	if (!bat_priv->primary_if) {
+ 	int gw_count = 0, ret = 0;
  
- 		return seq_printf(seq, "BATMAN mesh %s disabled - please "
- 				  "specify interfaces to enable it\n",
- 				  net_dev->name);
+ 	primary_if = primary_if_get_selected(bat_priv);
+ 	if (!primary_if) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
+ 				 "specify interfaces to enable it\n",
+ 				 net_dev->name);
+ 		goto out;
  	}
  
- 	if (bat_priv->primary_if->if_status != IF_ACTIVE) {
- 
- 		return seq_printf(seq, "BATMAN mesh %s disabled - "
- 				       "primary interface not active\n",
- 				       net_dev->name);
+ 	if (primary_if->if_status != IF_ACTIVE) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+ 				 "primary interface not active\n",
+ 				 net_dev->name);
+ 		goto out;
  	}
  
  	seq_printf(seq, "      %-12s (%s/%i) %17s [%10s]: gw_class ... "
  		   "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
  		   "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
  		   "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
- 		   bat_priv->primary_if->net_dev->name,
- 		   bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+ 		   primary_if->net_dev->name,
+ 		   primary_if->net_dev->dev_addr, net_dev->name);
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
  		if (gw_node->deleted)
  			continue;
  
- 		if (!gw_node->orig_node->router)
+ 		/* fails if orig_node has no router */
+ 		if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
  			continue;
  
- 		_write_buffer_text(bat_priv, seq, gw_node);
  		gw_count++;
  	}
  	rcu_read_unlock();
@@@ -425,7 -482,10 +474,10 @@@
  	if (gw_count == 0)
  		seq_printf(seq, "No gateways in range ...\n");
  
- 	return 0;
+ out:
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
+ 	return ret;
  }
  
  int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
@@@ -434,6 -494,7 +486,7 @@@
  	struct iphdr *iphdr;
  	struct ipv6hdr *ipv6hdr;
  	struct udphdr *udphdr;
+ 	struct gw_node *curr_gw;
  	unsigned int header_len = 0;
  
  	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
@@@ -498,12 -559,11 +551,11 @@@
  	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
  		return -1;
  
- 	rcu_read_lock();
- 	if (!rcu_dereference(bat_priv->curr_gw)) {
- 		rcu_read_unlock();
+ 	curr_gw = gw_get_selected_gw_node(bat_priv);
+ 	if (!curr_gw)
  		return 0;
- 	}
- 	rcu_read_unlock();
  
+ 	if (curr_gw)
+ 		gw_node_free_ref(curr_gw);
  	return 1;
  }
diff --combined net/batman-adv/originator.c
index ed23a589,080ec883..40a30bb
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@@ -19,8 -19,6 +19,6 @@@
   *
   */
  
- /* increase the reference counter for this originator */
- 
  #include "main.h"
  #include "originator.h"
  #include "hash.h"
@@@ -56,12 -54,35 +54,27 @@@ err
  	return 0;
  }
  
  void neigh_node_free_ref(struct neigh_node *neigh_node)
  {
  	if (atomic_dec_and_test(&neigh_node->refcount))
 -		call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
 +		kfree_rcu(neigh_node, rcu);
  }
  
+ /* increases the refcounter of a found router */
+ struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
+ {
+ 	struct neigh_node *router;
+ 
+ 	rcu_read_lock();
+ 	router = rcu_dereference(orig_node->router);
+ 
+ 	if (router && !atomic_inc_not_zero(&router->refcount))
+ 		router = NULL;
+ 
+ 	rcu_read_unlock();
+ 	return router;
+ }
+ 
  struct neigh_node *create_neighbor(struct orig_node *orig_node,
  				   struct orig_node *orig_neigh_node,
  				   uint8_t *neigh,
@@@ -79,6 -100,7 +92,7 @@@
  
  	INIT_HLIST_NODE(&neigh_node->list);
  	INIT_LIST_HEAD(&neigh_node->bonding_list);
+ 	spin_lock_init(&neigh_node->tq_lock);
  
  	memcpy(neigh_node->addr, neigh, ETH_ALEN);
  	neigh_node->orig_node = orig_neigh_node;
@@@ -120,7 -142,7 +134,7 @@@ static void orig_node_free_rcu(struct r
  	spin_unlock_bh(&orig_node->neigh_list_lock);
  
  	frag_list_free(&orig_node->frag_list);
- 	hna_global_del_orig(orig_node->bat_priv, orig_node,
+ 	tt_global_del_orig(orig_node->bat_priv, orig_node,
  			    "originator timed out");
  
  	kfree(orig_node->bcast_own);
@@@ -198,7 -220,7 +212,7 @@@ struct orig_node *get_orig_node(struct 
  	orig_node->bat_priv = bat_priv;
  	memcpy(orig_node->orig, addr, ETH_ALEN);
  	orig_node->router = NULL;
- 	orig_node->hna_buff = NULL;
+ 	orig_node->tt_buff = NULL;
  	orig_node->bcast_seqno_reset = jiffies - 1
  					- msecs_to_jiffies(RESET_PROTECTION_MS);
  	orig_node->batman_seqno_reset = jiffies - 1
@@@ -309,8 -331,8 +323,8 @@@ static bool purge_orig_node(struct bat_
  							&best_neigh_node)) {
  			update_routes(bat_priv, orig_node,
  				      best_neigh_node,
- 				      orig_node->hna_buff,
- 				      orig_node->hna_buff_len);
+ 				      orig_node->tt_buff,
+ 				      orig_node->tt_buff_len);
  		}
  	}
  
@@@ -381,29 -403,34 +395,34 @@@ int orig_seq_print_text(struct seq_fil
  	struct hashtable_t *hash = bat_priv->orig_hash;
  	struct hlist_node *node, *node_tmp;
  	struct hlist_head *head;
+ 	struct hard_iface *primary_if;
  	struct orig_node *orig_node;
- 	struct neigh_node *neigh_node;
+ 	struct neigh_node *neigh_node, *neigh_node_tmp;
  	int batman_count = 0;
  	int last_seen_secs;
  	int last_seen_msecs;
- 	int i;
+ 	int i, ret = 0;
+ 
+ 	primary_if = primary_if_get_selected(bat_priv);
  
- 	if ((!bat_priv->primary_if) ||
- 	    (bat_priv->primary_if->if_status != IF_ACTIVE)) {
- 		if (!bat_priv->primary_if)
- 			return seq_printf(seq, "BATMAN mesh %s disabled - "
- 				     "please specify interfaces to enable it\n",
- 				     net_dev->name);
+ 	if (!primary_if) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+ 				 "please specify interfaces to enable it\n",
+ 				 net_dev->name);
+ 		goto out;
+ 	}
  
- 		return seq_printf(seq, "BATMAN mesh %s "
- 				  "disabled - primary interface not active\n",
- 				  net_dev->name);
+ 	if (primary_if->if_status != IF_ACTIVE) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s "
+ 				 "disabled - primary interface not active\n",
+ 				 net_dev->name);
+ 		goto out;
  	}
  
  	seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
  		   SOURCE_VERSION, REVISION_VERSION_STR,
- 		   bat_priv->primary_if->net_dev->name,
- 		   bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
+ 		   primary_if->net_dev->name,
+ 		   primary_if->net_dev->dev_addr, net_dev->name);
  	seq_printf(seq, "  %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
  		   "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
  		   "outgoingIF", "Potential nexthops");
@@@ -413,40 -440,47 +432,47 @@@
  
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
- 			if (!orig_node->router)
+ 			neigh_node = orig_node_get_router(orig_node);
+ 			if (!neigh_node)
  				continue;
  
- 			if (orig_node->router->tq_avg == 0)
- 				continue;
+ 			if (neigh_node->tq_avg == 0)
+ 				goto next;
  
  			last_seen_secs = jiffies_to_msecs(jiffies -
  						orig_node->last_valid) / 1000;
  			last_seen_msecs = jiffies_to_msecs(jiffies -
  						orig_node->last_valid) % 1000;
  
- 			neigh_node = orig_node->router;
  			seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
  				   orig_node->orig, last_seen_secs,
  				   last_seen_msecs, neigh_node->tq_avg,
  				   neigh_node->addr,
  				   neigh_node->if_incoming->net_dev->name);
  
- 			hlist_for_each_entry_rcu(neigh_node, node_tmp,
+ 			hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp,
  						 &orig_node->neigh_list, list) {
- 				seq_printf(seq, " %pM (%3i)", neigh_node->addr,
- 						neigh_node->tq_avg);
+ 				seq_printf(seq, " %pM (%3i)",
+ 					   neigh_node_tmp->addr,
+ 					   neigh_node_tmp->tq_avg);
  			}
  
  			seq_printf(seq, "\n");
  			batman_count++;
+ 
+ next:
+ 			neigh_node_free_ref(neigh_node);
  		}
  		rcu_read_unlock();
  	}
  
- 	if ((batman_count == 0))
+ 	if (batman_count == 0)
  		seq_printf(seq, "No batman nodes in range ...\n");
  
- 	return 0;
+ out:
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
+ 	return ret;
  }
  
  static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
diff --combined net/batman-adv/soft-interface.c
index 04efe02,c76a33e..d5aa609
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@@ -43,8 -43,6 +43,6 @@@ static void bat_get_drvinfo(struct net_
  static u32 bat_get_msglevel(struct net_device *dev);
  static void bat_set_msglevel(struct net_device *dev, u32 value);
  static u32 bat_get_link(struct net_device *dev);
- static u32 bat_get_rx_csum(struct net_device *dev);
- static int bat_set_rx_csum(struct net_device *dev, u32 data);
  
  static const struct ethtool_ops bat_ethtool_ops = {
  	.get_settings = bat_get_settings,
@@@ -52,8 -50,6 +50,6 @@@
  	.get_msglevel = bat_get_msglevel,
  	.set_msglevel = bat_set_msglevel,
  	.get_link = bat_get_link,
- 	.get_rx_csum = bat_get_rx_csum,
- 	.set_rx_csum = bat_set_rx_csum
  };
  
  int my_skb_head_push(struct sk_buff *skb, unsigned int len)
@@@ -76,112 -72,379 +72,371 @@@
  	return 0;
  }
  
  static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
  {
  	if (atomic_dec_and_test(&softif_neigh->refcount))
 -		call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
 +		kfree_rcu(softif_neigh, rcu);
  }
  
- void softif_neigh_purge(struct bat_priv *bat_priv)
+ static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
  {
- 	struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct softif_neigh *softif_neigh;
  	struct hlist_node *node, *node_tmp;
+ 	struct bat_priv *bat_priv;
  
- 	spin_lock_bh(&bat_priv->softif_neigh_lock);
+ 	softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu);
+ 	bat_priv = softif_neigh_vid->bat_priv;
  
+ 	spin_lock_bh(&bat_priv->softif_neigh_lock);
  	hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
- 				  &bat_priv->softif_neigh_list, list) {
+ 				  &softif_neigh_vid->softif_neigh_list, list) {
+ 		hlist_del_rcu(&softif_neigh->list);
+ 		softif_neigh_free_ref(softif_neigh);
+ 	}
+ 	spin_unlock_bh(&bat_priv->softif_neigh_lock);
  
- 		if ((!time_after(jiffies, softif_neigh->last_seen +
- 				msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
- 		    (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
- 			continue;
+ 	kfree(softif_neigh_vid);
+ }
  
- 		hlist_del_rcu(&softif_neigh->list);
+ static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid)
+ {
+ 	if (atomic_dec_and_test(&softif_neigh_vid->refcount))
+ 		call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu);
+ }
  
- 		if (bat_priv->softif_neigh == softif_neigh) {
- 			bat_dbg(DBG_ROUTES, bat_priv,
- 				 "Current mesh exit point '%pM' vanished "
- 				 "(vid: %d).\n",
- 				 softif_neigh->addr, softif_neigh->vid);
- 			softif_neigh_tmp = bat_priv->softif_neigh;
- 			bat_priv->softif_neigh = NULL;
- 			softif_neigh_free_ref(softif_neigh_tmp);
- 		}
+ static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
+ 						     short vid)
+ {
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct hlist_node *node;
  
- 		softif_neigh_free_ref(softif_neigh);
+ 	rcu_read_lock();
+ 	hlist_for_each_entry_rcu(softif_neigh_vid, node,
+ 				 &bat_priv->softif_neigh_vids, list) {
+ 		if (softif_neigh_vid->vid != vid)
+ 			continue;
+ 
+ 		if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+ 			continue;
+ 
+ 		goto out;
  	}
  
- 	spin_unlock_bh(&bat_priv->softif_neigh_lock);
+ 	softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid),
+ 				   GFP_ATOMIC);
+ 	if (!softif_neigh_vid)
+ 		goto out;
+ 
+ 	softif_neigh_vid->vid = vid;
+ 	softif_neigh_vid->bat_priv = bat_priv;
+ 
+ 	/* initialize with 2 - caller decrements counter by one */
+ 	atomic_set(&softif_neigh_vid->refcount, 2);
+ 	INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list);
+ 	INIT_HLIST_NODE(&softif_neigh_vid->list);
+ 	spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+ 	hlist_add_head_rcu(&softif_neigh_vid->list,
+ 			   &bat_priv->softif_neigh_vids);
+ 	spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
+ 
+ out:
+ 	rcu_read_unlock();
+ 	return softif_neigh_vid;
  }
  
  static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
  					     uint8_t *addr, short vid)
  {
- 	struct softif_neigh *softif_neigh;
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct softif_neigh *softif_neigh = NULL;
  	struct hlist_node *node;
  
+ 	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+ 	if (!softif_neigh_vid)
+ 		goto out;
+ 
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(softif_neigh, node,
- 				 &bat_priv->softif_neigh_list, list) {
+ 				 &softif_neigh_vid->softif_neigh_list,
+ 				 list) {
  		if (!compare_eth(softif_neigh->addr, addr))
  			continue;
  
- 		if (softif_neigh->vid != vid)
- 			continue;
- 
  		if (!atomic_inc_not_zero(&softif_neigh->refcount))
  			continue;
  
  		softif_neigh->last_seen = jiffies;
- 		goto out;
+ 		goto unlock;
  	}
  
  	softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
  	if (!softif_neigh)
- 		goto out;
+ 		goto unlock;
  
  	memcpy(softif_neigh->addr, addr, ETH_ALEN);
- 	softif_neigh->vid = vid;
  	softif_neigh->last_seen = jiffies;
  	/* initialize with 2 - caller decrements counter by one */
  	atomic_set(&softif_neigh->refcount, 2);
  
  	INIT_HLIST_NODE(&softif_neigh->list);
  	spin_lock_bh(&bat_priv->softif_neigh_lock);
- 	hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list);
+ 	hlist_add_head_rcu(&softif_neigh->list,
+ 			   &softif_neigh_vid->softif_neigh_list);
  	spin_unlock_bh(&bat_priv->softif_neigh_lock);
  
+ unlock:
+ 	rcu_read_unlock();
  out:
+ 	if (softif_neigh_vid)
+ 		softif_neigh_vid_free_ref(softif_neigh_vid);
+ 	return softif_neigh;
+ }
+ 
+ static struct softif_neigh *softif_neigh_get_selected(
+ 				struct softif_neigh_vid *softif_neigh_vid)
+ {
+ 	struct softif_neigh *softif_neigh;
+ 
+ 	rcu_read_lock();
+ 	softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+ 
+ 	if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount))
+ 		softif_neigh = NULL;
+ 
  	rcu_read_unlock();
  	return softif_neigh;
  }
  
+ static struct softif_neigh *softif_neigh_vid_get_selected(
+ 						struct bat_priv *bat_priv,
+ 						short vid)
+ {
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct softif_neigh *softif_neigh = NULL;
+ 
+ 	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+ 	if (!softif_neigh_vid)
+ 		goto out;
+ 
+ 	softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+ out:
+ 	if (softif_neigh_vid)
+ 		softif_neigh_vid_free_ref(softif_neigh_vid);
+ 	return softif_neigh;
+ }
+ 
+ static void softif_neigh_vid_select(struct bat_priv *bat_priv,
+ 				    struct softif_neigh *new_neigh,
+ 				    short vid)
+ {
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct softif_neigh *curr_neigh;
+ 
+ 	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
+ 	if (!softif_neigh_vid)
+ 		goto out;
+ 
+ 	spin_lock_bh(&bat_priv->softif_neigh_lock);
+ 
+ 	if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
+ 		new_neigh = NULL;
+ 
+ 	curr_neigh = softif_neigh_vid->softif_neigh;
+ 	rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
+ 
+ 	if ((curr_neigh) && (!new_neigh))
+ 		bat_dbg(DBG_ROUTES, bat_priv,
+ 			"Removing mesh exit point on vid: %d (prev: %pM).\n",
+ 			vid, curr_neigh->addr);
+ 	else if ((curr_neigh) && (new_neigh))
+ 		bat_dbg(DBG_ROUTES, bat_priv,
+ 			"Changing mesh exit point on vid: %d from %pM "
+ 			"to %pM.\n", vid, curr_neigh->addr, new_neigh->addr);
+ 	else if ((!curr_neigh) && (new_neigh))
+ 		bat_dbg(DBG_ROUTES, bat_priv,
+ 			"Setting mesh exit point on vid: %d to %pM.\n",
+ 			vid, new_neigh->addr);
+ 
+ 	if (curr_neigh)
+ 		softif_neigh_free_ref(curr_neigh);
+ 
+ 	spin_unlock_bh(&bat_priv->softif_neigh_lock);
+ 
+ out:
+ 	if (softif_neigh_vid)
+ 		softif_neigh_vid_free_ref(softif_neigh_vid);
+ }
+ 
+ static void softif_neigh_vid_deselect(struct bat_priv *bat_priv,
+ 				      struct softif_neigh_vid *softif_neigh_vid)
+ {
+ 	struct softif_neigh *curr_neigh;
+ 	struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp;
+ 	struct hard_iface *primary_if = NULL;
+ 	struct hlist_node *node;
+ 
+ 	primary_if = primary_if_get_selected(bat_priv);
+ 	if (!primary_if)
+ 		goto out;
+ 
+ 	/* find new softif_neigh immediately to avoid temporary loops */
+ 	rcu_read_lock();
+ 	curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
+ 
+ 	hlist_for_each_entry_rcu(softif_neigh_tmp, node,
+ 				 &softif_neigh_vid->softif_neigh_list,
+ 				 list) {
+ 		if (softif_neigh_tmp == curr_neigh)
+ 			continue;
+ 
+ 		/* we got a neighbor but its mac is 'bigger' than ours  */
+ 		if (memcmp(primary_if->net_dev->dev_addr,
+ 			   softif_neigh_tmp->addr, ETH_ALEN) < 0)
+ 			continue;
+ 
+ 		if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount))
+ 			continue;
+ 
+ 		softif_neigh = softif_neigh_tmp;
+ 		goto unlock;
+ 	}
+ 
+ unlock:
+ 	rcu_read_unlock();
+ out:
+ 	softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid);
+ 
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
+ 	if (softif_neigh)
+ 		softif_neigh_free_ref(softif_neigh);
+ }
+ 
  int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct bat_priv *bat_priv = netdev_priv(net_dev);
+ 	struct softif_neigh_vid *softif_neigh_vid;
  	struct softif_neigh *softif_neigh;
- 	struct hlist_node *node;
+ 	struct hard_iface *primary_if;
+ 	struct hlist_node *node, *node_tmp;
+ 	struct softif_neigh *curr_softif_neigh;
+ 	int ret = 0, last_seen_secs, last_seen_msecs;
+ 
+ 	primary_if = primary_if_get_selected(bat_priv);
+ 	if (!primary_if) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s disabled - "
+ 				 "please specify interfaces to enable it\n",
+ 				 net_dev->name);
+ 		goto out;
+ 	}
  
- 	if (!bat_priv->primary_if) {
- 		return seq_printf(seq, "BATMAN mesh %s disabled - "
- 			       "please specify interfaces to enable it\n",
- 			       net_dev->name);
+ 	if (primary_if->if_status != IF_ACTIVE) {
+ 		ret = seq_printf(seq, "BATMAN mesh %s "
+ 				 "disabled - primary interface not active\n",
+ 				 net_dev->name);
+ 		goto out;
  	}
  
  	seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
  
  	rcu_read_lock();
- 	hlist_for_each_entry_rcu(softif_neigh, node,
- 				 &bat_priv->softif_neigh_list, list)
- 		seq_printf(seq, "%s %pM (vid: %d)\n",
- 				bat_priv->softif_neigh == softif_neigh
- 				? "=>" : "  ", softif_neigh->addr,
- 				softif_neigh->vid);
+ 	hlist_for_each_entry_rcu(softif_neigh_vid, node,
+ 				 &bat_priv->softif_neigh_vids, list) {
+ 		seq_printf(seq, "     %-15s %s on vid: %d\n",
+ 			   "Originator", "last-seen", softif_neigh_vid->vid);
+ 
+ 		curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+ 
+ 		hlist_for_each_entry_rcu(softif_neigh, node_tmp,
+ 					 &softif_neigh_vid->softif_neigh_list,
+ 					 list) {
+ 			last_seen_secs = jiffies_to_msecs(jiffies -
+ 						softif_neigh->last_seen) / 1000;
+ 			last_seen_msecs = jiffies_to_msecs(jiffies -
+ 						softif_neigh->last_seen) % 1000;
+ 			seq_printf(seq, "%s %pM  %3i.%03is\n",
+ 				   curr_softif_neigh == softif_neigh
+ 				   ? "=>" : "  ", softif_neigh->addr,
+ 				   last_seen_secs, last_seen_msecs);
+ 		}
+ 
+ 		if (curr_softif_neigh)
+ 			softif_neigh_free_ref(curr_softif_neigh);
+ 
+ 		seq_printf(seq, "\n");
+ 	}
  	rcu_read_unlock();
  
- 	return 0;
+ out:
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
+ 	return ret;
+ }
+ 
+ void softif_neigh_purge(struct bat_priv *bat_priv)
+ {
+ 	struct softif_neigh *softif_neigh, *curr_softif_neigh;
+ 	struct softif_neigh_vid *softif_neigh_vid;
+ 	struct hlist_node *node, *node_tmp, *node_tmp2;
+ 	char do_deselect;
+ 
+ 	rcu_read_lock();
+ 	hlist_for_each_entry_rcu(softif_neigh_vid, node,
+ 				 &bat_priv->softif_neigh_vids, list) {
+ 		if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
+ 			continue;
+ 
+ 		curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
+ 		do_deselect = 0;
+ 
+ 		spin_lock_bh(&bat_priv->softif_neigh_lock);
+ 		hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2,
+ 					  &softif_neigh_vid->softif_neigh_list,
+ 					  list) {
+ 			if ((!time_after(jiffies, softif_neigh->last_seen +
+ 				msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
+ 			    (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
+ 				continue;
+ 
+ 			if (curr_softif_neigh == softif_neigh) {
+ 				bat_dbg(DBG_ROUTES, bat_priv,
+ 					"Current mesh exit point on vid: %d "
+ 					"'%pM' vanished.\n",
+ 					softif_neigh_vid->vid,
+ 					softif_neigh->addr);
+ 				do_deselect = 1;
+ 			}
+ 
+ 			hlist_del_rcu(&softif_neigh->list);
+ 			softif_neigh_free_ref(softif_neigh);
+ 		}
+ 		spin_unlock_bh(&bat_priv->softif_neigh_lock);
+ 
+ 		/* soft_neigh_vid_deselect() needs to acquire the
+ 		 * softif_neigh_lock */
+ 		if (do_deselect)
+ 			softif_neigh_vid_deselect(bat_priv, softif_neigh_vid);
+ 
+ 		if (curr_softif_neigh)
+ 			softif_neigh_free_ref(curr_softif_neigh);
+ 
+ 		softif_neigh_vid_free_ref(softif_neigh_vid);
+ 	}
+ 	rcu_read_unlock();
+ 
+ 	spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
+ 	hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp,
+ 				  &bat_priv->softif_neigh_vids, list) {
+ 		if (!hlist_empty(&softif_neigh_vid->softif_neigh_list))
+ 			continue;
+ 
+ 		hlist_del_rcu(&softif_neigh_vid->list);
+ 		softif_neigh_vid_free_ref(softif_neigh_vid);
+ 	}
+ 	spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
+ 
  }
  
  static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
@@@ -190,7 -453,9 +445,9 @@@
  	struct bat_priv *bat_priv = netdev_priv(dev);
  	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
  	struct batman_packet *batman_packet;
- 	struct softif_neigh *softif_neigh, *softif_neigh_tmp;
+ 	struct softif_neigh *softif_neigh = NULL;
+ 	struct hard_iface *primary_if = NULL;
+ 	struct softif_neigh *curr_softif_neigh = NULL;
  
  	if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
  		batman_packet = (struct batman_packet *)
@@@ -199,63 -464,52 +456,52 @@@
  		batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
  
  	if (batman_packet->version != COMPAT_VERSION)
- 		goto err;
+ 		goto out;
  
  	if (batman_packet->packet_type != BAT_PACKET)
- 		goto err;
+ 		goto out;
  
  	if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
- 		goto err;
+ 		goto out;
  
  	if (is_my_mac(batman_packet->orig))
- 		goto err;
+ 		goto out;
  
  	softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
- 
  	if (!softif_neigh)
- 		goto err;
+ 		goto out;
  
- 	if (bat_priv->softif_neigh == softif_neigh)
+ 	curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+ 	if (curr_softif_neigh == softif_neigh)
+ 		goto out;
+ 
+ 	primary_if = primary_if_get_selected(bat_priv);
+ 	if (!primary_if)
  		goto out;
  
  	/* we got a neighbor but its mac is 'bigger' than ours  */
- 	if (memcmp(bat_priv->primary_if->net_dev->dev_addr,
+ 	if (memcmp(primary_if->net_dev->dev_addr,
  		   softif_neigh->addr, ETH_ALEN) < 0)
  		goto out;
  
- 	/* switch to new 'smallest neighbor' */
- 	if ((bat_priv->softif_neigh) &&
- 	    (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr,
- 							ETH_ALEN) < 0)) {
- 		bat_dbg(DBG_ROUTES, bat_priv,
- 			"Changing mesh exit point from %pM (vid: %d) "
- 			"to %pM (vid: %d).\n",
- 			 bat_priv->softif_neigh->addr,
- 			 bat_priv->softif_neigh->vid,
- 			 softif_neigh->addr, softif_neigh->vid);
- 		softif_neigh_tmp = bat_priv->softif_neigh;
- 		bat_priv->softif_neigh = softif_neigh;
- 		softif_neigh_free_ref(softif_neigh_tmp);
- 		/* we need to hold the additional reference */
- 		goto err;
- 	}
- 
  	/* close own batX device and use softif_neigh as exit node */
- 	if ((!bat_priv->softif_neigh) &&
- 	    (memcmp(softif_neigh->addr,
- 		    bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
- 		bat_dbg(DBG_ROUTES, bat_priv,
- 			"Setting mesh exit point to %pM (vid: %d).\n",
- 			softif_neigh->addr, softif_neigh->vid);
- 		bat_priv->softif_neigh = softif_neigh;
- 		/* we need to hold the additional reference */
- 		goto err;
+ 	if (!curr_softif_neigh) {
+ 		softif_neigh_vid_select(bat_priv, softif_neigh, vid);
+ 		goto out;
  	}
  
+ 	/* switch to new 'smallest neighbor' */
+ 	if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)
+ 		softif_neigh_vid_select(bat_priv, softif_neigh, vid);
+ 
  out:
- 	softif_neigh_free_ref(softif_neigh);
- err:
  	kfree_skb(skb);
+ 	if (softif_neigh)
+ 		softif_neigh_free_ref(softif_neigh);
+ 	if (curr_softif_neigh)
+ 		softif_neigh_free_ref(curr_softif_neigh);
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
  	return;
  }
  
@@@ -285,11 -539,11 +531,11 @@@ static int interface_set_mac_addr(struc
  	if (!is_valid_ether_addr(addr->sa_data))
  		return -EADDRNOTAVAIL;
  
- 	/* only modify hna-table if it has been initialised before */
+ 	/* only modify transtable if it has been initialised before */
  	if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
- 		hna_local_remove(bat_priv, dev->dev_addr,
+ 		tt_local_remove(bat_priv, dev->dev_addr,
  				 "mac address changed");
- 		hna_local_add(dev, addr->sa_data);
+ 		tt_local_add(dev, addr->sa_data);
  	}
  
  	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@@ -311,8 -565,10 +557,10 @@@ int interface_tx(struct sk_buff *skb, s
  {
  	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
  	struct bat_priv *bat_priv = netdev_priv(soft_iface);
+ 	struct hard_iface *primary_if = NULL;
  	struct bcast_packet *bcast_packet;
  	struct vlan_ethhdr *vhdr;
+ 	struct softif_neigh *curr_softif_neigh = NULL;
  	int data_len = skb->len, ret;
  	short vid = -1;
  	bool do_bcast = false;
@@@ -340,11 -596,12 +588,12 @@@
  	 * if we have a another chosen mesh exit node in range
  	 * it will transport the packets to the mesh
  	 */
- 	if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid))
+ 	curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+ 	if (curr_softif_neigh)
  		goto dropped;
  
  	/* TODO: check this for locks */
- 	hna_local_add(soft_iface, ethhdr->h_source);
+ 	tt_local_add(soft_iface, ethhdr->h_source);
  
  	if (is_multicast_ether_addr(ethhdr->h_dest)) {
  		ret = gw_is_target(bat_priv, skb);
@@@ -358,7 -615,8 +607,8 @@@
  
  	/* ethernet packet should be broadcasted */
  	if (do_bcast) {
- 		if (!bat_priv->primary_if)
+ 		primary_if = primary_if_get_selected(bat_priv);
+ 		if (!primary_if)
  			goto dropped;
  
  		if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
@@@ -374,7 -632,7 +624,7 @@@
  		/* hw address of first interface is the orig mac because only
  		 * this mac is known throughout the mesh */
  		memcpy(bcast_packet->orig,
- 		       bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
+ 		       primary_if->net_dev->dev_addr, ETH_ALEN);
  
  		/* set broadcast sequence number */
  		bcast_packet->seqno =
@@@ -402,6 -660,10 +652,10 @@@ dropped
  dropped_freed:
  	bat_priv->stats.tx_dropped++;
  end:
+ 	if (curr_softif_neigh)
+ 		softif_neigh_free_ref(curr_softif_neigh);
+ 	if (primary_if)
+ 		hardif_free_ref(primary_if);
  	return NETDEV_TX_OK;
  }
  
@@@ -413,6 -675,7 +667,7 @@@ void interface_rx(struct net_device *so
  	struct unicast_packet *unicast_packet;
  	struct ethhdr *ethhdr;
  	struct vlan_ethhdr *vhdr;
+ 	struct softif_neigh *curr_softif_neigh = NULL;
  	short vid = -1;
  	int ret;
  
@@@ -442,7 -705,8 +697,8 @@@
  	 * if we have a another chosen mesh exit node in range
  	 * it will transport the packets to the non-mesh network
  	 */
- 	if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) {
+ 	curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
+ 	if (curr_softif_neigh) {
  		skb_push(skb, hdr_size);
  		unicast_packet = (struct unicast_packet *)skb->data;
  
@@@ -453,7 -717,7 +709,7 @@@
  		skb_reset_mac_header(skb);
  
  		memcpy(unicast_packet->dest,
- 		       bat_priv->softif_neigh->addr, ETH_ALEN);
+ 		       curr_softif_neigh->addr, ETH_ALEN);
  		ret = route_unicast_packet(skb, recv_if);
  		if (ret == NET_RX_DROP)
  			goto dropped;
@@@ -478,11 -742,13 +734,13 @@@
  	soft_iface->last_rx = jiffies;
  
  	netif_rx(skb);
- 	return;
+ 	goto out;
  
  dropped:
  	kfree_skb(skb);
  out:
+ 	if (curr_softif_neigh)
+ 		softif_neigh_free_ref(curr_softif_neigh);
  	return;
  }
  
@@@ -516,14 -782,15 +774,15 @@@ static void interface_setup(struct net_
  	dev->hard_start_xmit = interface_tx;
  #endif
  	dev->destructor = free_netdev;
+ 	dev->tx_queue_len = 0;
  
  	/**
  	 * can't call min_mtu, because the needed variables
  	 * have not been initialized yet
  	 */
  	dev->mtu = ETH_DATA_LEN;
- 	dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
- 						* skbuff for our header */
+ 	/* reserve more space in the skbuff for our header */
+ 	dev->hard_header_len = BAT_HEADER_LEN;
  
  	/* generate random address */
  	random_ether_addr(dev_addr);
@@@ -548,7 -815,7 +807,7 @@@ struct net_device *softif_create(char *
  		goto out;
  	}
  
- 	ret = register_netdev(soft_iface);
+ 	ret = register_netdevice(soft_iface);
  	if (ret < 0) {
  		pr_err("Unable to register the batman interface '%s': %i\n",
  		       name, ret);
@@@ -572,11 -839,10 +831,10 @@@
  
  	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
  	atomic_set(&bat_priv->bcast_seqno, 1);
- 	atomic_set(&bat_priv->hna_local_changed, 0);
+ 	atomic_set(&bat_priv->tt_local_changed, 0);
  
  	bat_priv->primary_if = NULL;
  	bat_priv->num_ifaces = 0;
- 	bat_priv->softif_neigh = NULL;
  
  	ret = sysfs_add_meshif(soft_iface);
  	if (ret < 0)
@@@ -632,7 -898,7 +890,7 @@@ static int bat_get_settings(struct net_
  {
  	cmd->supported = 0;
  	cmd->advertising = 0;
- 	cmd->speed = SPEED_10;
+ 	ethtool_cmd_speed_set(cmd, SPEED_10);
  	cmd->duplex = DUPLEX_FULL;
  	cmd->port = PORT_TP;
  	cmd->phy_address = 0;
@@@ -667,12 -933,3 +925,3 @@@ static u32 bat_get_link(struct net_devi
  	return 1;
  }
  
- static u32 bat_get_rx_csum(struct net_device *dev)
- {
- 	return 0;
- }
- 
- static int bat_set_rx_csum(struct net_device *dev, u32 data)
- {
- 	return -EOPNOTSUPP;
- }
diff --combined net/core/dst.c
index 0a3920b,da47a29..81a4fa1
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/types.h>
  #include <net/net_namespace.h>
  #include <linux/sched.h>
 +#include <linux/prefetch.h>
  
  #include <net/dst.h>
  
@@@ -34,9 -33,6 +34,6 @@@
   * 3) This list is guarded by a mutex,
   *    so that the gc_task and dst_dev_event() can be synchronized.
   */
- #if RT_CACHE_DEBUG >= 2
- static atomic_t			 dst_total = ATOMIC_INIT(0);
- #endif
  
  /*
   * We want to keep lock & list close together
@@@ -70,10 -66,6 +67,6 @@@ static void dst_gc_task(struct work_str
  	unsigned long expires = ~0L;
  	struct dst_entry *dst, *next, head;
  	struct dst_entry *last = &head;
- #if RT_CACHE_DEBUG >= 2
- 	ktime_t time_start = ktime_get();
- 	struct timespec elapsed;
- #endif
  
  	mutex_lock(&dst_gc_mutex);
  	next = dst_busy_list;
@@@ -147,15 -139,6 +140,6 @@@ loop
  
  	spin_unlock_bh(&dst_garbage.lock);
  	mutex_unlock(&dst_gc_mutex);
- #if RT_CACHE_DEBUG >= 2
- 	elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start));
- 	printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d"
- 		" expires: %lu elapsed: %lu us\n",
- 		atomic_read(&dst_total), delayed, work_performed,
- 		expires,
- 		elapsed.tv_sec * USEC_PER_SEC +
- 		  elapsed.tv_nsec / NSEC_PER_USEC);
- #endif
  }
  
  int dst_discard(struct sk_buff *skb)
@@@ -167,7 -150,8 +151,8 @@@ EXPORT_SYMBOL(dst_discard)
  
  const u32 dst_default_metrics[RTAX_MAX];
  
- void *dst_alloc(struct dst_ops *ops, int initial_ref)
+ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
+ 		int initial_ref, int initial_obsolete, int flags)
  {
  	struct dst_entry *dst;
  
@@@ -175,18 -159,36 +160,36 @@@
  		if (ops->gc(ops))
  			return NULL;
  	}
- 	dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC);
+ 	dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
  	if (!dst)
  		return NULL;
- 	atomic_set(&dst->__refcnt, initial_ref);
+ 	dst->child = NULL;
+ 	dst->dev = dev;
+ 	if (dev)
+ 		dev_hold(dev);
  	dst->ops = ops;
- 	dst->lastuse = jiffies;
- 	dst->path = dst;
- 	dst->input = dst->output = dst_discard;
  	dst_init_metrics(dst, dst_default_metrics, true);
- #if RT_CACHE_DEBUG >= 2
- 	atomic_inc(&dst_total);
+ 	dst->expires = 0UL;
+ 	dst->path = dst;
+ 	dst->neighbour = NULL;
+ 	dst->hh = NULL;
+ #ifdef CONFIG_XFRM
+ 	dst->xfrm = NULL;
+ #endif
+ 	dst->input = dst_discard;
+ 	dst->output = dst_discard;
+ 	dst->error = 0;
+ 	dst->obsolete = initial_obsolete;
+ 	dst->header_len = 0;
+ 	dst->trailer_len = 0;
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ 	dst->tclassid = 0;
  #endif
+ 	atomic_set(&dst->__refcnt, initial_ref);
+ 	dst->__use = 0;
+ 	dst->lastuse = jiffies;
+ 	dst->flags = flags;
+ 	dst->next = NULL;
  	dst_entries_add(ops, 1);
  	return dst;
  }
@@@ -246,9 -248,6 +249,6 @@@ again
  		dst->ops->destroy(dst);
  	if (dst->dev)
  		dev_put(dst->dev);
- #if RT_CACHE_DEBUG >= 2
- 	atomic_dec(&dst_total);
- #endif
  	kmem_cache_free(dst->ops->kmem_cachep, dst);
  
  	dst = child;
diff --combined net/core/net-sysfs.c
index 80b2aad,1b12217..11b98bc
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@@ -28,6 -28,7 +28,7 @@@
  static const char fmt_hex[] = "%#x\n";
  static const char fmt_long_hex[] = "%#lx\n";
  static const char fmt_dec[] = "%d\n";
+ static const char fmt_udec[] = "%u\n";
  static const char fmt_ulong[] = "%lu\n";
  static const char fmt_u64[] = "%llu\n";
  
@@@ -145,13 -146,10 +146,10 @@@ static ssize_t show_speed(struct devic
  	if (!rtnl_trylock())
  		return restart_syscall();
  
- 	if (netif_running(netdev) &&
- 	    netdev->ethtool_ops &&
- 	    netdev->ethtool_ops->get_settings) {
- 		struct ethtool_cmd cmd = { ETHTOOL_GSET };
- 
- 		if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
- 			ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+ 	if (netif_running(netdev)) {
+ 		struct ethtool_cmd cmd;
+ 		if (!dev_ethtool_get_settings(netdev, &cmd))
+ 			ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
  	}
  	rtnl_unlock();
  	return ret;
@@@ -166,13 -164,11 +164,11 @@@ static ssize_t show_duplex(struct devic
  	if (!rtnl_trylock())
  		return restart_syscall();
  
- 	if (netif_running(netdev) &&
- 	    netdev->ethtool_ops &&
- 	    netdev->ethtool_ops->get_settings) {
- 		struct ethtool_cmd cmd = { ETHTOOL_GSET };
- 
- 		if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
- 			ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+ 	if (netif_running(netdev)) {
+ 		struct ethtool_cmd cmd;
+ 		if (!dev_ethtool_get_settings(netdev, &cmd))
+ 			ret = sprintf(buf, "%s\n",
+ 				      cmd.duplex ? "full" : "half");
  	}
  	rtnl_unlock();
  	return ret;
@@@ -565,6 -561,13 +561,6 @@@ static ssize_t show_rps_map(struct netd
  	return len;
  }
  
 -static void rps_map_release(struct rcu_head *rcu)
 -{
 -	struct rps_map *map = container_of(rcu, struct rps_map, rcu);
 -
 -	kfree(map);
 -}
 -
  static ssize_t store_rps_map(struct netdev_rx_queue *queue,
  		      struct rx_queue_attribute *attribute,
  		      const char *buf, size_t len)
@@@ -612,7 -615,7 +608,7 @@@
  	spin_unlock(&rps_map_lock);
  
  	if (old_map)
 -		call_rcu(&old_map->rcu, rps_map_release);
 +		kfree_rcu(old_map, rcu);
  
  	free_cpumask_var(mask);
  	return len;
@@@ -721,7 -724,7 +717,7 @@@ static void rx_queue_release(struct kob
  	map = rcu_dereference_raw(queue->rps_map);
  	if (map) {
  		RCU_INIT_POINTER(queue->rps_map, NULL);
 -		call_rcu(&map->rcu, rps_map_release);
 +		kfree_rcu(map, rcu);
  	}
  
  	flow_table = rcu_dereference_raw(queue->rps_flow_table);
@@@ -891,6 -894,21 +887,6 @@@ static ssize_t show_xps_map(struct netd
  	return len;
  }
  
 -static void xps_map_release(struct rcu_head *rcu)
 -{
 -	struct xps_map *map = container_of(rcu, struct xps_map, rcu);
 -
 -	kfree(map);
 -}
 -
 -static void xps_dev_maps_release(struct rcu_head *rcu)
 -{
 -	struct xps_dev_maps *dev_maps =
 -	    container_of(rcu, struct xps_dev_maps, rcu);
 -
 -	kfree(dev_maps);
 -}
 -
  static DEFINE_MUTEX(xps_map_mutex);
  #define xmap_dereference(P)		\
  	rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex))
@@@ -946,7 -964,7 +942,7 @@@ static ssize_t store_xps_map(struct net
  		} else
  			pos = map_len = alloc_len = 0;
  
- 		need_set = cpu_isset(cpu, *mask) && cpu_online(cpu);
+ 		need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu);
  #ifdef CONFIG_NUMA
  		if (need_set) {
  			if (numa_node == -2)
@@@ -987,7 -1005,7 +983,7 @@@
  		map = dev_maps ?
  			xmap_dereference(dev_maps->cpu_map[cpu]) : NULL;
  		if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map)
 -			call_rcu(&map->rcu, xps_map_release);
 +			kfree_rcu(map, rcu);
  		if (new_dev_maps->cpu_map[cpu])
  			nonempty = 1;
  	}
@@@ -1000,7 -1018,7 +996,7 @@@
  	}
  
  	if (dev_maps)
 -		call_rcu(&dev_maps->rcu, xps_dev_maps_release);
 +		kfree_rcu(dev_maps, rcu);
  
  	netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node :
  					    NUMA_NO_NODE);
@@@ -1062,7 -1080,7 +1058,7 @@@ static void netdev_queue_release(struc
  				else {
  					RCU_INIT_POINTER(dev_maps->cpu_map[i],
  					    NULL);
 -					call_rcu(&map->rcu, xps_map_release);
 +					kfree_rcu(map, rcu);
  					map = NULL;
  				}
  			}
@@@ -1072,7 -1090,7 +1068,7 @@@
  
  		if (!nonempty) {
  			RCU_INIT_POINTER(dev->xps_maps, NULL);
 -			call_rcu(&dev_maps->rcu, xps_dev_maps_release);
 +			kfree_rcu(dev_maps, rcu);
  		}
  	}
  
diff --combined net/core/net_namespace.c
index 297bb92,1abb508..2e2dce6
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@@ -27,6 -27,14 +27,6 @@@ EXPORT_SYMBOL(init_net)
  
  #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */
  
 -static void net_generic_release(struct rcu_head *rcu)
 -{
 -	struct net_generic *ng;
 -
 -	ng = container_of(rcu, struct net_generic, rcu);
 -	kfree(ng);
 -}
 -
  static int net_assign_generic(struct net *net, int id, void *data)
  {
  	struct net_generic *ng, *old_ng;
@@@ -60,7 -68,7 +60,7 @@@
  	memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
  
  	rcu_assign_pointer(net->gen, ng);
 -	call_rcu(&old_ng->rcu, net_generic_release);
 +	kfree_rcu(old_ng, rcu);
  assign:
  	ng->ptr[id - 1] = data;
  	return 0;
@@@ -208,11 -216,14 +208,14 @@@ static void net_free(struct net *net
  	kmem_cache_free(net_cachep, net);
  }
  
- static struct net *net_create(void)
+ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
  {
  	struct net *net;
  	int rv;
  
+ 	if (!(flags & CLONE_NEWNET))
+ 		return get_net(old_net);
+ 
  	net = net_alloc();
  	if (!net)
  		return ERR_PTR(-ENOMEM);
@@@ -231,13 -242,6 +234,6 @@@
  	return net;
  }
  
- struct net *copy_net_ns(unsigned long flags, struct net *old_net)
- {
- 	if (!(flags & CLONE_NEWNET))
- 		return get_net(old_net);
- 	return net_create();
- }
- 
  static DEFINE_SPINLOCK(cleanup_list_lock);
  static LIST_HEAD(cleanup_list);  /* Must hold cleanup_list_lock to touch */
  
diff --combined net/core/pktgen.c
index 6ed9e27,379270f..67870e9
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@@ -156,7 -156,6 +156,7 @@@
  #include <linux/wait.h>
  #include <linux/etherdevice.h>
  #include <linux/kthread.h>
 +#include <linux/prefetch.h>
  #include <net/net_namespace.h>
  #include <net/checksum.h>
  #include <net/ipv6.h>
@@@ -450,7 -449,6 +450,6 @@@ static void pktgen_stop(struct pktgen_t
  static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
  
  static unsigned int scan_ip6(const char *s, char ip[16]);
- static unsigned int fmt_ip6(char *s, const char ip[16]);
  
  /* Module parameters, defaults. */
  static int pg_count_d __read_mostly = 1000;
@@@ -557,21 -555,13 +556,13 @@@ static int pktgen_if_show(struct seq_fi
  			   pkt_dev->skb_priority);
  
  	if (pkt_dev->flags & F_IPV6) {
- 		char b1[128], b2[128], b3[128];
- 		fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
- 		fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr);
- 		fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr);
  		seq_printf(seq,
- 			   "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1,
- 			   b2, b3);
- 
- 		fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr);
- 		fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr);
- 		fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr);
- 		seq_printf(seq,
- 			   "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1,
- 			   b2, b3);
- 
+ 			   "     saddr: %pI6c  min_saddr: %pI6c  max_saddr: %pI6c\n"
+ 			   "     daddr: %pI6c  min_daddr: %pI6c  max_daddr: %pI6c\n",
+ 			   &pkt_dev->in6_saddr,
+ 			   &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr,
+ 			   &pkt_dev->in6_daddr,
+ 			   &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr);
  	} else {
  		seq_printf(seq,
  			   "     dst_min: %s  dst_max: %s\n",
@@@ -707,10 -697,9 +698,9 @@@
  		   pkt_dev->cur_src_mac_offset);
  
  	if (pkt_dev->flags & F_IPV6) {
- 		char b1[128], b2[128];
- 		fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr);
- 		fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr);
- 		seq_printf(seq, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
+ 		seq_printf(seq, "     cur_saddr: %pI6c  cur_daddr: %pI6c\n",
+ 				&pkt_dev->cur_in6_saddr,
+ 				&pkt_dev->cur_in6_daddr);
  	} else
  		seq_printf(seq, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
  			   pkt_dev->cur_saddr, pkt_dev->cur_daddr);
@@@ -1310,7 -1299,7 +1300,7 @@@ static ssize_t pktgen_if_write(struct f
  		buf[len] = 0;
  
  		scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
- 		fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
+ 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
  
  		ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
  
@@@ -1333,7 -1322,7 +1323,7 @@@
  		buf[len] = 0;
  
  		scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
- 		fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
+ 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
  
  		ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
  			       &pkt_dev->min_in6_daddr);
@@@ -1356,7 -1345,7 +1346,7 @@@
  		buf[len] = 0;
  
  		scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
- 		fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
+ 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
  
  		if (debug)
  			printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
@@@ -1377,7 -1366,7 +1367,7 @@@
  		buf[len] = 0;
  
  		scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
- 		fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
+ 		snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
  
  		ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
  
@@@ -1431,11 -1420,6 +1421,6 @@@
  		return count;
  	}
  	if (!strcmp(name, "dst_mac")) {
- 		char *v = valstr;
- 		unsigned char old_dmac[ETH_ALEN];
- 		unsigned char *m = pkt_dev->dst_mac;
- 		memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
- 
  		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
  		if (len < 0)
  			return len;
@@@ -1443,35 -1427,16 +1428,16 @@@
  		memset(valstr, 0, sizeof(valstr));
  		if (copy_from_user(valstr, &user_buffer[i], len))
  			return -EFAULT;
- 		i += len;
- 
- 		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
- 			int value;
- 
- 			value = hex_to_bin(*v);
- 			if (value >= 0)
- 				*m = *m * 16 + value;
- 
- 			if (*v == ':') {
- 				m++;
- 				*m = 0;
- 			}
- 		}
  
+ 		if (!mac_pton(valstr, pkt_dev->dst_mac))
+ 			return -EINVAL;
  		/* Set up Dest MAC */
- 		if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
- 			memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
+ 		memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN);
  
- 		sprintf(pg_result, "OK: dstmac");
+ 		sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac);
  		return count;
  	}
  	if (!strcmp(name, "src_mac")) {
- 		char *v = valstr;
- 		unsigned char old_smac[ETH_ALEN];
- 		unsigned char *m = pkt_dev->src_mac;
- 
- 		memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
- 
  		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
  		if (len < 0)
  			return len;
@@@ -1479,26 -1444,13 +1445,13 @@@
  		memset(valstr, 0, sizeof(valstr));
  		if (copy_from_user(valstr, &user_buffer[i], len))
  			return -EFAULT;
- 		i += len;
- 
- 		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
- 			int value;
- 
- 			value = hex_to_bin(*v);
- 			if (value >= 0)
- 				*m = *m * 16 + value;
- 
- 			if (*v == ':') {
- 				m++;
- 				*m = 0;
- 			}
- 		}
  
+ 		if (!mac_pton(valstr, pkt_dev->src_mac))
+ 			return -EINVAL;
  		/* Set up Src MAC */
- 		if (compare_ether_addr(old_smac, pkt_dev->src_mac))
- 			memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
+ 		memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN);
  
- 		sprintf(pg_result, "OK: srcmac");
+ 		sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac);
  		return count;
  	}
  
@@@ -2515,7 -2467,6 +2468,6 @@@ static int pktgen_output_ipsec(struct s
  {
  	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
  	int err = 0;
- 	struct iphdr *iph;
  
  	if (!x)
  		return 0;
@@@ -2525,7 -2476,6 +2477,6 @@@
  		return 0;
  
  	spin_lock(&x->lock);
- 	iph = ip_hdr(skb);
  
  	err = x->outer_mode->output(x, skb);
  	if (err)
@@@ -2625,6 -2575,7 +2576,7 @@@ static void pktgen_finalize_skb(struct 
  	} else {
  		int frags = pkt_dev->nfrags;
  		int i, len;
+ 		int frag_len;
  
  
  		if (frags > MAX_SKB_FRAGS)
@@@ -2636,6 -2587,8 +2588,8 @@@
  		}
  
  		i = 0;
+ 		frag_len = (datalen/frags) < PAGE_SIZE ?
+ 			   (datalen/frags) : PAGE_SIZE;
  		while (datalen > 0) {
  			if (unlikely(!pkt_dev->page)) {
  				int node = numa_node_id();
@@@ -2649,38 -2602,18 +2603,18 @@@
  			skb_shinfo(skb)->frags[i].page = pkt_dev->page;
  			get_page(pkt_dev->page);
  			skb_shinfo(skb)->frags[i].page_offset = 0;
- 			skb_shinfo(skb)->frags[i].size =
- 			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ 			/*last fragment, fill rest of data*/
+ 			if (i == (frags - 1))
+ 				skb_shinfo(skb)->frags[i].size =
+ 				    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+ 			else
+ 				skb_shinfo(skb)->frags[i].size = frag_len;
  			datalen -= skb_shinfo(skb)->frags[i].size;
  			skb->len += skb_shinfo(skb)->frags[i].size;
  			skb->data_len += skb_shinfo(skb)->frags[i].size;
  			i++;
  			skb_shinfo(skb)->nr_frags = i;
  		}
- 
- 		while (i < frags) {
- 			int rem;
- 
- 			if (i == 0)
- 				break;
- 
- 			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
- 			if (rem == 0)
- 				break;
- 
- 			skb_shinfo(skb)->frags[i - 1].size -= rem;
- 
- 			skb_shinfo(skb)->frags[i] =
- 			    skb_shinfo(skb)->frags[i - 1];
- 			get_page(skb_shinfo(skb)->frags[i].page);
- 			skb_shinfo(skb)->frags[i].page =
- 			    skb_shinfo(skb)->frags[i - 1].page;
- 			skb_shinfo(skb)->frags[i].page_offset +=
- 			    skb_shinfo(skb)->frags[i - 1].size;
- 			skb_shinfo(skb)->frags[i].size = rem;
- 			i++;
- 			skb_shinfo(skb)->nr_frags = i;
- 		}
  	}
  
  	/* Stamp the time, and sequence number,
@@@ -2918,79 -2851,6 +2852,6 @@@ static unsigned int scan_ip6(const cha
  	return len;
  }
  
- static char tohex(char hexdigit)
- {
- 	return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
- }
- 
- static int fmt_xlong(char *s, unsigned int i)
- {
- 	char *bak = s;
- 	*s = tohex((i >> 12) & 0xf);
- 	if (s != bak || *s != '0')
- 		++s;
- 	*s = tohex((i >> 8) & 0xf);
- 	if (s != bak || *s != '0')
- 		++s;
- 	*s = tohex((i >> 4) & 0xf);
- 	if (s != bak || *s != '0')
- 		++s;
- 	*s = tohex(i & 0xf);
- 	return s - bak + 1;
- }
- 
- static unsigned int fmt_ip6(char *s, const char ip[16])
- {
- 	unsigned int len;
- 	unsigned int i;
- 	unsigned int temp;
- 	unsigned int compressing;
- 	int j;
- 
- 	len = 0;
- 	compressing = 0;
- 	for (j = 0; j < 16; j += 2) {
- 
- #ifdef V4MAPPEDPREFIX
- 		if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
- 			inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
- 			temp = strlen(s);
- 			return len + temp;
- 		}
- #endif
- 		temp = ((unsigned long)(unsigned char)ip[j] << 8) +
- 		    (unsigned long)(unsigned char)ip[j + 1];
- 		if (temp == 0) {
- 			if (!compressing) {
- 				compressing = 1;
- 				if (j == 0) {
- 					*s++ = ':';
- 					++len;
- 				}
- 			}
- 		} else {
- 			if (compressing) {
- 				compressing = 0;
- 				*s++ = ':';
- 				++len;
- 			}
- 			i = fmt_xlong(s, temp);
- 			len += i;
- 			s += i;
- 			if (j < 14) {
- 				*s++ = ':';
- 				++len;
- 			}
- 		}
- 	}
- 	if (compressing) {
- 		*s++ = ':';
- 		++len;
- 	}
- 	*s = 0;
- 	return len;
- }
- 
  static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
  					struct pktgen_dev *pkt_dev)
  {
diff --combined net/core/skbuff.c
index 960ea89,3e934fe..46cbd28
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@@ -57,7 -57,6 +57,7 @@@
  #include <linux/init.h>
  #include <linux/scatterlist.h>
  #include <linux/errqueue.h>
 +#include <linux/prefetch.h>
  
  #include <net/protocol.h>
  #include <net/dst.h>
@@@ -2994,6 -2993,9 +2994,9 @@@ int sock_queue_err_skb(struct sock *sk
  	skb->destructor = sock_rmem_free;
  	atomic_add(skb->truesize, &sk->sk_rmem_alloc);
  
+ 	/* before exiting rcu section, make sure dst is refcounted */
+ 	skb_dst_force(skb);
+ 
  	skb_queue_tail(&sk->sk_error_queue, skb);
  	if (!sock_flag(sk, SOCK_DEAD))
  		sk->sk_data_ready(sk, skb->len);
diff --combined net/decnet/dn_dev.c
index 4c27615,404fa15..cf26ac7
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@@ -332,9 -332,14 +332,9 @@@ static struct dn_ifaddr *dn_dev_alloc_i
  	return ifa;
  }
  
 -static void dn_dev_free_ifa_rcu(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct dn_ifaddr, rcu));
 -}
 -
  static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
  {
 -	call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu);
 +	kfree_rcu(ifa, rcu);
  }
  
  static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
@@@ -747,7 -752,8 +747,8 @@@ static int dn_nl_dump_ifaddr(struct sk_
  	skip_naddr = cb->args[1];
  
  	idx = 0;
- 	for_each_netdev(&init_net, dev) {
+ 	rcu_read_lock();
+ 	for_each_netdev_rcu(&init_net, dev) {
  		if (idx < skip_ndevs)
  			goto cont;
  		else if (idx > skip_ndevs) {
@@@ -756,11 -762,11 +757,11 @@@
  			skip_naddr = 0;
  		}
  
- 		if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL)
+ 		if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
  			goto cont;
  
- 		for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
- 		     ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) {
+ 		for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
+ 		     ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
  			if (dn_idx < skip_naddr)
  				continue;
  
@@@ -773,6 -779,7 +774,7 @@@ cont
  		idx++;
  	}
  done:
+ 	rcu_read_unlock();
  	cb->args[0] = idx;
  	cb->args[1] = dn_idx;
  
diff --combined net/ipv4/fib_trie.c
index 11d4d28,6375c1c..c779ce9
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@@ -126,7 -126,7 +126,7 @@@ struct tnode 
  		struct work_struct work;
  		struct tnode *tnode_free;
  	};
- 	struct rt_trie_node *child[0];
+ 	struct rt_trie_node __rcu *child[0];
  };
  
  #ifdef CONFIG_IP_FIB_TRIE_STATS
@@@ -151,7 -151,7 +151,7 @@@ struct trie_stat 
  };
  
  struct trie {
- 	struct rt_trie_node *trie;
+ 	struct rt_trie_node __rcu *trie;
  #ifdef CONFIG_IP_FIB_TRIE_STATS
  	struct trie_use_stats stats;
  #endif
@@@ -177,16 -177,29 +177,29 @@@ static const int sync_pages = 128
  static struct kmem_cache *fn_alias_kmem __read_mostly;
  static struct kmem_cache *trie_leaf_kmem __read_mostly;
  
- static inline struct tnode *node_parent(struct rt_trie_node *node)
+ /*
+  * caller must hold RTNL
+  */
+ static inline struct tnode *node_parent(const struct rt_trie_node *node)
  {
- 	return (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
+ 	unsigned long parent;
+ 
+ 	parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
+ 
+ 	return (struct tnode *)(parent & ~NODE_TYPE_MASK);
  }
  
- static inline struct tnode *node_parent_rcu(struct rt_trie_node *node)
+ /*
+  * caller must hold RCU read lock or RTNL
+  */
+ static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
  {
- 	struct tnode *ret = node_parent(node);
+ 	unsigned long parent;
+ 
+ 	parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
+ 							   lockdep_rtnl_is_held());
  
- 	return rcu_dereference_rtnl(ret);
+ 	return (struct tnode *)(parent & ~NODE_TYPE_MASK);
  }
  
  /* Same as rcu_assign_pointer
@@@ -198,18 -211,24 +211,24 @@@ static inline void node_set_parent(stru
  	node->parent = (unsigned long)ptr | NODE_TYPE(node);
  }
  
- static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i)
+ /*
+  * caller must hold RTNL
+  */
+ static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
  {
  	BUG_ON(i >= 1U << tn->bits);
  
- 	return tn->child[i];
+ 	return rtnl_dereference(tn->child[i]);
  }
  
- static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
+ /*
+  * caller must hold RCU read lock or RTNL
+  */
+ static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
  {
- 	struct rt_trie_node *ret = tnode_get_child(tn, i);
+ 	BUG_ON(i >= 1U << tn->bits);
  
- 	return rcu_dereference_rtnl(ret);
+ 	return rcu_dereference_rtnl(tn->child[i]);
  }
  
  static inline int tnode_child_length(const struct tnode *tn)
@@@ -350,9 -369,14 +369,9 @@@ static inline void free_leaf(struct lea
  	call_rcu_bh(&l->rcu, __leaf_free_rcu);
  }
  
 -static void __leaf_info_free_rcu(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct leaf_info, rcu));
 -}
 -
  static inline void free_leaf_info(struct leaf_info *leaf)
  {
 -	call_rcu(&leaf->rcu, __leaf_info_free_rcu);
 +	kfree_rcu(leaf, rcu);
  }
  
  static struct tnode *tnode_alloc(size_t size)
@@@ -482,7 -506,7 +501,7 @@@ static inline void put_child(struct tri
  static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
  				  int wasfull)
  {
- 	struct rt_trie_node *chi = tn->child[i];
+ 	struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
  	int isfull;
  
  	BUG_ON(i >= 1<<tn->bits);
@@@ -660,7 -684,7 +679,7 @@@ one_child
  		for (i = 0; i < tnode_child_length(tn); i++) {
  			struct rt_trie_node *n;
  
- 			n = tn->child[i];
+ 			n = rtnl_dereference(tn->child[i]);
  			if (!n)
  				continue;
  
@@@ -674,6 -698,20 +693,20 @@@
  	return (struct rt_trie_node *) tn;
  }
  
+ 
+ static void tnode_clean_free(struct tnode *tn)
+ {
+ 	int i;
+ 	struct tnode *tofree;
+ 
+ 	for (i = 0; i < tnode_child_length(tn); i++) {
+ 		tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
+ 		if (tofree)
+ 			tnode_free(tofree);
+ 	}
+ 	tnode_free(tn);
+ }
+ 
  static struct tnode *inflate(struct trie *t, struct tnode *tn)
  {
  	struct tnode *oldtnode = tn;
@@@ -750,8 -788,8 +783,8 @@@
  		inode = (struct tnode *) node;
  
  		if (inode->bits == 1) {
- 			put_child(t, tn, 2*i, inode->child[0]);
- 			put_child(t, tn, 2*i+1, inode->child[1]);
+ 			put_child(t, tn, 2*i, rtnl_dereference(inode->child[0]));
+ 			put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
  
  			tnode_free_safe(inode);
  			continue;
@@@ -792,8 -830,8 +825,8 @@@
  
  		size = tnode_child_length(left);
  		for (j = 0; j < size; j++) {
- 			put_child(t, left, j, inode->child[j]);
- 			put_child(t, right, j, inode->child[j + size]);
+ 			put_child(t, left, j, rtnl_dereference(inode->child[j]));
+ 			put_child(t, right, j, rtnl_dereference(inode->child[j + size]));
  		}
  		put_child(t, tn, 2*i, resize(t, left));
  		put_child(t, tn, 2*i+1, resize(t, right));
@@@ -803,18 -841,8 +836,8 @@@
  	tnode_free_safe(oldtnode);
  	return tn;
  nomem:
- 	{
- 		int size = tnode_child_length(tn);
- 		int j;
- 
- 		for (j = 0; j < size; j++)
- 			if (tn->child[j])
- 				tnode_free((struct tnode *)tn->child[j]);
- 
- 		tnode_free(tn);
- 
- 		return ERR_PTR(-ENOMEM);
- 	}
+ 	tnode_clean_free(tn);
+ 	return ERR_PTR(-ENOMEM);
  }
  
  static struct tnode *halve(struct trie *t, struct tnode *tn)
@@@ -885,18 -913,8 +908,8 @@@
  	tnode_free_safe(oldtnode);
  	return tn;
  nomem:
- 	{
- 		int size = tnode_child_length(tn);
- 		int j;
- 
- 		for (j = 0; j < size; j++)
- 			if (tn->child[j])
- 				tnode_free((struct tnode *)tn->child[j]);
- 
- 		tnode_free(tn);
- 
- 		return ERR_PTR(-ENOMEM);
- 	}
+ 	tnode_clean_free(tn);
+ 	return ERR_PTR(-ENOMEM);
  }
  
  /* readside must use rcu_read_lock currently dump routines
@@@ -1028,7 -1046,7 +1041,7 @@@ static struct list_head *fib_insert_nod
  	t_key cindex;
  
  	pos = 0;
- 	n = t->trie;
+ 	n = rtnl_dereference(t->trie);
  
  	/* If we point to NULL, stop. Either the tree is empty and we should
  	 * just put a new leaf in if, or we have reached an empty child slot,
@@@ -1314,6 -1332,9 +1327,9 @@@ int fib_table_insert(struct fib_table *
  		}
  	}
  
+ 	if (!plen)
+ 		tb->tb_num_default++;
+ 
  	list_add_tail_rcu(&new_fa->fa_list,
  			  (fa ? &fa->fa_list : fa_head));
  
@@@ -1679,6 -1700,9 +1695,9 @@@ int fib_table_delete(struct fib_table *
  
  	list_del_rcu(&fa->fa_list);
  
+ 	if (!plen)
+ 		tb->tb_num_default--;
+ 
  	if (list_empty(fa_head)) {
  		hlist_del_rcu(&li->hlist);
  		free_leaf_info(li);
@@@ -1751,7 -1775,7 +1770,7 @@@ static struct leaf *leaf_walk_rcu(struc
  				continue;
  
  			if (IS_LEAF(c)) {
- 				prefetch(p->child[idx]);
+ 				prefetch(rcu_dereference_rtnl(p->child[idx]));
  				return (struct leaf *) c;
  			}
  
@@@ -1969,6 -1993,7 +1988,7 @@@ struct fib_table *fib_trie_table(u32 id
  
  	tb->tb_id = id;
  	tb->tb_default = -1;
+ 	tb->tb_num_default = 0;
  
  	t = (struct trie *) tb->tb_data;
  	memset(t, 0, sizeof(*t));
@@@ -2264,7 -2289,7 +2284,7 @@@ static void *fib_trie_seq_next(struct s
  
  	/* walk rest of this hash chain */
  	h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
- 	while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+ 	while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) {
  		tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
  		n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
  		if (n)
diff --combined net/ipv4/igmp.c
index 8f62d66,ec03c2f..672e476
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@@ -149,11 -149,17 +149,11 @@@ static void ip_mc_clear_src(struct ip_m
  static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
  			 int sfcount, __be32 *psfsrc, int delta);
  
 -
 -static void ip_mc_list_reclaim(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct ip_mc_list, rcu));
 -}
 -
  static void ip_ma_put(struct ip_mc_list *im)
  {
  	if (atomic_dec_and_test(&im->refcnt)) {
  		in_dev_put(im->interface);
 -		call_rcu(&im->rcu, ip_mc_list_reclaim);
 +		kfree_rcu(im, rcu);
  	}
  }
  
@@@ -303,6 -309,7 +303,7 @@@ static struct sk_buff *igmpv3_newpack(s
  	struct iphdr *pip;
  	struct igmpv3_report *pig;
  	struct net *net = dev_net(dev);
+ 	struct flowi4 fl4;
  
  	while (1) {
  		skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
@@@ -315,18 -322,13 +316,13 @@@
  	}
  	igmp_skb_size(skb) = size;
  
- 	rt = ip_route_output_ports(net, NULL, IGMPV3_ALL_MCR, 0,
+ 	rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
  				   0, 0,
  				   IPPROTO_IGMP, 0, dev->ifindex);
  	if (IS_ERR(rt)) {
  		kfree_skb(skb);
  		return NULL;
  	}
- 	if (rt->rt_src == 0) {
- 		kfree_skb(skb);
- 		ip_rt_put(rt);
- 		return NULL;
- 	}
  
  	skb_dst_set(skb, &rt->dst);
  	skb->dev = dev;
@@@ -342,8 -344,8 +338,8 @@@
  	pip->tos      = 0xc0;
  	pip->frag_off = htons(IP_DF);
  	pip->ttl      = 1;
- 	pip->daddr    = rt->rt_dst;
- 	pip->saddr    = rt->rt_src;
+ 	pip->daddr    = fl4.daddr;
+ 	pip->saddr    = fl4.saddr;
  	pip->protocol = IPPROTO_IGMP;
  	pip->tot_len  = 0;	/* filled in later */
  	ip_select_ident(pip, &rt->dst, NULL);
@@@ -649,6 -651,7 +645,7 @@@ static int igmp_send_report(struct in_d
  	struct net_device *dev = in_dev->dev;
  	struct net *net = dev_net(dev);
  	__be32	group = pmc ? pmc->multiaddr : 0;
+ 	struct flowi4 fl4;
  	__be32	dst;
  
  	if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
@@@ -658,17 -661,12 +655,12 @@@
  	else
  		dst = group;
  
- 	rt = ip_route_output_ports(net, NULL, dst, 0,
+ 	rt = ip_route_output_ports(net, &fl4, NULL, dst, 0,
  				   0, 0,
  				   IPPROTO_IGMP, 0, dev->ifindex);
  	if (IS_ERR(rt))
  		return -1;
  
- 	if (rt->rt_src == 0) {
- 		ip_rt_put(rt);
- 		return -1;
- 	}
- 
  	skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
  	if (skb == NULL) {
  		ip_rt_put(rt);
@@@ -689,7 -687,7 +681,7 @@@
  	iph->frag_off = htons(IP_DF);
  	iph->ttl      = 1;
  	iph->daddr    = dst;
- 	iph->saddr    = rt->rt_src;
+ 	iph->saddr    = fl4.saddr;
  	iph->protocol = IPPROTO_IGMP;
  	ip_select_ident(iph, &rt->dst, NULL);
  	((u8*)&iph[1])[0] = IPOPT_RA;
@@@ -1830,6 -1828,12 +1822,6 @@@ done
  }
  EXPORT_SYMBOL(ip_mc_join_group);
  
 -static void ip_sf_socklist_reclaim(struct rcu_head *rp)
 -{
 -	kfree(container_of(rp, struct ip_sf_socklist, rcu));
 -	/* sk_omem_alloc should have been decreased by the caller*/
 -}
 -
  static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
  			   struct in_device *in_dev)
  {
@@@ -1846,10 -1850,18 +1838,10 @@@
  	rcu_assign_pointer(iml->sflist, NULL);
  	/* decrease mem now to avoid the memleak warning */
  	atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
 -	call_rcu(&psf->rcu, ip_sf_socklist_reclaim);
 +	kfree_rcu(psf, rcu);
  	return err;
  }
  
 -
 -static void ip_mc_socklist_reclaim(struct rcu_head *rp)
 -{
 -	kfree(container_of(rp, struct ip_mc_socklist, rcu));
 -	/* sk_omem_alloc should have been decreased by the caller*/
 -}
 -
 -
  /*
   *	Ask a socket to leave a group.
   */
@@@ -1889,7 -1901,7 +1881,7 @@@ int ip_mc_leave_group(struct sock *sk, 
  		rtnl_unlock();
  		/* decrease mem now to avoid the memleak warning */
  		atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
 -		call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
 +		kfree_rcu(iml, rcu);
  		return 0;
  	}
  	if (!in_dev)
@@@ -2006,7 -2018,7 +1998,7 @@@ int ip_mc_source(int add, int omode, st
  				newpsl->sl_addr[i] = psl->sl_addr[i];
  			/* decrease mem now to avoid the memleak warning */
  			atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
 -			call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
 +			kfree_rcu(psl, rcu);
  		}
  		rcu_assign_pointer(pmc->sflist, newpsl);
  		psl = newpsl;
@@@ -2107,7 -2119,7 +2099,7 @@@ int ip_mc_msfilter(struct sock *sk, str
  			psl->sl_count, psl->sl_addr, 0);
  		/* decrease mem now to avoid the memleak warning */
  		atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
 -		call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
 +		kfree_rcu(psl, rcu);
  	} else
  		(void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
  			0, NULL, 0);
@@@ -2304,7 -2316,7 +2296,7 @@@ void ip_mc_drop_socket(struct sock *sk
  			ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
  		/* decrease mem now to avoid the memleak warning */
  		atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
 -		call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
 +		kfree_rcu(iml, rcu);
  	}
  	rtnl_unlock();
  }
diff --combined net/ipv6/addrconf.c
index 8f13d88,3cfbbf3..498b927
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@@ -289,19 -289,19 +289,19 @@@ static int snmp6_alloc_dev(struct inet6
  			  sizeof(struct ipstats_mib),
  			  __alignof__(struct ipstats_mib)) < 0)
  		goto err_ip;
- 	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6,
- 			  sizeof(struct icmpv6_mib),
- 			  __alignof__(struct icmpv6_mib)) < 0)
+ 	idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device),
+ 					GFP_KERNEL);
+ 	if (!idev->stats.icmpv6dev)
  		goto err_icmp;
- 	if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg,
- 			  sizeof(struct icmpv6msg_mib),
- 			  __alignof__(struct icmpv6msg_mib)) < 0)
+ 	idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device),
+ 					   GFP_KERNEL);
+ 	if (!idev->stats.icmpv6msgdev)
  		goto err_icmpmsg;
  
  	return 0;
  
  err_icmpmsg:
- 	snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+ 	kfree(idev->stats.icmpv6dev);
  err_icmp:
  	snmp_mib_free((void __percpu **)idev->stats.ipv6);
  err_ip:
@@@ -310,13 -310,19 +310,13 @@@
  
  static void snmp6_free_dev(struct inet6_dev *idev)
  {
- 	snmp_mib_free((void __percpu **)idev->stats.icmpv6msg);
- 	snmp_mib_free((void __percpu **)idev->stats.icmpv6);
+ 	kfree(idev->stats.icmpv6msgdev);
+ 	kfree(idev->stats.icmpv6dev);
  	snmp_mib_free((void __percpu **)idev->stats.ipv6);
  }
  
  /* Nobody refers to this device, we may destroy it. */
  
 -static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
 -{
 -	struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
 -	kfree(idev);
 -}
 -
  void in6_dev_finish_destroy(struct inet6_dev *idev)
  {
  	struct net_device *dev = idev->dev;
@@@ -333,7 -339,7 +333,7 @@@
  		return;
  	}
  	snmp6_free_dev(idev);
 -	call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
 +	kfree_rcu(idev, rcu);
  }
  
  EXPORT_SYMBOL(in6_dev_finish_destroy);
@@@ -529,6 -535,12 +529,6 @@@ static int addrconf_fixup_forwarding(st
  }
  #endif
  
 -static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
 -{
 -	struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
 -	kfree(ifp);
 -}
 -
  /* Nobody refers to this ifaddr, destroy it */
  void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
  {
@@@ -549,7 -561,7 +549,7 @@@
  	}
  	dst_release(&ifp->rt->dst);
  
 -	call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
 +	kfree_rcu(ifp, rcu);
  }
  
  static void
@@@ -813,6 -825,8 +813,8 @@@ static void ipv6_del_addr(struct inet6_
  		dst_release(&rt->dst);
  	}
  
+ 	/* clean up prefsrc entries */
+ 	rt6_remove_prefsrc(ifp);
  out:
  	in6_ifa_put(ifp);
  }
@@@ -1269,7 -1283,7 +1271,7 @@@ static int ipv6_count_addresses(struct 
  	return cnt;
  }
  
- int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
+ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
  		  struct net_device *dev, int strict)
  {
  	struct inet6_ifaddr *ifp;
@@@ -1312,7 -1326,7 +1314,7 @@@ static bool ipv6_chk_same_addr(struct n
  	return false;
  }
  
- int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)
+ int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev)
  {
  	struct inet6_dev *idev;
  	struct inet6_ifaddr *ifa;
@@@ -1443,7 -1457,7 +1445,7 @@@ void addrconf_dad_failure(struct inet6_
  
  /* Join to solicited addr multicast group. */
  
- void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
+ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
  {
  	struct in6_addr maddr;
  
@@@ -1454,7 -1468,7 +1456,7 @@@
  	ipv6_dev_mc_inc(dev, &maddr);
  }
  
- void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr)
+ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
  {
  	struct in6_addr maddr;
  
@@@ -2099,7 -2113,7 +2101,7 @@@ err_exit
  /*
   *	Manual configuration of address on an interface
   */
- static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
+ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
  			  unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
  			  __u32 valid_lft)
  {
@@@ -2173,7 -2187,7 +2175,7 @@@
  	return PTR_ERR(ifp);
  }
  
- static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
+ static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx,
  			  unsigned int plen)
  {
  	struct inet6_ifaddr *ifp;
@@@ -2336,7 -2350,7 +2338,7 @@@ static void init_loopback(struct net_de
  	add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
  }
  
- static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
+ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
  {
  	struct inet6_ifaddr * ifp;
  	u32 addr_flags = IFA_F_PERMANENT;
@@@ -3107,7 -3121,7 +3109,7 @@@ void if6_proc_exit(void
  
  #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
  /* Check if address is a home address configured on any interface. */
- int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
+ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
  {
  	int ret = 0;
  	struct inet6_ifaddr *ifp = NULL;
@@@ -3824,7 -3838,7 +3826,7 @@@ static inline size_t inet6_if_nlmsg_siz
  	       + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */
  }
  
- static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
+ static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib,
  				      int items, int bytes)
  {
  	int i;
@@@ -3834,7 -3848,7 +3836,7 @@@
  	/* Use put_unaligned() because stats may not be aligned for u64. */
  	put_unaligned(items, &stats[0]);
  	for (i = 1; i < items; i++)
- 		put_unaligned(snmp_fold_field(mib, i), &stats[i]);
+ 		put_unaligned(atomic_long_read(&mib[i]), &stats[i]);
  
  	memset(&stats[items], 0, pad);
  }
@@@ -3863,7 -3877,7 +3865,7 @@@ static void snmp6_fill_stats(u64 *stats
  				     IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp));
  		break;
  	case IFLA_INET6_ICMP6STATS:
- 		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+ 		__snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes);
  		break;
  	}
  }
diff --combined net/ipv6/mcast.c
index f2d98ca,ff62e33..3e6ebcd
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@@ -92,16 -92,16 +92,16 @@@ static void mld_gq_timer_expire(unsigne
  static void mld_ifc_timer_expire(unsigned long data);
  static void mld_ifc_event(struct inet6_dev *idev);
  static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
- static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr);
+ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
  static void mld_clear_delrec(struct inet6_dev *idev);
  static int sf_setstate(struct ifmcaddr6 *pmc);
  static void sf_markstate(struct ifmcaddr6 *pmc);
  static void ip6_mc_clear_src(struct ifmcaddr6 *pmc);
- static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
- 			  int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
  			  int delta);
- static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
- 			  int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
  			  int delta);
  static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
  			    struct inet6_dev *idev);
@@@ -201,6 -201,10 +201,6 @@@ int ipv6_sock_mc_join(struct sock *sk, 
  	return 0;
  }
  
 -static void ipv6_mc_socklist_reclaim(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct ipv6_mc_socklist, rcu));
 -}
  /*
   *	socket leave on multicast group
   */
@@@ -235,7 -239,7 +235,7 @@@ int ipv6_sock_mc_drop(struct sock *sk, 
  				(void) ip6_mc_leave_src(sk, mc_lst, NULL);
  			rcu_read_unlock();
  			atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
 -			call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
 +			kfree_rcu(mc_lst, rcu);
  			return 0;
  		}
  	}
@@@ -246,7 -250,7 +246,7 @@@
  
  /* called with rcu_read_lock() */
  static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
- 					     struct in6_addr *group,
+ 					     const struct in6_addr *group,
  					     int ifindex)
  {
  	struct net_device *dev = NULL;
@@@ -303,7 -307,7 +303,7 @@@ void ipv6_sock_mc_close(struct sock *sk
  		rcu_read_unlock();
  
  		atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
 -		call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim);
 +		kfree_rcu(mc_lst, rcu);
  
  		spin_lock(&ipv6_sk_mc_lock);
  	}
@@@ -447,7 -451,7 +447,7 @@@ done
  
  int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
  {
- 	struct in6_addr *group;
+ 	const struct in6_addr *group;
  	struct ipv6_mc_socklist *pmc;
  	struct inet6_dev *idev;
  	struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@@ -538,7 -542,7 +538,7 @@@ int ip6_mc_msfget(struct sock *sk, stru
  	struct group_filter __user *optval, int __user *optlen)
  {
  	int err, i, count, copycount;
- 	struct in6_addr *group;
+ 	const struct in6_addr *group;
  	struct ipv6_mc_socklist *pmc;
  	struct inet6_dev *idev;
  	struct ipv6_pinfo *inet6 = inet6_sk(sk);
@@@ -748,7 -752,7 +748,7 @@@ static void mld_add_delrec(struct inet6
  	spin_unlock_bh(&idev->mc_lock);
  }
  
- static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca)
+ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
  {
  	struct ifmcaddr6 *pmc, *pmc_prev;
  	struct ip6_sf_list *psf, *psf_next;
@@@ -1048,7 -1052,7 +1048,7 @@@ static void igmp6_group_queried(struct 
  
  /* mark EXCLUDE-mode sources */
  static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
- 	struct in6_addr *srcs)
+ 	const struct in6_addr *srcs)
  {
  	struct ip6_sf_list *psf;
  	int i, scount;
@@@ -1076,7 -1080,7 +1076,7 @@@
  }
  
  static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
- 	struct in6_addr *srcs)
+ 	const struct in6_addr *srcs)
  {
  	struct ip6_sf_list *psf;
  	int i, scount;
@@@ -1111,7 -1115,7 +1111,7 @@@ int igmp6_event_query(struct sk_buff *s
  {
  	struct mld2_query *mlh2 = NULL;
  	struct ifmcaddr6 *ma;
- 	struct in6_addr *group;
+ 	const struct in6_addr *group;
  	unsigned long max_delay;
  	struct inet6_dev *idev;
  	struct mld_msg *mld;
@@@ -1817,7 -1821,7 +1817,7 @@@ err_out
  }
  
  static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
- 	struct in6_addr *psfsrc)
+ 	const struct in6_addr *psfsrc)
  {
  	struct ip6_sf_list *psf, *psf_prev;
  	int rv = 0;
@@@ -1853,8 -1857,8 +1853,8 @@@
  	return rv;
  }
  
- static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,
- 			  int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
  			  int delta)
  {
  	struct ifmcaddr6 *pmc;
@@@ -1914,7 -1918,7 +1914,7 @@@
   * Add multicast single-source filter to the interface list
   */
  static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
- 	struct in6_addr *psfsrc, int delta)
+ 	const struct in6_addr *psfsrc, int delta)
  {
  	struct ip6_sf_list *psf, *psf_prev;
  
@@@ -2017,8 -2021,8 +2017,8 @@@ static int sf_setstate(struct ifmcaddr
  /*
   * Add multicast source filter list to the interface list
   */
- static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,
- 			  int sfmode, int sfcount, struct in6_addr *psfsrc,
+ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
+ 			  int sfmode, int sfcount, const struct in6_addr *psfsrc,
  			  int delta)
  {
  	struct ifmcaddr6 *pmc;
diff --combined net/ipv6/sit.c
index 5f35d59,a6a32b3..1cca576
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@@ -250,11 -250,6 +250,6 @@@ static struct ip_tunnel *ipip6_tunnel_l
  
  	dev_net_set(dev, net);
  
- 	if (strchr(name, '%')) {
- 		if (dev_alloc_name(dev, name) < 0)
- 			goto failed_free;
- 	}
- 
  	nt = netdev_priv(dev);
  
  	nt->parms = *parms;
@@@ -401,6 -396,11 +396,6 @@@ out
  	return err;
  }
  
 -static void prl_entry_destroy_rcu(struct rcu_head *head)
 -{
 -	kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
 -}
 -
  static void prl_list_destroy_rcu(struct rcu_head *head)
  {
  	struct ip_tunnel_prl_entry *p, *n;
@@@ -428,7 -428,7 +423,7 @@@ ipip6_tunnel_del_prl(struct ip_tunnel *
  		     p = &x->next) {
  			if (x->addr == a->addr) {
  				*p = x->next;
 -				call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
 +				kfree_rcu(x, rcu_head);
  				t->prl_count--;
  				goto out;
  			}
@@@ -447,7 -447,7 +442,7 @@@ out
  }
  
  static int
- isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
+ isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
  {
  	struct ip_tunnel_prl_entry *p;
  	int ok = 1;
@@@ -460,7 -460,8 +455,8 @@@
  		else
  			skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT;
  	} else {
- 		struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
+ 		const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr;
+ 
  		if (ipv6_addr_is_isatap(addr6) &&
  		    (addr6->s6_addr32[3] == iph->saddr) &&
  		    ipv6_chk_prefix(addr6, t->dev))
@@@ -494,7 -495,7 +490,7 @@@ static int ipip6_err(struct sk_buff *sk
     8 bytes of packet payload. It means, that precise relaying of
     ICMP in the real Internet is absolutely infeasible.
   */
- 	struct iphdr *iph = (struct iphdr*)skb->data;
+ 	const struct iphdr *iph = (const struct iphdr *)skb->data;
  	const int type = icmp_hdr(skb)->type;
  	const int code = icmp_hdr(skb)->code;
  	struct ip_tunnel *t;
@@@ -552,7 -553,7 +548,7 @@@ out
  	return err;
  }
  
- static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+ static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb)
  {
  	if (INET_ECN_is_ce(iph->tos))
  		IP6_ECN_set_ce(ipv6_hdr(skb));
@@@ -560,7 -561,7 +556,7 @@@
  
  static int ipip6_rcv(struct sk_buff *skb)
  {
- 	struct iphdr *iph;
+ 	const struct iphdr *iph;
  	struct ip_tunnel *tunnel;
  
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
@@@ -616,7 -617,7 +612,7 @@@ out
   * comes from 6rd / 6to4 (RFC 3056) addr space.
   */
  static inline
- __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
+ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel)
  {
  	__be32 dst = 0;
  
@@@ -659,8 -660,8 +655,8 @@@ static netdev_tx_t ipip6_tunnel_xmit(st
  {
  	struct ip_tunnel *tunnel = netdev_priv(dev);
  	struct pcpu_tstats *tstats;
- 	struct iphdr  *tiph = &tunnel->parms.iph;
- 	struct ipv6hdr *iph6 = ipv6_hdr(skb);
+ 	const struct iphdr  *tiph = &tunnel->parms.iph;
+ 	const struct ipv6hdr *iph6 = ipv6_hdr(skb);
  	u8     tos = tunnel->parms.iph.tos;
  	__be16 df = tiph->frag_off;
  	struct rtable *rt;     			/* Route to the other host */
@@@ -668,8 -669,9 +664,9 @@@
  	struct iphdr  *iph;			/* Our new IP header */
  	unsigned int max_headroom;		/* The extra header space needed */
  	__be32 dst = tiph->daddr;
+ 	struct flowi4 fl4;
  	int    mtu;
- 	struct in6_addr *addr6;
+ 	const struct in6_addr *addr6;
  	int addr_type;
  
  	if (skb->protocol != htons(ETH_P_IPV6))
@@@ -688,7 -690,7 +685,7 @@@
  			goto tx_error;
  		}
  
- 		addr6 = (struct in6_addr*)&neigh->primary_key;
+ 		addr6 = (const struct in6_addr*)&neigh->primary_key;
  		addr_type = ipv6_addr_type(addr6);
  
  		if ((addr_type & IPV6_ADDR_UNICAST) &&
@@@ -713,7 -715,7 +710,7 @@@
  			goto tx_error;
  		}
  
- 		addr6 = (struct in6_addr*)&neigh->primary_key;
+ 		addr6 = (const struct in6_addr*)&neigh->primary_key;
  		addr_type = ipv6_addr_type(addr6);
  
  		if (addr_type == IPV6_ADDR_ANY) {
@@@ -727,7 -729,7 +724,7 @@@
  		dst = addr6->s6_addr32[3];
  	}
  
- 	rt = ip_route_output_ports(dev_net(dev), NULL,
+ 	rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
  				   dst, tiph->saddr,
  				   0, 0,
  				   IPPROTO_IPV6, RT_TOS(tos),
@@@ -821,8 -823,8 +818,8 @@@
  	iph->frag_off		=	df;
  	iph->protocol		=	IPPROTO_IPV6;
  	iph->tos		=	INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
- 	iph->daddr		=	rt->rt_dst;
- 	iph->saddr		=	rt->rt_src;
+ 	iph->daddr		=	fl4.daddr;
+ 	iph->saddr		=	fl4.saddr;
  
  	if ((iph->ttl = tiph->ttl) == 0)
  		iph->ttl	=	iph6->hop_limit;
@@@ -844,13 -846,14 +841,14 @@@ static void ipip6_tunnel_bind_dev(struc
  {
  	struct net_device *tdev = NULL;
  	struct ip_tunnel *tunnel;
- 	struct iphdr *iph;
+ 	const struct iphdr *iph;
+ 	struct flowi4 fl4;
  
  	tunnel = netdev_priv(dev);
  	iph = &tunnel->parms.iph;
  
  	if (iph->daddr) {
- 		struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL,
+ 		struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
  							  iph->daddr, iph->saddr,
  							  0, 0,
  							  IPPROTO_IPV6,
diff --combined net/l2tp/l2tp_ip.c
index 5c04f3e,f7fb09e..b6466e7
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@@ -296,12 -296,12 +296,12 @@@ out_in_use
  
  static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  {
- 	int rc;
- 	struct inet_sock *inet = inet_sk(sk);
  	struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
+ 	struct inet_sock *inet = inet_sk(sk);
+ 	struct flowi4 *fl4;
  	struct rtable *rt;
  	__be32 saddr;
- 	int oif;
+ 	int oif, rc;
  
  	rc = -EINVAL;
  	if (addr_len < sizeof(*lsa))
@@@ -311,6 -311,8 +311,8 @@@
  	if (lsa->l2tp_family != AF_INET)
  		goto out;
  
+ 	lock_sock(sk);
+ 
  	sk_dst_reset(sk);
  
  	oif = sk->sk_bound_dev_if;
@@@ -320,7 -322,8 +322,8 @@@
  	if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
  		goto out;
  
- 	rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr,
+ 	fl4 = &inet->cork.fl.u.ip4;
+ 	rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr,
  			      RT_CONN_FLAGS(sk), oif,
  			      IPPROTO_L2TP,
  			      0, 0, sk, true);
@@@ -340,10 -343,10 +343,10 @@@
  	l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
  
  	if (!inet->inet_saddr)
- 		inet->inet_saddr = rt->rt_src;
+ 		inet->inet_saddr = fl4->saddr;
  	if (!inet->inet_rcv_saddr)
- 		inet->inet_rcv_saddr = rt->rt_src;
- 	inet->inet_daddr = rt->rt_dst;
+ 		inet->inet_rcv_saddr = fl4->saddr;
+ 	inet->inet_daddr = fl4->daddr;
  	sk->sk_state = TCP_ESTABLISHED;
  	inet->inet_id = jiffies;
  
@@@ -356,6 -359,7 +359,7 @@@
  
  	rc = 0;
  out:
+ 	release_sock(sk);
  	return rc;
  }
  
@@@ -416,23 -420,28 +420,28 @@@ static int l2tp_ip_sendmsg(struct kioc
  	int rc;
  	struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk);
  	struct inet_sock *inet = inet_sk(sk);
- 	struct ip_options *opt = inet->opt;
  	struct rtable *rt = NULL;
+ 	struct flowi4 *fl4;
  	int connected = 0;
  	__be32 daddr;
  
+ 	lock_sock(sk);
+ 
+ 	rc = -ENOTCONN;
  	if (sock_flag(sk, SOCK_DEAD))
- 		return -ENOTCONN;
+ 		goto out;
  
  	/* Get and verify the address. */
  	if (msg->msg_name) {
  		struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name;
+ 		rc = -EINVAL;
  		if (msg->msg_namelen < sizeof(*lip))
- 			return -EINVAL;
+ 			goto out;
  
  		if (lip->l2tp_family != AF_INET) {
+ 			rc = -EAFNOSUPPORT;
  			if (lip->l2tp_family != AF_UNSPEC)
- 				return -EAFNOSUPPORT;
+ 				goto out;
  		}
  
  		daddr = lip->l2tp_addr.s_addr;
@@@ -467,19 -476,27 +476,27 @@@
  		goto error;
  	}
  
+ 	fl4 = &inet->cork.fl.u.ip4;
  	if (connected)
  		rt = (struct rtable *) __sk_dst_check(sk, 0);
  
  	if (rt == NULL) {
+ 		struct ip_options_rcu *inet_opt;
+ 
+ 		rcu_read_lock();
+ 		inet_opt = rcu_dereference(inet->inet_opt);
+ 
  		/* Use correct destination address if we have options. */
- 		if (opt && opt->srr)
- 			daddr = opt->faddr;
+ 		if (inet_opt && inet_opt->opt.srr)
+ 			daddr = inet_opt->opt.faddr;
+ 
+ 		rcu_read_unlock();
  
  		/* If this fails, retransmit mechanism of transport layer will
  		 * keep trying until route appears or the connection times
  		 * itself out.
  		 */
- 		rt = ip_route_output_ports(sock_net(sk), sk,
+ 		rt = ip_route_output_ports(sock_net(sk), fl4, sk,
  					   daddr, inet->inet_saddr,
  					   inet->inet_dport, inet->inet_sport,
  					   sk->sk_protocol, RT_CONN_FLAGS(sk),
@@@ -491,7 -508,7 +508,7 @@@
  	skb_dst_set(skb, dst_clone(&rt->dst));
  
  	/* Queue the packet to IP for output */
- 	rc = ip_queue_xmit(skb);
+ 	rc = ip_queue_xmit(skb, &inet->cork.fl);
  
  error:
  	/* Update stats */
@@@ -503,12 -520,15 +520,15 @@@
  		lsa->tx_errors++;
  	}
  
+ out:
+ 	release_sock(sk);
  	return rc;
  
  no_route:
  	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
  	kfree_skb(skb);
- 	return -EHOSTUNREACH;
+ 	rc = -EHOSTUNREACH;
+ 	goto out;
  }
  
  static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@@ -667,7 -687,7 +687,7 @@@ MODULE_AUTHOR("James Chapman <jchapman@
  MODULE_DESCRIPTION("L2TP over IP");
  MODULE_VERSION("1.0");
  
 -/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like
 +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
   * enums
   */
  MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
diff --combined net/mac80211/agg-tx.c
index 53defaf,cd5125f..c8be8ef
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@@ -136,26 -136,45 +136,37 @@@ void ieee80211_send_bar(struct ieee8021
  	ieee80211_tx_skb(sdata, skb);
  }
  
+ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+ 			     struct tid_ampdu_tx *tid_tx)
+ {
+ 	lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ 	lockdep_assert_held(&sta->lock);
+ 	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+ }
+ 
 -static void kfree_tid_tx(struct rcu_head *rcu_head)
 -{
 -	struct tid_ampdu_tx *tid_tx =
 -	    container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
 -
 -	kfree(tid_tx);
 -}
 -
  int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
  				    enum ieee80211_back_parties initiator,
  				    bool tx)
  {
  	struct ieee80211_local *local = sta->local;
- 	struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	struct tid_ampdu_tx *tid_tx;
  	int ret;
  
  	lockdep_assert_held(&sta->ampdu_mlme.mtx);
  
- 	if (!tid_tx)
- 		return -ENOENT;
- 
  	spin_lock_bh(&sta->lock);
  
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+ 	if (!tid_tx) {
+ 		spin_unlock_bh(&sta->lock);
+ 		return -ENOENT;
+ 	}
+ 
  	if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
  		/* not even started yet! */
- 		rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ 		ieee80211_assign_tid_tx(sta, tid, NULL);
  		spin_unlock_bh(&sta->lock);
 -		call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +		kfree_rcu(tid_tx, rcu_head);
  		return 0;
  	}
  
@@@ -275,13 -294,13 +286,13 @@@ ieee80211_wake_queue_agg(struct ieee802
  
  void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
  {
- 	struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	struct tid_ampdu_tx *tid_tx;
  	struct ieee80211_local *local = sta->local;
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
  	u16 start_seq_num;
  	int ret;
  
- 	lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
  	/*
  	 * While we're asking the driver about the aggregation,
@@@ -310,11 -329,11 +321,11 @@@
  					" tid %d\n", tid);
  #endif
  		spin_lock_bh(&sta->lock);
- 		rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ 		ieee80211_assign_tid_tx(sta, tid, NULL);
  		spin_unlock_bh(&sta->lock);
  
  		ieee80211_wake_queue_agg(local, tid);
 -		call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +		kfree_rcu(tid_tx, rcu_head);
  		return;
  	}
  
@@@ -388,9 -407,9 +399,9 @@@ int ieee80211_start_tx_ba_session(struc
  		goto err_unlock_sta;
  	}
  
- 	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  	/* check if the TID is not in aggregation flow already */
- 	if (tid_tx) {
+ 	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
  		printk(KERN_DEBUG "BA request denied - session is not "
  				 "idle on tid %u\n", tid);
@@@ -425,8 -444,11 +436,11 @@@
  	sta->ampdu_mlme.dialog_token_allocator++;
  	tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
  
- 	/* finally, assign it to the array */
- 	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+ 	/*
+ 	 * Finally, assign it to the start array; the work item will
+ 	 * collect it and move it to the normal array.
+ 	 */
+ 	sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
  
  	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
  
@@@ -472,16 -494,19 +486,19 @@@ ieee80211_agg_splice_finish(struct ieee
  static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
  					 struct sta_info *sta, u16 tid)
  {
+ 	struct tid_ampdu_tx *tid_tx;
+ 
  	lockdep_assert_held(&sta->ampdu_mlme.mtx);
  
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+ 
  #ifdef CONFIG_MAC80211_HT_DEBUG
  	printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
  #endif
  
  	drv_ampdu_action(local, sta->sdata,
  			 IEEE80211_AMPDU_TX_OPERATIONAL,
- 			 &sta->sta, tid, NULL,
- 			 sta->ampdu_mlme.tid_tx[tid]->buf_size);
+ 			 &sta->sta, tid, NULL, tid_tx->buf_size);
  
  	/*
  	 * synchronize with TX path, while splicing the TX path
@@@ -489,13 -514,13 +506,13 @@@
  	 */
  	spin_lock_bh(&sta->lock);
  
- 	ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+ 	ieee80211_agg_splice_packets(local, tid_tx, tid);
  	/*
  	 * Now mark as operational. This will be visible
  	 * in the TX path, and lets it go lock-free in
  	 * the common case.
  	 */
- 	set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+ 	set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
  	ieee80211_agg_splice_finish(local, tid);
  
  	spin_unlock_bh(&sta->lock);
@@@ -529,7 -554,7 +546,7 @@@ void ieee80211_start_tx_ba_cb(struct ie
  	}
  
  	mutex_lock(&sta->ampdu_mlme.mtx);
- 	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
  	if (WARN_ON(!tid_tx)) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
@@@ -607,7 -632,7 +624,7 @@@ int ieee80211_stop_tx_ba_session(struc
  		return -EINVAL;
  
  	spin_lock_bh(&sta->lock);
- 	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
  	if (!tid_tx) {
  		ret = -ENOENT;
@@@ -663,7 -688,7 +680,7 @@@ void ieee80211_stop_tx_ba_cb(struct iee
  
  	mutex_lock(&sta->ampdu_mlme.mtx);
  	spin_lock_bh(&sta->lock);
- 	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  
  	if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
@@@ -689,11 -714,11 +706,11 @@@
  	ieee80211_agg_splice_packets(local, tid_tx, tid);
  
  	/* future packets must not find the tid_tx struct any more */
- 	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ 	ieee80211_assign_tid_tx(sta, tid, NULL);
  
  	ieee80211_agg_splice_finish(local, tid);
  
 -	call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
 +	kfree_rcu(tid_tx, rcu_head);
  
   unlock_sta:
  	spin_unlock_bh(&sta->lock);
@@@ -744,7 -769,7 +761,7 @@@ void ieee80211_process_addba_resp(struc
  
  	mutex_lock(&sta->ampdu_mlme.mtx);
  
- 	tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ 	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
  	if (!tid_tx)
  		goto out;
  
diff --combined net/mac80211/work.c
index ac35496,a94b312..d2e7f0e
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@@ -65,9 -65,17 +65,9 @@@ static void run_again(struct ieee80211_
  		mod_timer(&local->work_timer, timeout);
  }
  
 -static void work_free_rcu(struct rcu_head *head)
 -{
 -	struct ieee80211_work *wk =
 -		container_of(head, struct ieee80211_work, rcu_head);
 -
 -	kfree(wk);
 -}
 -
  void free_work(struct ieee80211_work *wk)
  {
 -	call_rcu(&wk->rcu_head, work_free_rcu);
 +	kfree_rcu(wk, rcu_head);
  }
  
  static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
@@@ -190,9 -198,8 +190,8 @@@ static void ieee80211_send_assoc(struc
  	struct sk_buff *skb;
  	struct ieee80211_mgmt *mgmt;
  	u8 *pos, qos_info;
- 	const u8 *ies;
  	size_t offset = 0, noffset;
- 	int i, len, count, rates_len, supp_rates_len;
+ 	int i, count, rates_len, supp_rates_len;
  	u16 capab;
  	struct ieee80211_supported_band *sband;
  	u32 rates = 0;
@@@ -277,7 -284,7 +276,7 @@@
  	}
  
  	/* SSID */
- 	ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+ 	pos = skb_put(skb, 2 + wk->assoc.ssid_len);
  	*pos++ = WLAN_EID_SSID;
  	*pos++ = wk->assoc.ssid_len;
  	memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
@@@ -287,7 -294,6 +286,6 @@@
  	if (supp_rates_len > 8)
  		supp_rates_len = 8;
  
- 	len = sband->n_bitrates;
  	pos = skb_put(skb, supp_rates_len + 2);
  	*pos++ = WLAN_EID_SUPP_RATES;
  	*pos++ = supp_rates_len;
diff --combined net/phonet/pn_dev.c
index 1566672,47b3452..d2df8f3
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@@ -162,6 -162,14 +162,6 @@@ int phonet_address_add(struct net_devic
  	return err;
  }
  
 -static void phonet_device_rcu_free(struct rcu_head *head)
 -{
 -	struct phonet_device *pnd;
 -
 -	pnd = container_of(head, struct phonet_device, rcu);
 -	kfree(pnd);
 -}
 -
  int phonet_address_del(struct net_device *dev, u8 addr)
  {
  	struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
@@@ -180,7 -188,7 +180,7 @@@
  	mutex_unlock(&pndevs->lock);
  
  	if (pnd)
 -		call_rcu(&pnd->rcu, phonet_device_rcu_free);
 +		kfree_rcu(pnd, rcu);
  
  	return err;
  }
@@@ -418,18 -426,14 +418,14 @@@ int phonet_route_del(struct net_device 
  	return 0;
  }
  
- struct net_device *phonet_route_get(struct net *net, u8 daddr)
+ struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr)
  {
  	struct phonet_net *pnn = phonet_pernet(net);
  	struct phonet_routes *routes = &pnn->routes;
  	struct net_device *dev;
  
- 	ASSERT_RTNL(); /* no need to hold the device */
- 
  	daddr >>= 2;
- 	rcu_read_lock();
  	dev = rcu_dereference(routes->table[daddr]);
- 	rcu_read_unlock();
  	return dev;
  }
  
diff --combined net/sctp/bind_addr.c
index 3c06c87,6150ac5..6338413
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@@ -140,14 -140,12 +140,12 @@@ void sctp_bind_addr_init(struct sctp_bi
  /* Dispose of the address list. */
  static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
  {
- 	struct sctp_sockaddr_entry *addr;
- 	struct list_head *pos, *temp;
+ 	struct sctp_sockaddr_entry *addr, *temp;
  
  	/* Empty the bind address list. */
- 	list_for_each_safe(pos, temp, &bp->address_list) {
- 		addr = list_entry(pos, struct sctp_sockaddr_entry, list);
- 		list_del(pos);
- 		kfree(addr);
+ 	list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
+ 		list_del_rcu(&addr->list);
+ 		call_rcu(&addr->rcu, sctp_local_addr_free);
  		SCTP_DBG_OBJCNT_DEC(addr);
  	}
  }
@@@ -219,7 -217,7 +217,7 @@@ int sctp_del_bind_addr(struct sctp_bind
  	}
  
  	if (found) {
 -		call_rcu(&addr->rcu, sctp_local_addr_free);
 +		kfree_rcu(addr, rcu);
  		SCTP_DBG_OBJCNT_DEC(addr);
  		return 0;
  	}
diff --combined net/sctp/ipv6.c
index 185fe05,500875f..0bb0d7c
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@@ -80,6 -80,13 +80,13 @@@
  
  #include <asm/uaccess.h>
  
+ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
+ 					 union sctp_addr *s2);
+ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
+ 			      __be16 port);
+ static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
+ 			    const union sctp_addr *addr2);
+ 
  /* Event handler for inet6 address addition/deletion events.
   * The sctp_local_addr_list needs to be protocted by a spin lock since
   * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@@ -123,7 -130,7 +130,7 @@@ static int sctp_inet6addr_event(struct 
  		}
  		spin_unlock_bh(&sctp_local_addr_lock);
  		if (found)
 -			call_rcu(&addr->rcu, sctp_local_addr_free);
 +			kfree_rcu(addr, rcu);
  		break;
  	}
  
@@@ -240,37 -247,107 +247,107 @@@ static int sctp_v6_xmit(struct sk_buff 
  /* Returns the dst cache entry for the given source and destination ip
   * addresses.
   */
- static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
- 					 union sctp_addr *daddr,
- 					 union sctp_addr *saddr)
+ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ 			    struct flowi *fl, struct sock *sk)
  {
- 	struct dst_entry *dst;
- 	struct flowi6 fl6;
+ 	struct sctp_association *asoc = t->asoc;
+ 	struct dst_entry *dst = NULL;
+ 	struct flowi6 *fl6 = &fl->u.ip6;
+ 	struct sctp_bind_addr *bp;
+ 	struct sctp_sockaddr_entry *laddr;
+ 	union sctp_addr *baddr = NULL;
+ 	union sctp_addr *daddr = &t->ipaddr;
+ 	union sctp_addr dst_saddr;
+ 	__u8 matchlen = 0;
+ 	__u8 bmatchlen;
+ 	sctp_scope_t scope;
  
- 	memset(&fl6, 0, sizeof(fl6));
- 	ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr);
+ 	memset(fl6, 0, sizeof(struct flowi6));
+ 	ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
+ 	fl6->fl6_dport = daddr->v6.sin6_port;
+ 	fl6->flowi6_proto = IPPROTO_SCTP;
  	if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
- 		fl6.flowi6_oif = daddr->v6.sin6_scope_id;
+ 		fl6->flowi6_oif = daddr->v6.sin6_scope_id;
  
+ 	SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);
  
- 	SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr);
+ 	if (asoc)
+ 		fl6->fl6_sport = htons(asoc->base.bind_addr.port);
  
  	if (saddr) {
- 		ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr);
- 		SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr);
+ 		ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
+ 		fl6->fl6_sport = saddr->v6.sin6_port;
+ 		SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
+ 	}
+ 
+ 	dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+ 	if (!asoc || saddr)
+ 		goto out;
+ 
+ 	bp = &asoc->base.bind_addr;
+ 	scope = sctp_scope(daddr);
+ 	/* ip6_dst_lookup has filled in the fl6->saddr for us.  Check
+ 	 * to see if we can use it.
+ 	 */
+ 	if (!IS_ERR(dst)) {
+ 		/* Walk through the bind address list and look for a bind
+ 		 * address that matches the source address of the returned dst.
+ 		 */
+ 		sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
+ 		rcu_read_lock();
+ 		list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ 			if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+ 				continue;
+ 
+ 			/* Do not compare against v4 addrs */
+ 			if ((laddr->a.sa.sa_family == AF_INET6) &&
+ 			    (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
+ 				rcu_read_unlock();
+ 				goto out;
+ 			}
+ 		}
+ 		rcu_read_unlock();
+ 		/* None of the bound addresses match the source address of the
+ 		 * dst. So release it.
+ 		 */
+ 		dst_release(dst);
+ 		dst = NULL;
  	}
  
- 	dst = ip6_route_output(&init_net, NULL, &fl6);
- 	if (!dst->error) {
+ 	/* Walk through the bind address list and try to get the
+ 	 * best source address for a given destination.
+ 	 */
+ 	rcu_read_lock();
+ 	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
+ 		if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
+ 			continue;
+ 		if ((laddr->a.sa.sa_family == AF_INET6) &&
+ 		    (scope <= sctp_scope(&laddr->a))) {
+ 			bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
+ 			if (!baddr || (matchlen < bmatchlen)) {
+ 				baddr = &laddr->a;
+ 				matchlen = bmatchlen;
+ 			}
+ 		}
+ 	}
+ 	rcu_read_unlock();
+ 	if (baddr) {
+ 		ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
+ 		fl6->fl6_sport = baddr->v6.sin6_port;
+ 		dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+ 	}
+ 
+ out:
+ 	if (!IS_ERR(dst)) {
  		struct rt6_info *rt;
  		rt = (struct rt6_info *)dst;
+ 		t->dst = dst;
  		SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
- 			&rt->rt6i_dst.addr, &rt->rt6i_src.addr);
- 		return dst;
+ 			&rt->rt6i_dst.addr, &fl6->saddr);
+ 	} else {
+ 		t->dst = NULL;
+ 		SCTP_DEBUG_PRINTK("NO ROUTE\n");
  	}
- 	SCTP_DEBUG_PRINTK("NO ROUTE\n");
- 	dst_release(dst);
- 	return NULL;
  }
  
  /* Returns the number of consecutive initial bits that match in the 2 ipv6
@@@ -286,64 -363,18 +363,18 @@@ static inline int sctp_v6_addr_match_le
   * and asoc's bind address list.
   */
  static void sctp_v6_get_saddr(struct sctp_sock *sk,
- 			      struct sctp_association *asoc,
- 			      struct dst_entry *dst,
- 			      union sctp_addr *daddr,
- 			      union sctp_addr *saddr)
+ 			      struct sctp_transport *t,
+ 			      struct flowi *fl)
  {
- 	struct sctp_bind_addr *bp;
- 	struct sctp_sockaddr_entry *laddr;
- 	sctp_scope_t scope;
- 	union sctp_addr *baddr = NULL;
- 	__u8 matchlen = 0;
- 	__u8 bmatchlen;
+ 	struct flowi6 *fl6 = &fl->u.ip6;
+ 	union sctp_addr *saddr = &t->saddr;
  
- 	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
- 			  __func__, asoc, dst, &daddr->v6.sin6_addr);
- 
- 	if (!asoc) {
- 		ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
- 				   dst ? ip6_dst_idev(dst)->dev : NULL,
- 				   &daddr->v6.sin6_addr,
- 				   inet6_sk(&sk->inet.sk)->srcprefs,
- 				   &saddr->v6.sin6_addr);
- 		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
- 				  &saddr->v6.sin6_addr);
- 		return;
- 	}
- 
- 	scope = sctp_scope(daddr);
- 
- 	bp = &asoc->base.bind_addr;
+ 	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
  
- 	/* Go through the bind address list and find the best source address
- 	 * that matches the scope of the destination address.
- 	 */
- 	rcu_read_lock();
- 	list_for_each_entry_rcu(laddr, &bp->address_list, list) {
- 		if (!laddr->valid)
- 			continue;
- 		if ((laddr->state == SCTP_ADDR_SRC) &&
- 		    (laddr->a.sa.sa_family == AF_INET6) &&
- 		    (scope <= sctp_scope(&laddr->a))) {
- 			bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
- 			if (!baddr || (matchlen < bmatchlen)) {
- 				baddr = &laddr->a;
- 				matchlen = bmatchlen;
- 			}
- 		}
- 	}
- 
- 	if (baddr) {
- 		memcpy(saddr, baddr, sizeof(union sctp_addr));
- 		SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
- 	} else {
- 		pr_err("%s: asoc:%p Could not find a valid source "
- 		       "address for the dest:%pI6\n",
- 		       __func__, asoc, &daddr->v6.sin6_addr);
+ 	if (t->dst) {
+ 		saddr->v6.sin6_family = AF_INET6;
+ 		ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
  	}
- 
- 	rcu_read_unlock();
  }
  
  /* Make a copy of all potential local addresses. */
@@@ -465,14 -496,13 +496,13 @@@ static int sctp_v6_to_addr_param(const 
  	return length;
  }
  
- /* Initialize a sctp_addr from a dst_entry. */
- static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
+ /* Initialize a sctp_addr from struct in6_addr. */
+ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
  			      __be16 port)
  {
- 	struct rt6_info *rt = (struct rt6_info *)dst;
  	addr->sa.sa_family = AF_INET6;
  	addr->v6.sin6_port = port;
- 	ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
+ 	ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
  }
  
  /* Compare addresses exactly.
@@@ -531,7 -561,7 +561,7 @@@ static int sctp_v6_is_any(const union s
  static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
  {
  	int type;
- 	struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
+ 	const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
  
  	type = ipv6_addr_type(in6);
  	if (IPV6_ADDR_ANY == type)
@@@ -959,7 -989,6 +989,6 @@@ static struct sctp_af sctp_af_inet6 = 
  	.to_sk_daddr	   = sctp_v6_to_sk_daddr,
  	.from_addr_param   = sctp_v6_from_addr_param,
  	.to_addr_param	   = sctp_v6_to_addr_param,
- 	.dst_saddr	   = sctp_v6_dst_saddr,
  	.cmp_addr	   = sctp_v6_cmp_addr,
  	.scope		   = sctp_v6_scope,
  	.addr_valid	   = sctp_v6_addr_valid,
diff --combined net/sctp/protocol.c
index 065d999,4de77cb..67380a2
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@@ -230,6 -230,13 +230,6 @@@ static void sctp_free_local_addr_list(v
  	}
  }
  
 -void sctp_local_addr_free(struct rcu_head *head)
 -{
 -	struct sctp_sockaddr_entry *e = container_of(head,
 -				struct sctp_sockaddr_entry, rcu);
 -	kfree(e);
 -}
 -
  /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
  int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
  			      gfp_t gfp, int copy_flags)
@@@ -332,13 -339,12 +332,12 @@@ static int sctp_v4_to_addr_param(const 
  }
  
  /* Initialize a sctp_addr from a dst_entry. */
- static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
+ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4,
  			      __be16 port)
  {
- 	struct rtable *rt = (struct rtable *)dst;
  	saddr->v4.sin_family = AF_INET;
  	saddr->v4.sin_port = port;
- 	saddr->v4.sin_addr.s_addr = rt->rt_src;
+ 	saddr->v4.sin_addr.s_addr = fl4->saddr;
  }
  
  /* Compare two addresses exactly. */
@@@ -456,35 -462,36 +455,36 @@@ static sctp_scope_t sctp_v4_scope(unio
   * addresses. If an association is passed, trys to get a dst entry with a
   * source address that matches an address in the bind address list.
   */
- static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
- 					 union sctp_addr *daddr,
- 					 union sctp_addr *saddr)
+ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
+ 				struct flowi *fl, struct sock *sk)
  {
+ 	struct sctp_association *asoc = t->asoc;
  	struct rtable *rt;
- 	struct flowi4 fl4;
+ 	struct flowi4 *fl4 = &fl->u.ip4;
  	struct sctp_bind_addr *bp;
  	struct sctp_sockaddr_entry *laddr;
  	struct dst_entry *dst = NULL;
+ 	union sctp_addr *daddr = &t->ipaddr;
  	union sctp_addr dst_saddr;
  
- 	memset(&fl4, 0x0, sizeof(struct flowi4));
- 	fl4.daddr  = daddr->v4.sin_addr.s_addr;
- 	fl4.fl4_dport = daddr->v4.sin_port;
- 	fl4.flowi4_proto = IPPROTO_SCTP;
+ 	memset(fl4, 0x0, sizeof(struct flowi4));
+ 	fl4->daddr  = daddr->v4.sin_addr.s_addr;
+ 	fl4->fl4_dport = daddr->v4.sin_port;
+ 	fl4->flowi4_proto = IPPROTO_SCTP;
  	if (asoc) {
- 		fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
- 		fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if;
- 		fl4.fl4_sport = htons(asoc->base.bind_addr.port);
+ 		fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
+ 		fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
+ 		fl4->fl4_sport = htons(asoc->base.bind_addr.port);
  	}
  	if (saddr) {
- 		fl4.saddr = saddr->v4.sin_addr.s_addr;
- 		fl4.fl4_sport = saddr->v4.sin_port;
+ 		fl4->saddr = saddr->v4.sin_addr.s_addr;
+ 		fl4->fl4_sport = saddr->v4.sin_port;
  	}
  
  	SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
- 			  __func__, &fl4.daddr, &fl4.saddr);
+ 			  __func__, &fl4->daddr, &fl4->saddr);
  
- 	rt = ip_route_output_key(&init_net, &fl4);
+ 	rt = ip_route_output_key(&init_net, fl4);
  	if (!IS_ERR(rt))
  		dst = &rt->dst;
  
@@@ -500,7 -507,7 +500,7 @@@
  		/* Walk through the bind address list and look for a bind
  		 * address that matches the source address of the returned dst.
  		 */
- 		sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
+ 		sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
  		rcu_read_lock();
  		list_for_each_entry_rcu(laddr, &bp->address_list, list) {
  			if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
@@@ -526,9 -533,9 +526,9 @@@
  			continue;
  		if ((laddr->state == SCTP_ADDR_SRC) &&
  		    (AF_INET == laddr->a.sa.sa_family)) {
- 			fl4.saddr = laddr->a.v4.sin_addr.s_addr;
- 			fl4.fl4_sport = laddr->a.v4.sin_port;
- 			rt = ip_route_output_key(&init_net, &fl4);
+ 			fl4->saddr = laddr->a.v4.sin_addr.s_addr;
+ 			fl4->fl4_sport = laddr->a.v4.sin_port;
+ 			rt = ip_route_output_key(&init_net, fl4);
  			if (!IS_ERR(rt)) {
  				dst = &rt->dst;
  				goto out_unlock;
@@@ -539,33 -546,27 +539,27 @@@
  out_unlock:
  	rcu_read_unlock();
  out:
+ 	t->dst = dst;
  	if (dst)
  		SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
- 				  &rt->rt_dst, &rt->rt_src);
+ 				  &fl4->daddr, &fl4->saddr);
  	else
  		SCTP_DEBUG_PRINTK("NO ROUTE\n");
- 
- 	return dst;
  }
  
  /* For v4, the source address is cached in the route entry(dst). So no need
   * to cache it separately and hence this is an empty routine.
   */
  static void sctp_v4_get_saddr(struct sctp_sock *sk,
- 			      struct sctp_association *asoc,
- 			      struct dst_entry *dst,
- 			      union sctp_addr *daddr,
- 			      union sctp_addr *saddr)
+ 			      struct sctp_transport *t,
+ 			      struct flowi *fl)
  {
- 	struct rtable *rt = (struct rtable *)dst;
- 
- 	if (!asoc)
- 		return;
+ 	union sctp_addr *saddr = &t->saddr;
+ 	struct rtable *rt = (struct rtable *)t->dst;
  
  	if (rt) {
  		saddr->v4.sin_family = AF_INET;
- 		saddr->v4.sin_port = htons(asoc->base.bind_addr.port);
- 		saddr->v4.sin_addr.s_addr = rt->rt_src;
+ 		saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr;
  	}
  }
  
@@@ -674,7 -675,7 +668,7 @@@ static int sctp_inetaddr_event(struct n
  		}
  		spin_unlock_bh(&sctp_local_addr_lock);
  		if (found)
 -			call_rcu(&addr->rcu, sctp_local_addr_free);
 +			kfree_rcu(addr, rcu);
  		break;
  	}
  
@@@ -847,14 -848,14 +841,14 @@@ static inline int sctp_v4_xmit(struct s
  
  	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
  			  __func__, skb, skb->len,
- 			  &skb_rtable(skb)->rt_src,
- 			  &skb_rtable(skb)->rt_dst);
+ 			  &transport->fl.u.ip4.saddr,
+ 			  &transport->fl.u.ip4.daddr);
  
  	inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
  			 IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
  
  	SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
- 	return ip_queue_xmit(skb);
+ 	return ip_queue_xmit(skb, &transport->fl);
  }
  
  static struct sctp_af sctp_af_inet;
@@@ -943,7 -944,6 +937,6 @@@ static struct sctp_af sctp_af_inet = 
  	.to_sk_daddr	   = sctp_v4_to_sk_daddr,
  	.from_addr_param   = sctp_v4_from_addr_param,
  	.to_addr_param	   = sctp_v4_to_addr_param,
- 	.dst_saddr	   = sctp_v4_dst_saddr,
  	.cmp_addr	   = sctp_v4_cmp_addr,
  	.addr_valid	   = sctp_v4_addr_valid,
  	.inaddr_any	   = sctp_v4_inaddr_any,
diff --combined net/sctp/ulpevent.c
index 61b1f5a,c962c60..e70e5fc
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@@ -554,7 -554,7 +554,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak
  	memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
  
  	/* Per TSVWG discussion with Randy. Allow the application to
 -	 * resemble a fragmented message.
 +	 * reassemble a fragmented message.
  	 */
  	ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
  
@@@ -843,7 -843,7 +843,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak
  	ak = (struct sctp_authkey_event *)
  		skb_put(skb, sizeof(struct sctp_authkey_event));
  
- 	ak->auth_type = SCTP_AUTHENTICATION_INDICATION;
+ 	ak->auth_type = SCTP_AUTHENTICATION_EVENT;
  	ak->auth_flags = 0;
  	ak->auth_length = sizeof(struct sctp_authkey_event);
  
@@@ -862,6 -862,34 +862,34 @@@ fail
  	return NULL;
  }
  
+ /*
+  * Socket Extensions for SCTP
+  * 6.3.10. SCTP_SENDER_DRY_EVENT
+  */
+ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
+ 	const struct sctp_association *asoc, gfp_t gfp)
+ {
+ 	struct sctp_ulpevent *event;
+ 	struct sctp_sender_dry_event *sdry;
+ 	struct sk_buff *skb;
+ 
+ 	event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event),
+ 				  MSG_NOTIFICATION, gfp);
+ 	if (!event)
+ 		return NULL;
+ 
+ 	skb = sctp_event2skb(event);
+ 	sdry = (struct sctp_sender_dry_event *)
+ 		skb_put(skb, sizeof(struct sctp_sender_dry_event));
+ 
+ 	sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
+ 	sdry->sender_dry_flags = 0;
+ 	sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event);
+ 	sctp_ulpevent_set_owner(event, asoc);
+ 	sdry->sender_dry_assoc_id = sctp_assoc2id(asoc);
+ 
+ 	return event;
+ }
  
  /* Return the notification type, assuming this is a notification
   * event.
diff --combined net/socket.c
index c2ed7c9,2d5382d..02dc82d
--- a/net/socket.c
+++ b/net/socket.c
@@@ -263,6 -263,15 +263,6 @@@ static struct inode *sock_alloc_inode(s
  	return &ei->vfs_inode;
  }
  
 -
 -
 -static void wq_free_rcu(struct rcu_head *head)
 -{
 -	struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
 -
 -	kfree(wq);
 -}
 -
  static void sock_destroy_inode(struct inode *inode)
  {
  	struct socket_alloc *ei;
@@@ -270,7 -279,7 +270,7 @@@
  
  	ei = container_of(inode, struct socket_alloc, vfs_inode);
  	wq = rcu_dereference_protected(ei->socket.wq, 1);
 -	call_rcu(&wq->rcu, wq_free_rcu);
 +	kfree_rcu(wq, rcu);
  	kmem_cache_free(sock_inode_cachep, ei);
  }
  
@@@ -542,11 -551,10 +542,10 @@@ int sock_tx_timestamp(struct sock *sk, 
  }
  EXPORT_SYMBOL(sock_tx_timestamp);
  
- static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
- 				 struct msghdr *msg, size_t size)
+ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
+ 				       struct msghdr *msg, size_t size)
  {
  	struct sock_iocb *si = kiocb_to_siocb(iocb);
- 	int err;
  
  	sock_update_classid(sock->sk);
  
@@@ -555,13 -563,17 +554,17 @@@
  	si->msg = msg;
  	si->size = size;
  
  	return sock->ops->sendmsg(iocb, sock, msg, size);
  }
  
+ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ 				 struct msghdr *msg, size_t size)
+ {
+ 	int err = security_socket_sendmsg(sock, msg, size);
+ 
+ 	return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
+ }
+ 
  int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
  {
  	struct kiocb iocb;
@@@ -577,6 -589,20 +580,20 @@@
  }
  EXPORT_SYMBOL(sock_sendmsg);
  
+ int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size)
+ {
+ 	struct kiocb iocb;
+ 	struct sock_iocb siocb;
+ 	int ret;
+ 
+ 	init_sync_kiocb(&iocb, NULL);
+ 	iocb.private = &siocb;
+ 	ret = __sock_sendmsg_nosec(&iocb, sock, msg, size);
+ 	if (-EIOCBQUEUED == ret)
+ 		ret = wait_on_sync_kiocb(&iocb);
+ 	return ret;
+ }
+ 
  int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
  		   struct kvec *vec, size_t num, size_t size)
  {
@@@ -1854,57 -1880,47 +1871,47 @@@ SYSCALL_DEFINE2(shutdown, int, fd, int
  #define COMPAT_NAMELEN(msg)	COMPAT_MSG(msg, msg_namelen)
  #define COMPAT_FLAGS(msg)	COMPAT_MSG(msg, msg_flags)
  
- /*
-  *	BSD sendmsg interface
-  */
- 
- SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
+ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
+ 			 struct msghdr *msg_sys, unsigned flags, int nosec)
  {
  	struct compat_msghdr __user *msg_compat =
  	    (struct compat_msghdr __user *)msg;
- 	struct socket *sock;
  	struct sockaddr_storage address;
  	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
  	unsigned char ctl[sizeof(struct cmsghdr) + 20]
  	    __attribute__ ((aligned(sizeof(__kernel_size_t))));
  	/* 20 is size of ipv6_pktinfo */
  	unsigned char *ctl_buf = ctl;
- 	struct msghdr msg_sys;
  	int err, ctl_len, iov_size, total_len;
  
  	err = -EFAULT;
  	if (MSG_CMSG_COMPAT & flags) {
- 		if (get_compat_msghdr(&msg_sys, msg_compat))
+ 		if (get_compat_msghdr(msg_sys, msg_compat))
  			return -EFAULT;
- 	} else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ 	} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
  		return -EFAULT;
  
- 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
- 	if (!sock)
- 		goto out;
- 
  	/* do not move before msg_sys is valid */
  	err = -EMSGSIZE;
- 	if (msg_sys.msg_iovlen > UIO_MAXIOV)
- 		goto out_put;
+ 	if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ 		goto out;
  
  	/* Check whether to allocate the iovec area */
  	err = -ENOMEM;
- 	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
- 	if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+ 	iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
+ 	if (msg_sys->msg_iovlen > UIO_FASTIOV) {
  		iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
  		if (!iov)
- 			goto out_put;
+ 			goto out;
  	}
  
  	/* This will also move the address data into kernel space */
  	if (MSG_CMSG_COMPAT & flags) {
- 		err = verify_compat_iovec(&msg_sys, iov,
+ 		err = verify_compat_iovec(msg_sys, iov,
  					  (struct sockaddr *)&address,
  					  VERIFY_READ);
  	} else
- 		err = verify_iovec(&msg_sys, iov,
+ 		err = verify_iovec(msg_sys, iov,
  				   (struct sockaddr *)&address,
  				   VERIFY_READ);
  	if (err < 0)
@@@ -1913,17 -1929,17 +1920,17 @@@
  
  	err = -ENOBUFS;
  
- 	if (msg_sys.msg_controllen > INT_MAX)
+ 	if (msg_sys->msg_controllen > INT_MAX)
  		goto out_freeiov;
- 	ctl_len = msg_sys.msg_controllen;
+ 	ctl_len = msg_sys->msg_controllen;
  	if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
  		err =
- 		    cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl,
+ 		    cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl,
  						     sizeof(ctl));
  		if (err)
  			goto out_freeiov;
- 		ctl_buf = msg_sys.msg_control;
- 		ctl_len = msg_sys.msg_controllen;
+ 		ctl_buf = msg_sys->msg_control;
+ 		ctl_len = msg_sys->msg_controllen;
  	} else if (ctl_len) {
  		if (ctl_len > sizeof(ctl)) {
  			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
@@@ -1932,21 -1948,22 +1939,22 @@@
  		}
  		err = -EFAULT;
  		/*
- 		 * Careful! Before this, msg_sys.msg_control contains a user pointer.
+ 		 * Careful! Before this, msg_sys->msg_control contains a user pointer.
  		 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
  		 * checking falls down on this.
  		 */
  		if (copy_from_user(ctl_buf,
- 				   (void __user __force *)msg_sys.msg_control,
+ 				   (void __user __force *)msg_sys->msg_control,
  				   ctl_len))
  			goto out_freectl;
- 		msg_sys.msg_control = ctl_buf;
+ 		msg_sys->msg_control = ctl_buf;
  	}
- 	msg_sys.msg_flags = flags;
+ 	msg_sys->msg_flags = flags;
  
  	if (sock->file->f_flags & O_NONBLOCK)
- 		msg_sys.msg_flags |= MSG_DONTWAIT;
- 	err = sock_sendmsg(sock, &msg_sys, total_len);
+ 		msg_sys->msg_flags |= MSG_DONTWAIT;
+ 	err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
+ 							  total_len);
  
  out_freectl:
  	if (ctl_buf != ctl)
@@@ -1954,12 -1971,114 +1962,114 @@@
  out_freeiov:
  	if (iov != iovstack)
  		sock_kfree_s(sock->sk, iov, iov_size);
- out_put:
+ out:
+ 	return err;
+ }
+ 
+ /*
+  *	BSD sendmsg interface
+  */
+ 
+ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
+ {
+ 	int fput_needed, err;
+ 	struct msghdr msg_sys;
+ 	struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ 
+ 	if (!sock)
+ 		goto out;
+ 
+ 	err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
+ 
  	fput_light(sock->file, fput_needed);
  out:
  	return err;
  }
  
+ /*
+  *	Linux sendmmsg interface
+  */
+ 
+ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ 		   unsigned int flags)
+ {
+ 	int fput_needed, err, datagrams;
+ 	struct socket *sock;
+ 	struct mmsghdr __user *entry;
+ 	struct compat_mmsghdr __user *compat_entry;
+ 	struct msghdr msg_sys;
+ 
+ 	datagrams = 0;
+ 
+ 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ 	if (!sock)
+ 		return err;
+ 
+ 	err = sock_error(sock->sk);
+ 	if (err)
+ 		goto out_put;
+ 
+ 	entry = mmsg;
+ 	compat_entry = (struct compat_mmsghdr __user *)mmsg;
+ 
+ 	while (datagrams < vlen) {
+ 		/*
+ 		 * No need to ask LSM for more than the first datagram.
+ 		 */
+ 		if (MSG_CMSG_COMPAT & flags) {
+ 			err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
+ 					    &msg_sys, flags, datagrams);
+ 			if (err < 0)
+ 				break;
+ 			err = __put_user(err, &compat_entry->msg_len);
+ 			++compat_entry;
+ 		} else {
+ 			err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
+ 					    &msg_sys, flags, datagrams);
+ 			if (err < 0)
+ 				break;
+ 			err = put_user(err, &entry->msg_len);
+ 			++entry;
+ 		}
+ 
+ 		if (err)
+ 			break;
+ 		++datagrams;
+ 	}
+ 
+ out_put:
+ 	fput_light(sock->file, fput_needed);
+ 
+ 	if (err == 0)
+ 		return datagrams;
+ 
+ 	if (datagrams != 0) {
+ 		/*
+ 		 * We may send less entries than requested (vlen) if the
+ 		 * sock is non blocking...
+ 		 */
+ 		if (err != -EAGAIN) {
+ 			/*
+ 			 * ... or if sendmsg returns an error after we
+ 			 * send some datagrams, where we record the
+ 			 * error to return on the next call or if the
+ 			 * app asks about it using getsockopt(SO_ERROR).
+ 			 */
+ 			sock->sk->sk_err = -err;
+ 		}
+ 
+ 		return datagrams;
+ 	}
+ 
+ 	return err;
+ }
+ 
+ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
+ 		unsigned int, vlen, unsigned int, flags)
+ {
+ 	return __sys_sendmmsg(fd, mmsg, vlen, flags);
+ }
+ 
  static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
  			 struct msghdr *msg_sys, unsigned flags, int nosec)
  {
@@@ -2113,14 -2232,16 +2223,16 @@@ int __sys_recvmmsg(int fd, struct mmsgh
  		 */
  		if (MSG_CMSG_COMPAT & flags) {
  			err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
- 					    &msg_sys, flags, datagrams);
+ 					    &msg_sys, flags & ~MSG_WAITFORONE,
+ 					    datagrams);
  			if (err < 0)
  				break;
  			err = __put_user(err, &compat_entry->msg_len);
  			++compat_entry;
  		} else {
  			err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
- 					    &msg_sys, flags, datagrams);
+ 					    &msg_sys, flags & ~MSG_WAITFORONE,
+ 					    datagrams);
  			if (err < 0)
  				break;
  			err = put_user(err, &entry->msg_len);
@@@ -2205,11 -2326,11 +2317,11 @@@ SYSCALL_DEFINE5(recvmmsg, int, fd, stru
  #ifdef __ARCH_WANT_SYS_SOCKETCALL
  /* Argument list sizes for sys_socketcall */
  #define AL(x) ((x) * sizeof(unsigned long))
- static const unsigned char nargs[20] = {
+ static const unsigned char nargs[21] = {
  	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
  	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
  	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
- 	AL(4), AL(5)
+ 	AL(4), AL(5), AL(4)
  };
  
  #undef AL
@@@ -2229,7 -2350,7 +2341,7 @@@ SYSCALL_DEFINE2(socketcall, int, call, 
  	int err;
  	unsigned int len;
  
- 	if (call < 1 || call > SYS_RECVMMSG)
+ 	if (call < 1 || call > SYS_SENDMMSG)
  		return -EINVAL;
  
  	len = nargs[call];
@@@ -2304,6 -2425,9 +2416,9 @@@
  	case SYS_SENDMSG:
  		err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
  		break;
+ 	case SYS_SENDMMSG:
+ 		err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
+ 		break;
  	case SYS_RECVMSG:
  		err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
  		break;
@@@ -2634,13 -2758,13 +2749,13 @@@ static int ethtool_ioctl(struct net *ne
  		return -EFAULT;
  
  	if (convert_in) {
- 		/* We expect there to be holes between fs.m_u and
+ 		/* We expect there to be holes between fs.m_ext and
  		 * fs.ring_cookie and at the end of fs, but nowhere else.
  		 */
- 		BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) +
- 			     sizeof(compat_rxnfc->fs.m_u) !=
- 			     offsetof(struct ethtool_rxnfc, fs.m_u) +
- 			     sizeof(rxnfc->fs.m_u));
+ 		BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) +
+ 			     sizeof(compat_rxnfc->fs.m_ext) !=
+ 			     offsetof(struct ethtool_rxnfc, fs.m_ext) +
+ 			     sizeof(rxnfc->fs.m_ext));
  		BUILD_BUG_ON(
  			offsetof(struct compat_ethtool_rxnfc, fs.location) -
  			offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
@@@ -2648,7 -2772,7 +2763,7 @@@
  			offsetof(struct ethtool_rxnfc, fs.ring_cookie));
  
  		if (copy_in_user(rxnfc, compat_rxnfc,
- 				 (void *)(&rxnfc->fs.m_u + 1) -
+ 				 (void *)(&rxnfc->fs.m_ext + 1) -
  				 (void *)rxnfc) ||
  		    copy_in_user(&rxnfc->fs.ring_cookie,
  				 &compat_rxnfc->fs.ring_cookie,
@@@ -2665,7 -2789,7 +2780,7 @@@
  
  	if (convert_out) {
  		if (copy_in_user(compat_rxnfc, rxnfc,
- 				 (const void *)(&rxnfc->fs.m_u + 1) -
+ 				 (const void *)(&rxnfc->fs.m_ext + 1) -
  				 (const void *)rxnfc) ||
  		    copy_in_user(&compat_rxnfc->fs.ring_cookie,
  				 &rxnfc->fs.ring_cookie,

-- 
LinuxNextTracking


More information about the linux-merge mailing list