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

batman at open-mesh.org batman at open-mesh.org
Wed Dec 7 00:15:40 CET 2016


The following commit has been merged in the master branch:
commit 8eec5b02fd2df6556082634a13c6742a64c01b4a
Merge: 432ee303783413be3dad83ab4e1c2fac3434fd63 b0da4f743db522e006de5c8a1956b600872e6979
Author: Stephen Rothwell <sfr at canb.auug.org.au>
Date:   Tue Dec 6 10:30:10 2016 +1100

    Merge remote-tracking branch 'net-next/master'

diff --combined MAINTAINERS
index b1cadd8,c04f619..fef3382
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@@ -35,13 -35,13 +35,13 @@@ trivial patch so apply some common sens
  
  	PLEASE check your patch with the automated style checker
  	(scripts/checkpatch.pl) to catch trivial style violations.
 -	See Documentation/CodingStyle for guidance here.
 +	See Documentation/process/coding-style.rst for guidance here.
  
  	PLEASE CC: the maintainers and mailing lists that are generated
  	by scripts/get_maintainer.pl.  The results returned by the
  	script will be best if you have git installed and are making
  	your changes in a branch derived from Linus' latest git tree.
 -	See Documentation/SubmittingPatches for details.
 +	See Documentation/process/submitting-patches.rst for details.
  
  	PLEASE try to include any credit lines you want added with the
  	patch. It avoids people being missed off by mistake and makes
@@@ -54,7 -54,7 +54,7 @@@
  	of the Linux Foundation certificate of contribution and should
  	include a Signed-off-by: line.  The current version of this
  	"Developer's Certificate of Origin" (DCO) is listed in the file
 -	Documentation/SubmittingPatches.
 +	Documentation/process/submitting-patches.rst.
  
  6.	Make sure you have the right to send any changes you make. If you
  	do changes at work you may find your employer owns the patch
@@@ -1026,7 -1026,6 +1026,7 @@@ L:	linux-arm-kernel at lists.infradead.or
  S:	Maintained
  N:	sun[x456789]i
  F:	arch/arm/boot/dts/ntc-gr8*
 +F:	arch/arm64/boot/dts/allwinner/
  
  ARM/Allwinner SoC Clock Support
  M:	Emilio López <emilio at elopez.com.ar>
@@@ -1487,9 -1486,8 +1487,9 @@@ L:	linux-arm-kernel at lists.infradead.or
  L:	linux-oxnas at lists.tuxfamily.org (moderated for non-subscribers)
  S:	Maintained
  F:	arch/arm/mach-oxnas/
 -F:	arch/arm/boot/dts/oxnas*
 +F:	arch/arm/boot/dts/ox8*.dtsi
  F:	arch/arm/boot/dts/wd-mbwe.dts
 +F:	arch/arm/boot/dts/cloudengines-pogoplug-series-3.dts
  N:	oxnas
  
  ARM/Mediatek RTC DRIVER
@@@ -1610,7 -1608,6 +1610,7 @@@ F:	arch/arm/mach-qcom
  F:	arch/arm64/boot/dts/qcom/*
  F:	drivers/i2c/busses/i2c-qup.c
  F:	drivers/clk/qcom/
 +F:	drivers/pinctrl/qcom/
  F:	drivers/soc/qcom/
  F:	drivers/spi/spi-qup.c
  F:	drivers/tty/serial/msm_serial.h
@@@ -1790,7 -1787,9 +1790,7 @@@ F:	drivers/media/rc/st_rc.
  F:	drivers/media/platform/sti/c8sectpfe/
  F:	drivers/mmc/host/sdhci-st.c
  F:	drivers/phy/phy-miphy28lp.c
 -F:	drivers/phy/phy-miphy365x.c
  F:	drivers/phy/phy-stih407-usb.c
 -F:	drivers/phy/phy-stih41x-usb.c
  F:	drivers/pinctrl/pinctrl-st.c
  F:	drivers/remoteproc/st_remoteproc.c
  F:	drivers/reset/sti/
@@@ -2538,6 -2537,8 +2538,8 @@@ L:	netdev at vger.kernel.or
  L:	linux-kernel at vger.kernel.org
  S:	Supported
  F:	kernel/bpf/
+ F:	tools/testing/selftests/bpf/
+ F:	lib/test_bpf.c
  
  BROADCOM B44 10/100 ETHERNET DRIVER
  M:	Michael Chan <michael.chan at broadcom.com>
@@@ -2750,14 -2751,6 +2752,14 @@@ L:	bcm-kernel-feedback-list at broadcom.co
  S:	Maintained
  F:	drivers/mtd/nand/brcmnand/
  
 +BROADCOM STB AVS CPUFREQ DRIVER
 +M:	Markus Mayer <mmayer at broadcom.com>
 +M:	bcm-kernel-feedback-list at broadcom.com
 +L:	linux-pm at vger.kernel.org
 +S:	Maintained
 +F:	Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
 +F:	drivers/cpufreq/brcmstb*
 +
  BROADCOM SPECIFIC AMBA DRIVER (BCMA)
  M:	Rafał Miłecki <zajec5 at gmail.com>
  L:	linux-wireless at vger.kernel.org
@@@ -2772,7 -2765,7 +2774,7 @@@ S:	Supporte
  F:	drivers/net/ethernet/broadcom/bcmsysport.*
  
  BROADCOM VULCAN ARM64 SOC
 -M:	Jayachandran C. <jchandra at broadcom.com>
 +M:	Jayachandran C. <c.jayachandran at gmail.com>
  M:	bcm-kernel-feedback-list at broadcom.com
  L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
  S:	Maintained
@@@ -2946,7 -2939,7 +2948,7 @@@ CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVE
  M:	Kevin Tsai <ktsai at capellamicro.com>
  S:	Maintained
  F:	drivers/iio/light/cm*
 -F:	Documentation/devicetree/bindings/i2c/trivial-devices.txt
 +F:	Documentation/devicetree/bindings/i2c/trivial-admin-guide/devices.rst
  
  CAVIUM I2C DRIVER
  M:	Jan Glauber <jglauber at cavium.com>
@@@ -2980,15 -2973,15 +2982,15 @@@ L:	linux-media at vger.kernel.or
  T:	git git://linuxtv.org/media_tree.git
  W:	http://linuxtv.org
  S:	Supported
 -F:	Documentation/cec.txt
 +F:	Documentation/media/kapi/cec-core.rst
  F:	Documentation/media/uapi/cec
 -F:	drivers/staging/media/cec/
 +F:	drivers/media/cec/
  F:	drivers/media/cec-edid.c
  F:	drivers/media/rc/keymaps/rc-cec.c
  F:	include/media/cec.h
  F:	include/media/cec-edid.h
 -F:	include/linux/cec.h
 -F:	include/linux/cec-funcs.h
 +F:	include/uapi/linux/cec.h
 +F:	include/uapi/linux/cec-funcs.h
  
  CELL BROADBAND ENGINE ARCHITECTURE
  M:	Arnd Bergmann <arnd at arndb.de>
@@@ -3094,7 -3087,7 +3096,7 @@@ M:	Harry Wei <harryxiyou at gmail.com
  L:	xiyoulinuxkernelgroup at googlegroups.com (subscribers-only)
  L:	linux-kernel at zh-kernel.org (moderated for non-subscribers)
  S:	Maintained
 -F:	Documentation/zh_CN/
 +F:	Documentation/translations/zh_CN/
  
  CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
  M:	Peter Chen <Peter.Chen at nxp.com>
@@@ -3350,7 -3343,6 +3352,7 @@@ L:	linux-pm at vger.kernel.or
  S:	Maintained
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
  T:	git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates)
 +B:	https://bugzilla.kernel.org
  F:	Documentation/cpu-freq/
  F:	drivers/cpufreq/
  F:	include/linux/cpufreq.h
@@@ -3390,7 -3382,6 +3392,7 @@@ M:	Daniel Lezcano <daniel.lezcano at linar
  L:	linux-pm at vger.kernel.org
  S:	Maintained
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 +B:	https://bugzilla.kernel.org
  F:	drivers/cpuidle/*
  F:	include/linux/cpuidle.h
  
@@@ -6114,6 -6105,7 +6116,7 @@@ F:	drivers/idle/i7300_idle.
  
  IEEE 802.15.4 SUBSYSTEM
  M:	Alexander Aring <aar at pengutronix.de>
+ M:	Stefan Schmidt <stefan at osg.samsung.com>
  L:	linux-wpan at vger.kernel.org
  W:	http://wpan.cakelab.org/
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
@@@ -6300,11 -6292,9 +6303,11 @@@ S:	Maintaine
  F:	drivers/platform/x86/intel-vbtn.c
  
  INTEL IDLE DRIVER
 +M:	Jacob Pan <jacob.jun.pan at linux.intel.com>
  M:	Len Brown <lenb at kernel.org>
  L:	linux-pm at vger.kernel.org
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
 +B:	https://bugzilla.kernel.org
  S:	Supported
  F:	drivers/idle/intel_idle.c
  
@@@ -7578,8 -7568,10 +7581,10 @@@ S:	Maintaine
  MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
  M:	Andrew Lunn <andrew at lunn.ch>
  M:	Vivien Didelot <vivien.didelot at savoirfairelinux.com>
+ L:	netdev at vger.kernel.org
  S:	Maintained
  F:	drivers/net/dsa/mv88e6xxx/
+ F:	Documentation/devicetree/bindings/net/dsa/marvell.txt
  
  MARVELL ARMADA DRM SUPPORT
  M:	Russell King <rmk+kernel at armlinux.org.uk>
@@@ -7747,15 -7739,6 +7752,15 @@@ F:	Documentation/devicetree/bindings/me
  F:	drivers/media/platform/rcar-fcp.c
  F:	include/media/rcar-fcp.h
  
 +MEDIA DRIVERS FOR RENESAS - FDP1
 +M:	Kieran Bingham <kieran at bingham.xyz>
 +L:	linux-media at vger.kernel.org
 +L:	linux-renesas-soc at vger.kernel.org
 +T:	git git://linuxtv.org/media_tree.git
 +S:	Supported
 +F:	Documentation/devicetree/bindings/media/renesas,fdp1.txt
 +F:	drivers/media/platform/rcar_fdp1.c
 +
  MEDIA DRIVERS FOR RENESAS - VIN
  M:	Niklas Söderlund <niklas.soderlund at ragnatech.se>
  L:	linux-media at vger.kernel.org
@@@ -7862,24 -7845,6 +7867,24 @@@ L:	netdev at vger.kernel.or
  S:	Maintained
  F:	drivers/net/ethernet/mediatek/
  
 +MEDIATEK MEDIA DRIVER
 +M:	Tiffany Lin <tiffany.lin at mediatek.com>
 +M:	Andrew-CT Chen <andrew-ct.chen at mediatek.com>
 +S:	Supported
 +F:	drivers/media/platform/mtk-vcodec/
 +F:	drivers/media/platform/mtk-vpu/
 +F:	Documentation/devicetree/bindings/media/mediatek-vcodec.txt
 +F:	Documentation/devicetree/bindings/media/mediatek-vpu.txt
 +
 +MEDIATEK MDP DRIVER
 +M:	Minghsiu Tsai <minghsiu.tsai at mediatek.com>
 +M:	Houlong Wei <houlong.wei at mediatek.com>
 +M:	Andrew-CT Chen <andrew-ct.chen at mediatek.com>
 +S:	Supported
 +F:	drivers/media/platform/mtk-mdp/
 +F:	drivers/media/platform/mtk-vpu/
 +F:	Documentation/devicetree/bindings/media/mediatek-mdp.txt
 +
  MEDIATEK MT7601U WIRELESS LAN DRIVER
  M:	Jakub Kicinski <kubakici at wp.pl>
  L:	linux-wireless at vger.kernel.org
@@@ -7930,15 -7895,6 +7935,15 @@@ W:	http://www.mellanox.co
  Q:	http://patchwork.ozlabs.org/project/netdev/list/
  F:	drivers/net/ethernet/mellanox/mlxsw/
  
 +MELLANOX MLXCPLD I2C AND MUX DRIVER
 +M:	Vadim Pasternak <vadimp at mellanox.com>
 +M:	Michael Shych <michaelsh at mellanox.com>
 +L:	linux-i2c at vger.kernel.org
 +S:	Supported
 +F:	drivers/i2c/busses/i2c-mlxcpld.c
 +F:	drivers/i2c/muxes/i2c-mux-mlxcpld.c
 +F:	Documentation/i2c/busses/i2c-mlxcpld
 +
  MELLANOX MLXCPLD LED DRIVER
  M:	Vadim Pasternak <vadimp at mellanox.com>
  L:	linux-leds at vger.kernel.org
@@@ -8506,7 -8462,6 +8511,6 @@@ F:	include/uapi/linux/net_namespace.
  F:	tools/net/
  F:	tools/testing/selftests/net/
  F:	lib/random32.c
- F:	lib/test_bpf.c
  
  NETWORKING [IPv4/IPv6]
  M:	"David S. Miller" <davem at davemloft.net>
@@@ -9017,11 -8972,9 +9021,11 @@@ F:	drivers/of/resolver.
  
  OPENRISC ARCHITECTURE
  M:	Jonas Bonn <jonas at southpole.se>
 -W:	http://openrisc.net
 +M:	Stefan Kristiansson <stefan.kristiansson at saunalahti.fi>
 +M:	Stafford Horne <shorne at gmail.com>
 +L:	openrisc at lists.librecores.org
 +W:	http://openrisc.io
  S:	Maintained
 -T:	git git://openrisc.net/~jonas/linux
  F:	arch/openrisc/
  
  OPENVSWITCH
@@@ -9839,7 -9792,7 +9843,7 @@@ M:	Hans Verkuil <hverkuil at xs4all.nl
  L:	linux-media at vger.kernel.org
  T:	git git://linuxtv.org/media_tree.git
  S:	Maintained
 -F:	drivers/staging/media/pulse8-cec
 +F:	drivers/media/usb/pulse8-cec/*
  
  PVRUSB2 VIDEO4LINUX DRIVER
  M:	Mike Isely <isely at pobox.com>
@@@ -10464,7 -10417,7 +10468,7 @@@ F:	arch/s390/pci
  F:	drivers/pci/hotplug/s390_pci_hpc.c
  
  S390 ZCRYPT DRIVER
 -M:	Ingo Tuchscherer <ingo.tuchscherer at de.ibm.com>
 +M:	Harald Freudenberger <freude at de.ibm.com>
  L:	linux-s390 at vger.kernel.org
  W:	http://www.ibm.com/developerworks/linux/linux390/
  S:	Supported
@@@ -10659,12 -10612,6 +10663,12 @@@ S:	Maintaine
  F:	Documentation/devicetree/bindings/serial/
  F:	drivers/tty/serial/
  
 +SERIAL IR RECEIVER
 +M:	Sean Young <sean at mess.org>
 +L:	linux-media at vger.kernel.org
 +S:	Maintained
 +F:	drivers/media/rc/serial_ir.c
 +
  STI CEC DRIVER
  M:	Benjamin Gaignard <benjamin.gaignard at linaro.org>
  L:	kernel at stlinux.com
@@@ -11528,7 -11475,7 +11532,7 @@@ STABLE BRANC
  M:	Greg Kroah-Hartman <gregkh at linuxfoundation.org>
  L:	stable at vger.kernel.org
  S:	Supported
 -F:	Documentation/stable_kernel_rules.txt
 +F:	Documentation/process/stable-kernel-rules.rst
  
  STAGING SUBSYSTEM
  M:	Greg Kroah-Hartman <gregkh at linuxfoundation.org>
@@@ -11714,7 -11661,6 +11718,7 @@@ S:	Supporte
  F:	arch/arc/
  F:	Documentation/devicetree/bindings/arc/*
  F:	Documentation/devicetree/bindings/interrupt-controller/snps,arc*
 +F:	drivers/clocksource/arc_timer.c
  F:	drivers/tty/serial/arc_uart.c
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
  
@@@ -11975,16 -11921,6 +11979,16 @@@ S:	Maintaine
  F:	arch/xtensa/
  F:	drivers/irqchip/irq-xtensa-*
  
 +Texas Instruments' System Control Interface (TISCI) Protocol Driver
 +M:	Nishanth Menon <nm at ti.com>
 +M:	Tero Kristo <t-kristo at ti.com>
 +M:	Santosh Shilimkar <ssantosh at kernel.org>
 +L:	linux-arm-kernel at lists.infradead.org
 +S:	Maintained
 +F:	Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
 +F:	drivers/firmware/ti_sci*
 +F:	include/linux/soc/ti/ti_sci_protocol.h
 +
  THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
  M:	Hans Verkuil <hverkuil at xs4all.nl>
  L:	linux-media at vger.kernel.org
@@@ -12415,12 -12351,6 +12419,12 @@@ S:	Maintaine
  F:	Documentation/filesystems/udf.txt
  F:	fs/udf/
  
 +UDRAW TABLET
 +M:	Bastien Nocera <hadess at hadess.net>
 +L:	linux-input at vger.kernel.org
 +S:	Maintained
 +F:	drivers/hid/hid-udraw.c
 +
  UFS FILESYSTEM
  M:	Evgeniy Dushistov <dushistov at mail.ru>
  S:	Maintained
@@@ -12987,7 -12917,7 +12991,7 @@@ M:	Greg Kroah-Hartman <gregkh at linuxfoun
  L:	devel at driverdev.osuosl.org
  S:	Maintained
  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 -F:	Documentation/vme_api.txt
 +F:	Documentation/driver-api/vme.rst
  F:	drivers/staging/vme/
  F:	drivers/vme/
  F:	include/linux/vme*
@@@ -13211,7 -13141,7 +13215,7 @@@ T:	git git://git.kernel.org/pub/scm/lin
  S:	Maintained
  F:	include/linux/workqueue.h
  F:	kernel/workqueue.c
 -F:	Documentation/workqueue.txt
 +F:	Documentation/core-api/workqueue.rst
  
  X-POWERS MULTIFUNCTION PMIC DEVICE DRIVERS
  M:	Chen-Yu Tsai <wens at csie.org>
diff --combined arch/arm/boot/dts/dra72-evm-revc.dts
index 4ea2a0c,3b23b32..c3d939c
--- a/arch/arm/boot/dts/dra72-evm-revc.dts
+++ b/arch/arm/boot/dts/dra72-evm-revc.dts
@@@ -17,22 -17,17 +17,22 @@@
  	};
  };
  
 -&tps65917_regulators {
 -	ldo2_reg: ldo2 {
 -		/* LDO2_OUT --> VDDA_1V8_PHY2 */
 -		regulator-name = "ldo2";
 -		regulator-min-microvolt = <1800000>;
 -		regulator-max-microvolt = <1800000>;
 -		regulator-always-on;
 -		regulator-boot-on;
 +&i2c1 {
 +	tps65917: tps65917 at 58 {
 +		reg = <0x58>;
 +
 +		interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>;  /* IRQ_SYS_1N */
  	};
  };
  
 +#include "dra72-evm-tps65917.dtsi"
 +
 +&ldo2_reg {
 +	/* LDO2_OUT --> VDDA_1V8_PHY2 */
 +	regulator-always-on;
 +	regulator-boot-on;
 +};
 +
  &hdmi {
  	vdda-supply = <&ldo2_reg>;
  };
@@@ -64,15 -59,17 +64,17 @@@
  &davinci_mdio {
  	dp83867_0: ethernet-phy at 2 {
  		reg = <2>;
- 		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
- 		ti,tx-internal-delay = <DP83867_RGMIIDCTL_1_NS>;
+ 		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+ 		ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
  		ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
+ 		ti,min-output-impedance;
  	};
  
  	dp83867_1: ethernet-phy at 3 {
  		reg = <3>;
- 		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
- 		ti,tx-internal-delay = <DP83867_RGMIIDCTL_1_NS>;
+ 		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+ 		ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
  		ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
+ 		ti,min-output-imepdance;
  	};
  };
diff --combined arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
index fa19cfd,1552db0..7ea617e
--- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
@@@ -88,10 -88,16 +88,16 @@@
  
  			switch0: switch0 at 0 {
  				compatible = "marvell,mv88e6085";
+ 				pinctrl-0 = <&pinctrl_gpio_switch0>;
+ 				pinctrl-names = "default";
  				#address-cells = <1>;
  				#size-cells = <0>;
  				reg = <0>;
  				dsa,member = <0 0>;
+ 				interrupt-parent = <&gpio0>;
+ 				interrupts = <27 IRQ_TYPE_LEVEL_LOW>;
+ 				interrupt-controller;
+ 				#interrupt-cells = <2>;
  
  				ports {
  					#address-cells = <1>;
@@@ -99,16 -105,19 +105,19 @@@
  					port at 0 {
  						reg = <0>;
  						label = "lan0";
+ 						phy-handle = <&switch0phy0>;
  					};
  
  					port at 1 {
  						reg = <1>;
  						label = "lan1";
+ 						phy-handle = <&switch0phy1>;
  					};
  
  					port at 2 {
  						reg = <2>;
  						label = "lan2";
+ 						phy-handle = <&switch0phy2>;
  					};
  
  					switch0port5: port at 5 {
@@@ -133,6 -142,24 +142,24 @@@
  						};
  					};
  				};
+ 				mdio {
+ 					#address-cells = <1>;
+ 					#size-cells = <0>;
+ 					switch0phy0: switch0phy0 at 0 {
+ 						reg = <0>;
+ 						interrupt-parent = <&switch0>;
+ 						interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+ 					};
+ 					switch0phy1: switch1phy0 at 1 {
+ 						reg = <1>;
+ 						interrupt-parent = <&switch0>;
+ 						interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;					};
+ 					switch0phy2: switch1phy0 at 2 {
+ 						reg = <2>;
+ 						interrupt-parent = <&switch0>;
+ 						interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+ 					};
+ 				};
  			};
  		};
  
@@@ -143,10 -170,16 +170,16 @@@
  
  			switch1: switch1 at 0 {
  				compatible = "marvell,mv88e6085";
+ 				pinctrl-0 = <&pinctrl_gpio_switch1>;
+ 				pinctrl-names = "default";
  				#address-cells = <1>;
  				#size-cells = <0>;
  				reg = <0>;
  				dsa,member = <0 1>;
+ 				interrupt-parent = <&gpio0>;
+ 				interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+ 				interrupt-controller;
+ 				#interrupt-cells = <2>;
  
  				ports {
  					#address-cells = <1>;
@@@ -196,12 -229,18 +229,18 @@@
  					#size-cells = <0>;
  					switch1phy0: switch1phy0 at 0 {
  						reg = <0>;
+ 						interrupt-parent = <&switch1>;
+ 						interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
  					};
  					switch1phy1: switch1phy0 at 1 {
  						reg = <1>;
+ 						interrupt-parent = <&switch1>;
+ 						interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
  					};
  					switch1phy2: switch1phy0 at 2 {
  						reg = <2>;
+ 						interrupt-parent = <&switch1>;
+ 						interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
  					};
  				};
  			};
@@@ -499,6 -538,13 +538,6 @@@
  	};
  };
  
 -&i2c3 {
 -	clock-frequency = <100000>;
 -	pinctrl-names = "default";
 -	pinctrl-0 = <&pinctrl_i2c3>;
 -	status = "okay";
 -};
 -
  &uart0 {
  	pinctrl-names = "default";
  	pinctrl-0 = <&pinctrl_uart0>;
@@@ -629,6 -675,18 +668,18 @@@
  		>;
  	};
  
+ 	pinctrl_gpio_switch0: pinctrl-gpio-switch0 {
+ 		fsl,pins = <
+ 			VF610_PAD_PTB5__GPIO_27		0x219d
+ 		>;
+ 	};
+ 
+ 	pinctrl_gpio_switch1: pinctrl-gpio-switch1 {
+ 		fsl,pins = <
+ 			VF610_PAD_PTB4__GPIO_26		0x219d
+ 		>;
+ 	};
+ 
  	pinctrl_i2c_mux_reset: pinctrl-i2c-mux-reset {
  		fsl,pins = <
  			 VF610_PAD_PTE14__GPIO_119	0x31c2
@@@ -656,6 -714,13 +707,6 @@@
  		>;
  	};
  
 -	pinctrl_i2c3: i2c3grp {
 -		fsl,pins = <
 -			VF610_PAD_PTA30__I2C3_SCL	0x37ff
 -			VF610_PAD_PTA31__I2C3_SDA	0x37ff
 -		>;
 -	};
 -
  	pinctrl_leds_debug: pinctrl-leds-debug {
  		fsl,pins = <
  			 VF610_PAD_PTD20__GPIO_74	0x31c2
diff --combined arch/arm64/boot/dts/broadcom/ns2-svk.dts
index 3461907,c4d5442..de8d379
--- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
@@@ -56,6 -56,10 +56,10 @@@
  	};
  };
  
+ &enet {
+ 	status = "ok";
+ };
+ 
  &pci_phy0 {
  	status = "ok";
  };
@@@ -157,10 -161,6 +161,10 @@@
  	status = "ok";
  };
  
 +&sdio1 {
 +	status = "ok";
 +};
 +
  &nand {
  	nandcs at 0 {
  		compatible = "brcm,nandcs";
@@@ -178,6 -178,7 +182,7 @@@
  &mdio_mux_iproc {
  	mdio at 10 {
  		gphy0: eth-phy at 10 {
+ 			enet-phy-lane-swap;
  			reg = <0x10>;
  		};
  	};
@@@ -191,37 -192,3 +196,37 @@@
  		groups = "nand_grp";
  	};
  };
 +
 +&qspi {
 +	bspi-sel = <0>;
 +	flash: m25p80 at 0 {
 +		#address-cells = <1>;
 +		#size-cells = <1>;
 +		compatible = "m25p80";
 +		reg = <0x0>;
 +		spi-max-frequency = <12500000>;
 +		m25p,fast-read;
 +		spi-cpol;
 +		spi-cpha;
 +
 +		partition at 0 {
 +			label = "boot";
 +			reg = <0x00000000 0x000a0000>;
 +		};
 +
 +		partition at a0000 {
 +			label = "env";
 +			reg = <0x000a0000 0x00060000>;
 +		};
 +
 +		partition at 100000 {
 +			label = "system";
 +			reg = <0x00100000 0x00600000>;
 +		};
 +
 +		partition at 700000 {
 +			label = "rootfs";
 +			reg = <0x00700000 0x01900000>;
 +		};
 +	};
 +};
diff --combined arch/arm64/boot/dts/broadcom/ns2.dtsi
index 863503d,773ed59..07704b5
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@@ -133,9 -133,6 +133,9 @@@
  
  		status = "disabled";
  
 +		phys = <&pci_phy0>;
 +		phy-names = "pcie-phy";
 +
  		msi-parent = <&msi0>;
  		msi0: msi at 20020000 {
  			compatible = "brcm,iproc-msi";
@@@ -174,9 -171,6 +174,9 @@@
  
  		status = "disabled";
  
 +		phys = <&pci_phy1>;
 +		phy-names = "pcie-phy";
 +
  		msi-parent = <&msi4>;
  		msi4: msi at 50020000 {
  			compatible = "brcm,iproc-msi";
@@@ -197,42 -191,18 +197,54 @@@
  
  		#include "ns2-clock.dtsi"
  
 +		pdc0: iproc-pdc0 at 612c0000 {
 +			compatible = "brcm,iproc-pdc-mbox";
 +			reg = <0x612c0000 0x445>;  /* PDC FS0 regs */
 +			interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
 +			#mbox-cells = <1>;
 +			brcm,rx-status-len = <32>;
 +			brcm,use-bcm-hdr;
 +		};
 +
 +		pdc1: iproc-pdc1 at 612e0000 {
 +			compatible = "brcm,iproc-pdc-mbox";
 +			reg = <0x612e0000 0x445>;  /* PDC FS1 regs */
 +			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
 +			#mbox-cells = <1>;
 +			brcm,rx-status-len = <32>;
 +			brcm,use-bcm-hdr;
 +		};
 +
 +		pdc2: iproc-pdc2 at 61300000 {
 +			compatible = "brcm,iproc-pdc-mbox";
 +			reg = <0x61300000 0x445>;  /* PDC FS2 regs */
 +			interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
 +			#mbox-cells = <1>;
 +			brcm,rx-status-len = <32>;
 +			brcm,use-bcm-hdr;
 +		};
 +
 +		pdc3: iproc-pdc3 at 61320000 {
 +			compatible = "brcm,iproc-pdc-mbox";
 +			reg = <0x61320000 0x445>;  /* PDC FS3 regs */
 +			interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>;
 +			#mbox-cells = <1>;
 +			brcm,rx-status-len = <32>;
 +			brcm,use-bcm-hdr;
 +		};
 +
+ 		enet: ethernet at 61000000 {
+ 			compatible = "brcm,ns2-amac";
+ 			reg = <0x61000000 0x1000>,
+ 			      <0x61090000 0x1000>,
+ 			      <0x61030000 0x100>;
+ 			reg-names = "amac_base", "idm_base", "nicpm_base";
+ 			interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
+ 			phy-handle = <&gphy0>;
+ 			phy-mode = "rgmii";
+ 			status = "disabled";
+ 		};
+ 
  		dma0: dma at 61360000 {
  			compatible = "arm,pl330", "arm,primecell";
  			reg = <0x61360000 0x1000>;
@@@ -290,7 -260,7 +302,7 @@@
  				     <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
  				     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
  				     <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
 -			mmu-masters;
 +			#iommu-cells = <1>;
  		};
  
  		pinctrl: pinctrl at 6501d130 {
@@@ -607,23 -577,5 +619,23 @@@
  
  			brcm,nand-has-wp;
  		};
 +
 +		qspi: spi at 66470200 {
 +			compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
 +			reg = <0x66470200 0x184>,
 +				<0x66470000 0x124>,
 +				<0x67017408 0x004>,
 +				<0x664703a0 0x01c>;
 +			reg-names = "mspi", "bspi", "intr_regs",
 +				"intr_status_reg";
 +			interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>;
 +			interrupt-names = "spi_l1_intr";
 +			clocks = <&iprocmed>;
 +			clock-names = "iprocmed";
 +			num-cs = <2>;
 +			#address-cells = <1>;
 +			#size-cells = <0>;
 +		};
 +
  	};
  };
diff --combined arch/arm64/boot/dts/marvell/armada-3720-db.dts
index a260ae2,a59d36c..89de0a7
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@@ -56,7 -56,7 +56,7 @@@
  		stdout-path = "serial0:115200n8";
  	};
  
 -	memory {
 +	memory at 0 {
  		device_type = "memory";
  		reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
  	};
@@@ -81,3 -81,26 +81,26 @@@
  &pcie0 {
  	status = "okay";
  };
+ 
+ &mdio {
+ 	status = "okay";
+ 	phy0: ethernet-phy at 0 {
+ 		reg = <0>;
+ 	};
+ 
+ 	phy1: ethernet-phy at 1 {
+ 		reg = <1>;
+ 	};
+ };
+ 
+ &eth0 {
+ 	phy-mode = "rgmii-id";
+ 	phy = <&phy0>;
+ 	status = "okay";
+ };
+ 
+ &eth1 {
+ 	phy-mode = "sgmii";
+ 	phy = <&phy1>;
+ 	status = "okay";
+ };
diff --combined arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index eba2e38,3b8eb45..bab5c6f
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@@ -91,7 -91,7 +91,7 @@@
  		#size-cells = <2>;
  		ranges;
  
 -		internal-regs {
 +		internal-regs at d0000000 {
  			#address-cells = <1>;
  			#size-cells = <1>;
  			compatible = "simple-bus";
@@@ -140,6 -140,29 +140,29 @@@
  				};
  			};
  
+ 			eth0: ethernet at 30000 {
+ 				   compatible = "marvell,armada-3700-neta";
+ 				   reg = <0x30000 0x4000>;
+ 				   interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ 				   clocks = <&sb_periph_clk 8>;
+ 				   status = "disabled";
+ 			};
+ 
+ 			mdio: mdio at 32004 {
+ 				#address-cells = <1>;
+ 				#size-cells = <0>;
+ 				compatible = "marvell,orion-mdio";
+ 				reg = <0x32004 0x4>;
+ 			};
+ 
+ 			eth1: ethernet at 40000 {
+ 				compatible = "marvell,armada-3700-neta";
+ 				reg = <0x40000 0x4000>;
+ 				interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ 				clocks = <&sb_periph_clk 7>;
+ 				status = "disabled";
+ 			};
+ 
  			usb3: usb at 58000 {
  				compatible = "marvell,armada3700-xhci",
  				"generic-xhci";
diff --combined arch/arm64/configs/defconfig
index 0bba32a,6be0811..869dded
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@@ -11,6 -11,7 +11,6 @@@ CONFIG_TASK_XACCT=
  CONFIG_TASK_IO_ACCOUNTING=y
  CONFIG_IKCONFIG=y
  CONFIG_IKCONFIG_PROC=y
 -CONFIG_LOG_BUF_SHIFT=14
  CONFIG_MEMCG=y
  CONFIG_MEMCG_SWAP=y
  CONFIG_BLK_CGROUP=y
@@@ -33,7 -34,6 +33,7 @@@ CONFIG_MODULE_UNLOAD=
  # CONFIG_IOSCHED_DEADLINE is not set
  CONFIG_ARCH_SUNXI=y
  CONFIG_ARCH_ALPINE=y
 +CONFIG_ARCH_BCM2835=y
  CONFIG_ARCH_BCM_IPROC=y
  CONFIG_ARCH_BERLIN=y
  CONFIG_ARCH_EXYNOS=y
@@@ -82,7 -82,6 +82,7 @@@ CONFIG_KEXEC=
  # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
  CONFIG_COMPAT=y
  CONFIG_CPU_IDLE=y
 +CONFIG_HIBERNATION=y
  CONFIG_ARM_CPUIDLE=y
  CONFIG_CPU_FREQ=y
  CONFIG_CPUFREQ_DT=y
@@@ -148,7 -147,6 +148,7 @@@ CONFIG_MTD_SPI_NOR=
  CONFIG_BLK_DEV_LOOP=y
  CONFIG_BLK_DEV_NBD=m
  CONFIG_VIRTIO_BLK=y
 +CONFIG_EEPROM_AT25=m
  CONFIG_SRAM=y
  # CONFIG_SCSI_PROC_FS is not set
  CONFIG_BLK_DEV_SD=y
@@@ -185,10 -183,7 +185,10 @@@ CONFIG_SMC91X=
  CONFIG_SMSC911X=y
  CONFIG_STMMAC_ETH=m
  CONFIG_REALTEK_PHY=m
 +CONFIG_MESON_GXL_PHY=m
  CONFIG_MICREL_PHY=y
 +CONFIG_MDIO_BUS_MUX=y
 +CONFIG_MDIO_BUS_MUX_MMIOREG=y
  CONFIG_USB_PEGASUS=m
  CONFIG_USB_RTL8150=m
  CONFIG_USB_RTL8152=m
@@@ -199,7 -194,6 +199,7 @@@ CONFIG_USB_NET_SMSC75XX=
  CONFIG_USB_NET_SMSC95XX=m
  CONFIG_USB_NET_PLUSB=m
  CONFIG_USB_NET_MCS7830=m
 +CONFIG_BRCMFMAC=m
  CONFIG_WL18XX=m
  CONFIG_WLCORE_SDIO=m
  CONFIG_INPUT_EVDEV=y
@@@ -212,9 -206,6 +212,9 @@@ CONFIG_SERIO_AMBAKMI=
  CONFIG_LEGACY_PTY_COUNT=16
  CONFIG_SERIAL_8250=y
  CONFIG_SERIAL_8250_CONSOLE=y
 +CONFIG_SERIAL_8250_EXTENDED=y
 +CONFIG_SERIAL_8250_SHARE_IRQ=y
 +CONFIG_SERIAL_8250_BCM2835AUX=y
  CONFIG_SERIAL_8250_DW=y
  CONFIG_SERIAL_8250_MT6577=y
  CONFIG_SERIAL_8250_UNIPHIER=y
@@@ -238,21 -229,17 +238,21 @@@ CONFIG_VIRTIO_CONSOLE=
  CONFIG_I2C_CHARDEV=y
  CONFIG_I2C_MUX=y
  CONFIG_I2C_MUX_PCA954x=y
 +CONFIG_I2C_BCM2835=m
  CONFIG_I2C_DESIGNWARE_PLATFORM=y
  CONFIG_I2C_IMX=y
  CONFIG_I2C_MESON=y
  CONFIG_I2C_MV64XXX=y
  CONFIG_I2C_QUP=y
 +CONFIG_I2C_RK3X=y
  CONFIG_I2C_TEGRA=y
  CONFIG_I2C_UNIPHIER_F=y
  CONFIG_I2C_RCAR=y
  CONFIG_I2C_CROS_EC_TUNNEL=y
  CONFIG_SPI=y
  CONFIG_SPI_MESON_SPIFC=m
 +CONFIG_SPI_BCM2835=m
 +CONFIG_SPI_BCM2835AUX=m
  CONFIG_SPI_ORION=y
  CONFIG_SPI_PL022=y
  CONFIG_SPI_QUP=y
@@@ -262,14 -249,15 +262,15 @@@ CONFIG_SPMI=
  CONFIG_PINCTRL_SINGLE=y
  CONFIG_PINCTRL_MAX77620=y
  CONFIG_PINCTRL_MSM8916=y
 +CONFIG_PINCTRL_MSM8994=y
  CONFIG_PINCTRL_MSM8996=y
  CONFIG_PINCTRL_QDF2XXX=y
  CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 -CONFIG_GPIO_SYSFS=y
  CONFIG_GPIO_DWAPB=y
  CONFIG_GPIO_PL061=y
  CONFIG_GPIO_RCAR=y
  CONFIG_GPIO_XGENE=y
+ CONFIG_GPIO_XGENE_SB=y
  CONFIG_GPIO_PCA953X=y
  CONFIG_GPIO_PCA953X_IRQ=y
  CONFIG_GPIO_MAX77620=y
@@@ -284,16 -272,13 +285,16 @@@ CONFIG_THERMAL=
  CONFIG_THERMAL_EMULATION=y
  CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
  CONFIG_CPU_THERMAL=y
 +CONFIG_BCM2835_THERMAL=y
  CONFIG_EXYNOS_THERMAL=y
  CONFIG_WATCHDOG=y
 +CONFIG_BCM2835_WDT=y
  CONFIG_RENESAS_WDT=y
  CONFIG_S3C2410_WATCHDOG=y
  CONFIG_MESON_GXBB_WATCHDOG=m
  CONFIG_MESON_WATCHDOG=m
  CONFIG_MFD_MAX77620=y
 +CONFIG_MFD_RK808=y
  CONFIG_MFD_SPMI_PMIC=y
  CONFIG_MFD_SEC_CORE=y
  CONFIG_MFD_HI655X_PMIC=y
@@@ -307,26 -292,10 +308,26 @@@ CONFIG_REGULATOR_MAX77620=
  CONFIG_REGULATOR_PWM=y
  CONFIG_REGULATOR_QCOM_SMD_RPM=y
  CONFIG_REGULATOR_QCOM_SPMI=y
 +CONFIG_REGULATOR_RK808=y
  CONFIG_REGULATOR_S2MPS11=y
 +CONFIG_MEDIA_SUPPORT=m
 +CONFIG_MEDIA_CAMERA_SUPPORT=y
 +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
 +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
 +CONFIG_MEDIA_CONTROLLER=y
 +CONFIG_VIDEO_V4L2_SUBDEV_API=y
 +# CONFIG_DVB_NET is not set
 +CONFIG_V4L_MEM2MEM_DRIVERS=y
 +CONFIG_VIDEO_RENESAS_FCP=m
 +CONFIG_VIDEO_RENESAS_VSP1=m
  CONFIG_DRM=m
  CONFIG_DRM_NOUVEAU=m
 +CONFIG_DRM_RCAR_DU=m
 +CONFIG_DRM_RCAR_HDMI=y
 +CONFIG_DRM_RCAR_LVDS=y
 +CONFIG_DRM_RCAR_VSP=y
  CONFIG_DRM_TEGRA=m
 +CONFIG_DRM_VC4=m
  CONFIG_DRM_PANEL_SIMPLE=m
  CONFIG_DRM_I2C_ADV7511=m
  CONFIG_DRM_HISI_KIRIN=m
@@@ -341,7 -310,6 +342,7 @@@ CONFIG_LOGO=
  CONFIG_SOUND=y
  CONFIG_SND=y
  CONFIG_SND_SOC=y
 +CONFIG_SND_BCM2835_SOC_I2S=m
  CONFIG_SND_SOC_RCAR=y
  CONFIG_SND_SOC_SAMSUNG=y
  CONFIG_SND_SOC_AK4613=y
@@@ -374,11 -342,9 +375,11 @@@ CONFIG_USB_RENESAS_USBHS_UDC=
  CONFIG_MMC=y
  CONFIG_MMC_BLOCK_MINORS=32
  CONFIG_MMC_ARMMMCI=y
 +CONFIG_MMC_MESON_GX=y
  CONFIG_MMC_SDHCI=y
  CONFIG_MMC_SDHCI_ACPI=y
  CONFIG_MMC_SDHCI_PLTFM=y
 +CONFIG_MMC_SDHCI_OF_ARASAN=y
  CONFIG_MMC_SDHCI_OF_ESDHC=y
  CONFIG_MMC_SDHCI_TEGRA=y
  CONFIG_MMC_SDHCI_MSM=y
@@@ -387,7 -353,6 +388,7 @@@ CONFIG_MMC_SDHI=
  CONFIG_MMC_DW=y
  CONFIG_MMC_DW_EXYNOS=y
  CONFIG_MMC_DW_K3=y
 +CONFIG_MMC_DW_ROCKCHIP=y
  CONFIG_MMC_SUNXI=y
  CONFIG_NEW_LEDS=y
  CONFIG_LEDS_CLASS=y
@@@ -403,13 -368,11 +404,13 @@@ CONFIG_RTC_DRV_DS3232=
  CONFIG_RTC_DRV_EFI=y
  CONFIG_RTC_DRV_PL031=y
  CONFIG_RTC_DRV_SUN6I=y
 +CONFIG_RTC_DRV_RK808=m
  CONFIG_RTC_DRV_TEGRA=y
  CONFIG_RTC_DRV_XGENE=y
  CONFIG_RTC_DRV_S3C=y
  CONFIG_DMADEVICES=y
  CONFIG_PL330_DMA=y
 +CONFIG_DMA_BCM2835=m
  CONFIG_TEGRA20_APB_DMA=y
  CONFIG_QCOM_BAM_DMA=y
  CONFIG_QCOM_HIDMA_MGMT=y
@@@ -425,39 -388,26 +426,39 @@@ CONFIG_XEN_GRANT_DEV_ALLOC=
  CONFIG_COMMON_CLK_SCPI=y
  CONFIG_COMMON_CLK_CS2000_CP=y
  CONFIG_COMMON_CLK_S2MPS11=y
 +CONFIG_COMMON_CLK_PWM=y
 +CONFIG_COMMON_CLK_RK808=y
  CONFIG_CLK_QORIQ=y
  CONFIG_COMMON_CLK_QCOM=y
  CONFIG_MSM_GCC_8916=y
 +CONFIG_MSM_GCC_8994=y
  CONFIG_MSM_MMCC_8996=y
  CONFIG_HWSPINLOCK_QCOM=y
  CONFIG_MAILBOX=y
  CONFIG_ARM_MHU=y
 +CONFIG_PLATFORM_MHU=y
 +CONFIG_BCM2835_MBOX=y
  CONFIG_HI6220_MBOX=y
  CONFIG_ARM_SMMU=y
 +CONFIG_RASPBERRYPI_POWER=y
  CONFIG_QCOM_SMEM=y
  CONFIG_QCOM_SMD=y
  CONFIG_QCOM_SMD_RPM=y
 +CONFIG_ROCKCHIP_PM_DOMAINS=y
  CONFIG_ARCH_TEGRA_132_SOC=y
  CONFIG_ARCH_TEGRA_210_SOC=y
 +CONFIG_ARCH_TEGRA_186_SOC=y
  CONFIG_EXTCON_USB_GPIO=y
  CONFIG_PWM=y
 +CONFIG_PWM_BCM2835=m
 +CONFIG_PWM_ROCKCHIP=y
  CONFIG_PWM_TEGRA=m
 +CONFIG_PWM_MESON=m
  CONFIG_COMMON_RESET_HI6220=y
  CONFIG_PHY_RCAR_GEN3_USB2=y
  CONFIG_PHY_HI6220_USB=y
 +CONFIG_PHY_ROCKCHIP_INNO_USB2=y
 +CONFIG_PHY_ROCKCHIP_EMMC=y
  CONFIG_PHY_XGENE=y
  CONFIG_PHY_TEGRA_XUSB=y
  CONFIG_ARM_SCPI_PROTOCOL=y
@@@ -465,7 -415,6 +466,7 @@@ CONFIG_ACPI=
  CONFIG_IIO=y
  CONFIG_EXYNOS_ADC=y
  CONFIG_PWM_SAMSUNG=y
 +CONFIG_RASPBERRYPI_FIRMWARE=y
  CONFIG_EXT2_FS=y
  CONFIG_EXT3_FS=y
  CONFIG_EXT4_FS_POSIX_ACL=y
diff --combined drivers/media/dvb-core/dvb_net.c
index bd833b0,0da622f..dfc03a9
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@@ -54,8 -54,6 +54,8 @@@
   *
   */
  
 +#define pr_fmt(fmt) "dvb_net: " fmt
 +
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
@@@ -311,589 -309,451 +311,589 @@@ static inline void reset_ule( struct dv
   * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
   * TS cells of a single PID.
   */
 -static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
 -{
 -	struct dvb_net_priv *priv = netdev_priv(dev);
 -	unsigned long skipped = 0L;
 -	const u8 *ts, *ts_end, *from_where = NULL;
 -	u8 ts_remain = 0, how_much = 0, new_ts = 1;
 -	struct ethhdr *ethh = NULL;
 -	bool error = false;
  
 +struct dvb_net_ule_handle {
 +	struct net_device *dev;
 +	struct dvb_net_priv *priv;
 +	struct ethhdr *ethh;
 +	const u8 *buf;
 +	size_t buf_len;
 +	unsigned long skipped;
 +	const u8 *ts, *ts_end, *from_where;
 +	u8 ts_remain, how_much, new_ts;
 +	bool error;
  #ifdef ULE_DEBUG
 -	/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
 +	/*
 +	 * The code inside ULE_DEBUG keeps a history of the
 +	 * last 100 TS cells processed.
 +	 */
  	static unsigned char ule_hist[100*TS_SZ];
  	static unsigned char *ule_where = ule_hist, ule_dump;
  #endif
 +};
  
 -	/* For all TS cells in current buffer.
 -	 * Appearently, we are called for every single TS cell.
 -	 */
 -	for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
 -
 -		if (new_ts) {
 -			/* We are about to process a new TS cell. */
 +static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h)
 +{
 +	/* We are about to process a new TS cell. */
  
  #ifdef ULE_DEBUG
 -			if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;
 -			memcpy( ule_where, ts, TS_SZ );
 -			if (ule_dump) {
 -				hexdump( ule_where, TS_SZ );
 -				ule_dump = 0;
 -			}
 -			ule_where += TS_SZ;
 +	if (h->ule_where >= &h->ule_hist[100*TS_SZ])
 +		h->ule_where = h->ule_hist;
 +	memcpy(h->ule_where, h->ts, TS_SZ);
 +	if (h->ule_dump) {
 +		hexdump(h->ule_where, TS_SZ);
 +		h->ule_dump = 0;
 +	}
 +	h->ule_where += TS_SZ;
  #endif
  
 -			/* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
 -			if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
 -				printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
 -				       priv->ts_count, ts[0],
 -				       (ts[1] & TS_TEI) >> 7,
 -				       (ts[3] & TS_SC) >> 6);
 -
 -				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 -				if (priv->ule_skb) {
 -					dev_kfree_skb( priv->ule_skb );
 -					/* Prepare for next SNDU. */
 -					dev->stats.rx_errors++;
 -					dev->stats.rx_frame_errors++;
 -				}
 -				reset_ule(priv);
 -				priv->need_pusi = 1;
 +	/*
 +	 * Check TS h->error conditions: sync_byte, transport_error_indicator,
 +	 * scrambling_control .
 +	 */
 +	if ((h->ts[0] != TS_SYNC) || (h->ts[1] & TS_TEI) ||
 +	    ((h->ts[3] & TS_SC) != 0)) {
 +		pr_warn("%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
 +			h->priv->ts_count, h->ts[0],
 +			(h->ts[1] & TS_TEI) >> 7,
 +			(h->ts[3] & TS_SC) >> 6);
 +
 +		/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 +		if (h->priv->ule_skb) {
 +			dev_kfree_skb(h->priv->ule_skb);
 +			/* Prepare for next SNDU. */
 +			h->dev->stats.rx_errors++;
 +			h->dev->stats.rx_frame_errors++;
 +		}
 +		reset_ule(h->priv);
 +		h->priv->need_pusi = 1;
  
 -				/* Continue with next TS cell. */
 -				ts += TS_SZ;
 -				priv->ts_count++;
 -				continue;
 -			}
 +		/* Continue with next TS cell. */
 +		h->ts += TS_SZ;
 +		h->priv->ts_count++;
 +		return 1;
 +	}
 +
 +	h->ts_remain = 184;
 +	h->from_where = h->ts + 4;
  
 -			ts_remain = 184;
 -			from_where = ts + 4;
 +	return 0;
 +}
 +
 +static int dvb_net_ule_ts_pusi(struct dvb_net_ule_handle *h)
 +{
 +	if (h->ts[1] & TS_PUSI) {
 +		/* Find beginning of first ULE SNDU in current TS cell. */
 +		/* Synchronize continuity counter. */
 +		h->priv->tscc = h->ts[3] & 0x0F;
 +		/* There is a pointer field here. */
 +		if (h->ts[4] > h->ts_remain) {
 +			pr_err("%lu: Invalid ULE packet (pointer field %d)\n",
 +				h->priv->ts_count, h->ts[4]);
 +			h->ts += TS_SZ;
 +			h->priv->ts_count++;
 +			return 1;
  		}
 -		/* Synchronize on PUSI, if required. */
 -		if (priv->need_pusi) {
 -			if (ts[1] & TS_PUSI) {
 -				/* Find beginning of first ULE SNDU in current TS cell. */
 -				/* Synchronize continuity counter. */
 -				priv->tscc = ts[3] & 0x0F;
 -				/* There is a pointer field here. */
 -				if (ts[4] > ts_remain) {
 -					printk(KERN_ERR "%lu: Invalid ULE packet "
 -					       "(pointer field %d)\n", priv->ts_count, ts[4]);
 -					ts += TS_SZ;
 -					priv->ts_count++;
 -					continue;
 -				}
 -				/* Skip to destination of pointer field. */
 -				from_where = &ts[5] + ts[4];
 -				ts_remain -= 1 + ts[4];
 -				skipped = 0;
 -			} else {
 -				skipped++;
 -				ts += TS_SZ;
 -				priv->ts_count++;
 -				continue;
 -			}
 +		/* Skip to destination of pointer field. */
 +		h->from_where = &h->ts[5] + h->ts[4];
 +		h->ts_remain -= 1 + h->ts[4];
 +		h->skipped = 0;
 +	} else {
 +		h->skipped++;
 +		h->ts += TS_SZ;
 +		h->priv->ts_count++;
 +		return 1;
 +	}
 +
 +	return 0;
 +}
 +
 +static int dvb_net_ule_new_ts(struct dvb_net_ule_handle *h)
 +{
 +	/* Check continuity counter. */
 +	if ((h->ts[3] & 0x0F) == h->priv->tscc)
 +		h->priv->tscc = (h->priv->tscc + 1) & 0x0F;
 +	else {
 +		/* TS discontinuity handling: */
 +		pr_warn("%lu: TS discontinuity: got %#x, expected %#x.\n",
 +			h->priv->ts_count, h->ts[3] & 0x0F,
 +			h->priv->tscc);
 +		/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 +		if (h->priv->ule_skb) {
 +			dev_kfree_skb(h->priv->ule_skb);
 +			/* Prepare for next SNDU. */
 +			// reset_ule(h->priv);  moved to below.
 +			h->dev->stats.rx_errors++;
 +			h->dev->stats.rx_frame_errors++;
  		}
 +		reset_ule(h->priv);
 +		/* skip to next PUSI. */
 +		h->priv->need_pusi = 1;
 +		return 1;
 +	}
 +	/*
 +	 * If we still have an incomplete payload, but PUSI is
 +	 * set; some TS cells are missing.
 +	 * This is only possible here, if we missed exactly 16 TS
 +	 * cells (continuity counter wrap).
 +	 */
 +	if (h->ts[1] & TS_PUSI) {
 +		if (!h->priv->need_pusi) {
 +			if (!(*h->from_where < (h->ts_remain-1)) ||
 +			    *h->from_where != h->priv->ule_sndu_remain) {
 +				/*
 +				 * Pointer field is invalid.
 +				 * Drop this TS cell and any started ULE SNDU.
 +				 */
 +				pr_warn("%lu: Invalid pointer field: %u.\n",
 +					h->priv->ts_count,
 +					*h->from_where);
  
 -		if (new_ts) {
 -			/* Check continuity counter. */
 -			if ((ts[3] & 0x0F) == priv->tscc)
 -				priv->tscc = (priv->tscc + 1) & 0x0F;
 -			else {
 -				/* TS discontinuity handling: */
 -				printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
 -				       "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
 -				/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 -				if (priv->ule_skb) {
 -					dev_kfree_skb( priv->ule_skb );
 -					/* Prepare for next SNDU. */
 -					// reset_ule(priv);  moved to below.
 -					dev->stats.rx_errors++;
 -					dev->stats.rx_frame_errors++;
 +				/*
 +				 * Drop partly decoded SNDU, reset state,
 +				 * resync on PUSI.
 +				 */
 +				if (h->priv->ule_skb) {
 +					h->error = true;
 +					dev_kfree_skb(h->priv->ule_skb);
  				}
 -				reset_ule(priv);
 -				/* skip to next PUSI. */
 -				priv->need_pusi = 1;
 -				continue;
 -			}
 -			/* If we still have an incomplete payload, but PUSI is
 -			 * set; some TS cells are missing.
 -			 * This is only possible here, if we missed exactly 16 TS
 -			 * cells (continuity counter wrap). */
 -			if (ts[1] & TS_PUSI) {
 -				if (! priv->need_pusi) {
 -					if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
 -						/* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
 -						printk(KERN_WARNING "%lu: Invalid pointer "
 -						       "field: %u.\n", priv->ts_count, *from_where);
 -
 -						/* Drop partly decoded SNDU, reset state, resync on PUSI. */
 -						if (priv->ule_skb) {
 -							error = true;
 -							dev_kfree_skb(priv->ule_skb);
 -						}
 -
 -						if (error || priv->ule_sndu_remain) {
 -							dev->stats.rx_errors++;
 -							dev->stats.rx_frame_errors++;
 -							error = false;
 -						}
 -
 -						reset_ule(priv);
 -						priv->need_pusi = 1;
 -						continue;
 -					}
 -					/* Skip pointer field (we're processing a
 -					 * packed payload). */
 -					from_where += 1;
 -					ts_remain -= 1;
 -				} else
 -					priv->need_pusi = 0;
 -
 -				if (priv->ule_sndu_remain > 183) {
 -					/* Current SNDU lacks more data than there could be available in the
 -					 * current TS cell. */
 -					dev->stats.rx_errors++;
 -					dev->stats.rx_length_errors++;
 -					printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
 -					       "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
 -					       priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
 -					dev_kfree_skb(priv->ule_skb);
 -					/* Prepare for next SNDU. */
 -					reset_ule(priv);
 -					/* Resync: go to where pointer field points to: start of next ULE SNDU. */
 -					from_where += ts[4];
 -					ts_remain -= ts[4];
 +
 +				if (h->error || h->priv->ule_sndu_remain) {
 +					h->dev->stats.rx_errors++;
 +					h->dev->stats.rx_frame_errors++;
 +					h->error = false;
  				}
 +
 +				reset_ule(h->priv);
 +				h->priv->need_pusi = 1;
 +				return 1;
  			}
 +			/*
 +			 * Skip pointer field (we're processing a
 +			 * packed payload).
 +			 */
 +			h->from_where += 1;
 +			h->ts_remain -= 1;
 +		} else
 +			h->priv->need_pusi = 0;
 +
 +		if (h->priv->ule_sndu_remain > 183) {
 +			/*
 +			 * Current SNDU lacks more data than there
 +			 * could be available in the current TS cell.
 +			 */
 +			h->dev->stats.rx_errors++;
 +			h->dev->stats.rx_length_errors++;
 +			pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, h->ts_remain %d).  Flushing incomplete payload.\n",
 +				h->priv->ts_count,
 +				h->priv->ule_sndu_remain,
 +				h->ts[4], h->ts_remain);
 +			dev_kfree_skb(h->priv->ule_skb);
 +			/* Prepare for next SNDU. */
 +			reset_ule(h->priv);
 +			/*
 +			 * Resync: go to where pointer field points to:
 +			 * start of next ULE SNDU.
 +			 */
 +			h->from_where += h->ts[4];
 +			h->ts_remain -= h->ts[4];
  		}
 +	}
 +	return 0;
 +}
  
 -		/* Check if new payload needs to be started. */
 -		if (priv->ule_skb == NULL) {
 -			/* Start a new payload with skb.
 -			 * Find ULE header.  It is only guaranteed that the
 -			 * length field (2 bytes) is contained in the current
 -			 * TS.
 -			 * Check ts_remain has to be >= 2 here. */
 -			if (ts_remain < 2) {
 -				printk(KERN_WARNING "Invalid payload packing: only %d "
 -				       "bytes left in TS.  Resyncing.\n", ts_remain);
 -				priv->ule_sndu_len = 0;
 -				priv->need_pusi = 1;
 -				ts += TS_SZ;
 -				continue;
 -			}
  
 -			if (! priv->ule_sndu_len) {
 -				/* Got at least two bytes, thus extrace the SNDU length. */
 -				priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
 -				if (priv->ule_sndu_len & 0x8000) {
 -					/* D-Bit is set: no dest mac present. */
 -					priv->ule_sndu_len &= 0x7FFF;
 -					priv->ule_dbit = 1;
 -				} else
 -					priv->ule_dbit = 0;
 -
 -				if (priv->ule_sndu_len < 5) {
 -					printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
 -					       "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
 -					dev->stats.rx_errors++;
 -					dev->stats.rx_length_errors++;
 -					priv->ule_sndu_len = 0;
 -					priv->need_pusi = 1;
 -					new_ts = 1;
 -					ts += TS_SZ;
 -					priv->ts_count++;
 -					continue;
 -				}
 -				ts_remain -= 2;	/* consume the 2 bytes SNDU length. */
 -				from_where += 2;
 -			}
 +/*
 + * Start a new payload with skb.
 + * Find ULE header.  It is only guaranteed that the
 + * length field (2 bytes) is contained in the current
 + * TS.
 + * Check h.ts_remain has to be >= 2 here.
 + */
 +static int dvb_net_ule_new_payload(struct dvb_net_ule_handle *h)
 +{
 +	if (h->ts_remain < 2) {
 +		pr_warn("Invalid payload packing: only %d bytes left in TS.  Resyncing.\n",
 +			h->ts_remain);
 +		h->priv->ule_sndu_len = 0;
 +		h->priv->need_pusi = 1;
 +		h->ts += TS_SZ;
 +		return 1;
 +	}
 +
 +	if (!h->priv->ule_sndu_len) {
 +		/* Got at least two bytes, thus extrace the SNDU length. */
 +		h->priv->ule_sndu_len = h->from_where[0] << 8 |
 +					h->from_where[1];
 +		if (h->priv->ule_sndu_len & 0x8000) {
 +			/* D-Bit is set: no dest mac present. */
 +			h->priv->ule_sndu_len &= 0x7FFF;
 +			h->priv->ule_dbit = 1;
 +		} else
 +			h->priv->ule_dbit = 0;
 +
 +		if (h->priv->ule_sndu_len < 5) {
 +			pr_warn("%lu: Invalid ULE SNDU length %u. Resyncing.\n",
 +				h->priv->ts_count,
 +				h->priv->ule_sndu_len);
 +			h->dev->stats.rx_errors++;
 +			h->dev->stats.rx_length_errors++;
 +			h->priv->ule_sndu_len = 0;
 +			h->priv->need_pusi = 1;
 +			h->new_ts = 1;
 +			h->ts += TS_SZ;
 +			h->priv->ts_count++;
 +			return 1;
 +		}
 +		h->ts_remain -= 2;	/* consume the 2 bytes SNDU length. */
 +		h->from_where += 2;
 +	}
 +
 +	h->priv->ule_sndu_remain = h->priv->ule_sndu_len + 2;
 +	/*
 +	 * State of current TS:
 +	 *   h->ts_remain (remaining bytes in the current TS cell)
 +	 *   0	ule_type is not available now, we need the next TS cell
 +	 *   1	the first byte of the ule_type is present
 +	 * >=2	full ULE header present, maybe some payload data as well.
 +	 */
 +	switch (h->ts_remain) {
 +	case 1:
 +		h->priv->ule_sndu_remain--;
 +		h->priv->ule_sndu_type = h->from_where[0] << 8;
 +
 +		/* first byte of ule_type is set. */
 +		h->priv->ule_sndu_type_1 = 1;
 +		h->ts_remain -= 1;
 +		h->from_where += 1;
 +		/* fallthrough */
 +	case 0:
 +		h->new_ts = 1;
 +		h->ts += TS_SZ;
 +		h->priv->ts_count++;
 +		return 1;
 +
 +	default: /* complete ULE header is present in current TS. */
 +		/* Extract ULE type field. */
 +		if (h->priv->ule_sndu_type_1) {
 +			h->priv->ule_sndu_type_1 = 0;
 +			h->priv->ule_sndu_type |= h->from_where[0];
 +			h->from_where += 1; /* points to payload start. */
 +			h->ts_remain -= 1;
 +		} else {
 +			/* Complete type is present in new TS. */
 +			h->priv->ule_sndu_type = h->from_where[0] << 8 |
 +						 h->from_where[1];
 +			h->from_where += 2; /* points to payload start. */
 +			h->ts_remain -= 2;
 +		}
 +		break;
 +	}
 +
 +	/*
 +	 * Allocate the skb (decoder target buffer) with the correct size,
 +	 * as follows:
 +	 *
 +	 * prepare for the largest case: bridged SNDU with MAC address
 +	 * (dbit = 0).
 +	 */
 +	h->priv->ule_skb = dev_alloc_skb(h->priv->ule_sndu_len +
 +					 ETH_HLEN + ETH_ALEN);
 +	if (!h->priv->ule_skb) {
 +		pr_notice("%s: Memory squeeze, dropping packet.\n",
 +			  h->dev->name);
 +		h->dev->stats.rx_dropped++;
 +		return -1;
 +	}
 +
 +	/* This includes the CRC32 _and_ dest mac, if !dbit. */
 +	h->priv->ule_sndu_remain = h->priv->ule_sndu_len;
 +	h->priv->ule_skb->dev = h->dev;
 +	/*
 +	 * Leave space for Ethernet or bridged SNDU header
 +	 * (eth hdr plus one MAC addr).
 +	 */
 +	skb_reserve(h->priv->ule_skb, ETH_HLEN + ETH_ALEN);
 +
 +	return 0;
 +}
 +
  
 -			priv->ule_sndu_remain = priv->ule_sndu_len + 2;
 +static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h)
 +{
 +	static const u8 bc_addr[ETH_ALEN] = { [0 ... ETH_ALEN - 1] = 0xff };
 +
 +	/*
 +	 * The destination MAC address is the next data in the skb.  It comes
 +	 * before any extension headers.
 +	 *
 +	 * Check if the payload of this SNDU should be passed up the stack.
 +	 */
 +	if (h->priv->rx_mode == RX_MODE_PROMISC)
 +		return 0;
 +
 +	if (h->priv->ule_skb->data[0] & 0x01) {
 +		/* multicast or broadcast */
 +		if (!ether_addr_equal(h->priv->ule_skb->data, bc_addr)) {
 +			/* multicast */
 +			if (h->priv->rx_mode == RX_MODE_MULTI) {
 +				int i;
 +
 +				for (i = 0; i < h->priv->multi_num &&
 +				     !ether_addr_equal(h->priv->ule_skb->data,
 +						       h->priv->multi_macs[i]);
 +				     i++)
 +					;
 +				if (i == h->priv->multi_num)
 +					return 1;
 +			} else if (h->priv->rx_mode != RX_MODE_ALL_MULTI)
 +				return 1; /* no broadcast; */
  			/*
 -			 * State of current TS:
 -			 *   ts_remain (remaining bytes in the current TS cell)
 -			 *   0	ule_type is not available now, we need the next TS cell
 -			 *   1	the first byte of the ule_type is present
 -			 * >=2	full ULE header present, maybe some payload data as well.
 +			 * else:
 +			 * all multicast mode: accept all multicast packets
  			 */
 -			switch (ts_remain) {
 -				case 1:
 -					priv->ule_sndu_remain--;
 -					priv->ule_sndu_type = from_where[0] << 8;
 -					priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
 -					ts_remain -= 1; from_where += 1;
 -					/* Continue w/ next TS. */
 -				case 0:
 -					new_ts = 1;
 -					ts += TS_SZ;
 -					priv->ts_count++;
 -					continue;
 -
 -				default: /* complete ULE header is present in current TS. */
 -					/* Extract ULE type field. */
 -					if (priv->ule_sndu_type_1) {
 -						priv->ule_sndu_type_1 = 0;
 -						priv->ule_sndu_type |= from_where[0];
 -						from_where += 1; /* points to payload start. */
 -						ts_remain -= 1;
 -					} else {
 -						/* Complete type is present in new TS. */
 -						priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
 -						from_where += 2; /* points to payload start. */
 -						ts_remain -= 2;
 -					}
 -					break;
 -			}
 +		}
 +		/* else: broadcast */
 +	} else if (!ether_addr_equal(h->priv->ule_skb->data, h->dev->dev_addr))
 +		return 1;
  
 -			/* Allocate the skb (decoder target buffer) with the correct size, as follows:
 -			 * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */
 -			priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN );
 -			if (priv->ule_skb == NULL) {
 -				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
 -				       dev->name);
 -				dev->stats.rx_dropped++;
 -				return;
 -			}
 +	return 0;
 +}
 +
 +
 +static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
 +				  u32 ule_crc, u32 expected_crc)
 +{
 +	u8 dest_addr[ETH_ALEN];
 +
 +	if (ule_crc != expected_crc) {
 +		pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
 +			h->priv->ts_count, ule_crc, expected_crc,
 +			h->priv->ule_sndu_len, h->priv->ule_sndu_type,
 +			h->ts_remain,
 +			h->ts_remain > 2 ?
 +				*(unsigned short *)h->from_where : 0);
 +
 +	#ifdef ULE_DEBUG
 +		hexdump(iov[0].iov_base, iov[0].iov_len);
 +		hexdump(iov[1].iov_base, iov[1].iov_len);
 +		hexdump(iov[2].iov_base, iov[2].iov_len);
 +
 +		if (h->ule_where == h->ule_hist) {
 +			hexdump(&h->ule_hist[98*TS_SZ], TS_SZ);
 +			hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
 +		} else if (h->ule_where == &h->ule_hist[TS_SZ]) {
 +			hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
 +			hexdump(h->ule_hist, TS_SZ);
 +		} else {
 +			hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ);
 +			hexdump(h->ule_where - TS_SZ, TS_SZ);
 +		}
 +		h->ule_dump = 1;
 +	#endif
 +
 +		h->dev->stats.rx_errors++;
 +		h->dev->stats.rx_crc_errors++;
 +		dev_kfree_skb(h->priv->ule_skb);
 +
 +		return;
 +	}
 +
 +	/* CRC32 verified OK. */
 +
 +	/* CRC32 was OK, so remove it from skb. */
 +	h->priv->ule_skb->tail -= 4;
 +	h->priv->ule_skb->len -= 4;
 +
 +	if (!h->priv->ule_dbit) {
 +		if (dvb_net_ule_should_drop(h)) {
 +#ifdef ULE_DEBUG
 +			netdev_dbg(h->dev,
 +				   "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n",
 +				   h->priv->ule_skb->data, h->dev->dev_addr);
 +#endif
 +			dev_kfree_skb(h->priv->ule_skb);
 +			return;
 +		}
 +
 +		skb_copy_from_linear_data(h->priv->ule_skb, dest_addr,
 +					  ETH_ALEN);
 +		skb_pull(h->priv->ule_skb, ETH_ALEN);
 +	}
 +
 +	/* Handle ULE Extension Headers. */
 +	if (h->priv->ule_sndu_type < ETH_P_802_3_MIN) {
 +		/* There is an extension header.  Handle it accordingly. */
 +		int l = handle_ule_extensions(h->priv);
 +
 +		if (l < 0) {
 +			/*
 +			 * Mandatory extension header unknown or TEST SNDU.
 +			 * Drop it.
 +			 */
 +
 +			// pr_warn("Dropping SNDU, extension headers.\n" );
 +			dev_kfree_skb(h->priv->ule_skb);
 +			return;
 +		}
 +		skb_pull(h->priv->ule_skb, l);
 +	}
 +
 +	/*
 +	 * Construct/assure correct ethernet header.
 +	 * Note: in bridged mode (h->priv->ule_bridged != 0)
 +	 * we already have the (original) ethernet
 +	 * header at the start of the payload (after
 +	 * optional dest. address and any extension
 +	 * headers).
 +	 */
 +	if (!h->priv->ule_bridged) {
 +		skb_push(h->priv->ule_skb, ETH_HLEN);
 +		h->ethh = (struct ethhdr *)h->priv->ule_skb->data;
 +		if (!h->priv->ule_dbit) {
 +			/*
 +			 * dest_addr buffer is only valid if
 +			 * h->priv->ule_dbit == 0
 +			 */
 +			memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN);
 +			eth_zero_addr(h->ethh->h_source);
 +		} else /* zeroize source and dest */
 +			memset(h->ethh, 0, ETH_ALEN * 2);
  
 -			/* This includes the CRC32 _and_ dest mac, if !dbit. */
 -			priv->ule_sndu_remain = priv->ule_sndu_len;
 -			priv->ule_skb->dev = dev;
 -			/* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */
 -			skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN );
 +		h->ethh->h_proto = htons(h->priv->ule_sndu_type);
 +	}
 +	/* else:  skb is in correct state; nothing to do. */
 +	h->priv->ule_bridged = 0;
 +
 +	/* Stuff into kernel's protocol stack. */
 +	h->priv->ule_skb->protocol = dvb_net_eth_type_trans(h->priv->ule_skb,
 +							   h->dev);
 +	/*
 +	 * If D-bit is set (i.e. destination MAC address not present),
 +	 * receive the packet anyhow.
 +	 */
 +#if 0
 +	if (h->priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
 +		h->priv->ule_skb->pkt_type = PACKET_HOST;
 +#endif
 +	h->dev->stats.rx_packets++;
 +	h->dev->stats.rx_bytes += h->priv->ule_skb->len;
 +	netif_rx(h->priv->ule_skb);
 +}
 +
 +static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
 +{
 +	int ret;
 +	struct dvb_net_ule_handle h = {
 +		.dev = dev,
 +		.buf = buf,
 +		.buf_len = buf_len,
 +		.skipped = 0L,
 +		.ts = NULL,
 +		.ts_end = NULL,
 +		.from_where = NULL,
 +		.ts_remain = 0,
 +		.how_much = 0,
 +		.new_ts = 1,
 +		.ethh = NULL,
 +		.error = false,
 +#ifdef ULE_DEBUG
 +		.ule_where = ule_hist,
 +#endif
 +	};
 +
 +	/*
 +	 * For all TS cells in current buffer.
 +	 * Appearently, we are called for every single TS cell.
 +	 */
 +	for (h.ts = h.buf, h.ts_end = h.buf + h.buf_len;
 +	     h.ts < h.ts_end; /* no incr. */) {
 +		if (h.new_ts) {
 +			/* We are about to process a new TS cell. */
 +			if (dvb_net_ule_new_ts_cell(&h))
 +				continue;
 +		}
 +
 +		/* Synchronize on PUSI, if required. */
 +		if (h.priv->need_pusi) {
 +			if (dvb_net_ule_ts_pusi(&h))
 +				continue;
 +		}
 +
 +		if (h.new_ts) {
 +			if (dvb_net_ule_new_ts(&h))
 +				continue;
 +		}
 +
 +		/* Check if new payload needs to be started. */
 +		if (h.priv->ule_skb == NULL) {
 +			ret = dvb_net_ule_new_payload(&h);
 +			if (ret < 0)
 +				return;
 +			if (ret)
 +				continue;
  		}
  
  		/* Copy data into our current skb. */
 -		how_much = min(priv->ule_sndu_remain, (int)ts_remain);
 -		memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much);
 -		priv->ule_sndu_remain -= how_much;
 -		ts_remain -= how_much;
 -		from_where += how_much;
 +		h.how_much = min(h.priv->ule_sndu_remain, (int)h.ts_remain);
 +		memcpy(skb_put(h.priv->ule_skb, h.how_much),
 +		       h.from_where, h.how_much);
 +		h.priv->ule_sndu_remain -= h.how_much;
 +		h.ts_remain -= h.how_much;
 +		h.from_where += h.how_much;
  
  		/* Check for complete payload. */
 -		if (priv->ule_sndu_remain <= 0) {
 +		if (h.priv->ule_sndu_remain <= 0) {
  			/* Check CRC32, we've got it in our skb already. */
 -			__be16 ulen = htons(priv->ule_sndu_len);
 -			__be16 utype = htons(priv->ule_sndu_type);
 +			__be16 ulen = htons(h.priv->ule_sndu_len);
 +			__be16 utype = htons(h.priv->ule_sndu_type);
  			const u8 *tail;
  			struct kvec iov[3] = {
  				{ &ulen, sizeof ulen },
  				{ &utype, sizeof utype },
 -				{ priv->ule_skb->data, priv->ule_skb->len - 4 }
 +				{ h.priv->ule_skb->data,
 +				  h.priv->ule_skb->len - 4 }
  			};
  			u32 ule_crc = ~0L, expected_crc;
 -			if (priv->ule_dbit) {
 +			if (h.priv->ule_dbit) {
  				/* Set D-bit for CRC32 verification,
  				 * if it was set originally. */
  				ulen |= htons(0x8000);
  			}
  
  			ule_crc = iov_crc32(ule_crc, iov, 3);
 -			tail = skb_tail_pointer(priv->ule_skb);
 +			tail = skb_tail_pointer(h.priv->ule_skb);
  			expected_crc = *(tail - 4) << 24 |
  				       *(tail - 3) << 16 |
  				       *(tail - 2) << 8 |
  				       *(tail - 1);
 -			if (ule_crc != expected_crc) {
 -				printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
 -				       priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
  
 -#ifdef ULE_DEBUG
 -				hexdump( iov[0].iov_base, iov[0].iov_len );
 -				hexdump( iov[1].iov_base, iov[1].iov_len );
 -				hexdump( iov[2].iov_base, iov[2].iov_len );
 -
 -				if (ule_where == ule_hist) {
 -					hexdump( &ule_hist[98*TS_SZ], TS_SZ );
 -					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
 -				} else if (ule_where == &ule_hist[TS_SZ]) {
 -					hexdump( &ule_hist[99*TS_SZ], TS_SZ );
 -					hexdump( ule_hist, TS_SZ );
 -				} else {
 -					hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ );
 -					hexdump( ule_where - TS_SZ, TS_SZ );
 -				}
 -				ule_dump = 1;
 -#endif
 +			dvb_net_ule_check_crc(&h, ule_crc, expected_crc);
  
 -				dev->stats.rx_errors++;
 -				dev->stats.rx_crc_errors++;
 -				dev_kfree_skb(priv->ule_skb);
 -			} else {
 -				/* CRC32 verified OK. */
 -				u8 dest_addr[ETH_ALEN];
 -				static const u8 bc_addr[ETH_ALEN] =
 -					{ [ 0 ... ETH_ALEN-1] = 0xff };
 -
 -				/* CRC32 was OK. Remove it from skb. */
 -				priv->ule_skb->tail -= 4;
 -				priv->ule_skb->len -= 4;
 -
 -				if (!priv->ule_dbit) {
 -					/*
 -					 * The destination MAC address is the
 -					 * next data in the skb.  It comes
 -					 * before any extension headers.
 -					 *
 -					 * Check if the payload of this SNDU
 -					 * should be passed up the stack.
 -					 */
 -					register int drop = 0;
 -					if (priv->rx_mode != RX_MODE_PROMISC) {
 -						if (priv->ule_skb->data[0] & 0x01) {
 -							/* multicast or broadcast */
 -							if (!ether_addr_equal(priv->ule_skb->data, bc_addr)) {
 -								/* multicast */
 -								if (priv->rx_mode == RX_MODE_MULTI) {
 -									int i;
 -									for(i = 0; i < priv->multi_num &&
 -									    !ether_addr_equal(priv->ule_skb->data,
 -											      priv->multi_macs[i]); i++)
 -										;
 -									if (i == priv->multi_num)
 -										drop = 1;
 -								} else if (priv->rx_mode != RX_MODE_ALL_MULTI)
 -									drop = 1; /* no broadcast; */
 -								/* else: all multicast mode: accept all multicast packets */
 -							}
 -							/* else: broadcast */
 -						}
 -						else if (!ether_addr_equal(priv->ule_skb->data, dev->dev_addr))
 -							drop = 1;
 -						/* else: destination address matches the MAC address of our receiver device */
 -					}
 -					/* else: promiscuous mode; pass everything up the stack */
 -
 -					if (drop) {
 -#ifdef ULE_DEBUG
 -						netdev_dbg(dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, dev addr: %pM\n",
 -							   priv->ule_skb->data, dev->dev_addr);
 -#endif
 -						dev_kfree_skb(priv->ule_skb);
 -						goto sndu_done;
 -					}
 -					else
 -					{
 -						skb_copy_from_linear_data(priv->ule_skb,
 -							      dest_addr,
 -							      ETH_ALEN);
 -						skb_pull(priv->ule_skb, ETH_ALEN);
 -					}
 -				}
 -
 -				/* Handle ULE Extension Headers. */
 -				if (priv->ule_sndu_type < ETH_P_802_3_MIN) {
 -					/* There is an extension header.  Handle it accordingly. */
 -					int l = handle_ule_extensions(priv);
 -					if (l < 0) {
 -						/* Mandatory extension header unknown or TEST SNDU.  Drop it. */
 -						// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
 -						dev_kfree_skb(priv->ule_skb);
 -						goto sndu_done;
 -					}
 -					skb_pull(priv->ule_skb, l);
 -				}
 -
 -				/*
 -				 * Construct/assure correct ethernet header.
 -				 * Note: in bridged mode (priv->ule_bridged !=
 -				 * 0) we already have the (original) ethernet
 -				 * header at the start of the payload (after
 -				 * optional dest. address and any extension
 -				 * headers).
 -				 */
 -
 -				if (!priv->ule_bridged) {
 -					skb_push(priv->ule_skb, ETH_HLEN);
 -					ethh = (struct ethhdr *)priv->ule_skb->data;
 -					if (!priv->ule_dbit) {
 -						 /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
 -						memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
 -						eth_zero_addr(ethh->h_source);
 -					}
 -					else /* zeroize source and dest */
 -						memset( ethh, 0, ETH_ALEN*2 );
 -
 -					ethh->h_proto = htons(priv->ule_sndu_type);
 -				}
 -				/* else:  skb is in correct state; nothing to do. */
 -				priv->ule_bridged = 0;
 -
 -				/* Stuff into kernel's protocol stack. */
 -				priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev);
 -				/* If D-bit is set (i.e. destination MAC address not present),
 -				 * receive the packet anyhow. */
 -				/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
 -					priv->ule_skb->pkt_type = PACKET_HOST; */
 -				dev->stats.rx_packets++;
 -				dev->stats.rx_bytes += priv->ule_skb->len;
 -				netif_rx(priv->ule_skb);
 -			}
 -			sndu_done:
  			/* Prepare for next SNDU. */
 -			reset_ule(priv);
 +			reset_ule(h.priv);
  		}
  
  		/* More data in current TS (look at the bytes following the CRC32)? */
 -		if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
 +		if (h.ts_remain >= 2 && *((unsigned short *)h.from_where) != 0xFFFF) {
  			/* Next ULE SNDU starts right there. */
 -			new_ts = 0;
 -			priv->ule_skb = NULL;
 -			priv->ule_sndu_type_1 = 0;
 -			priv->ule_sndu_len = 0;
 -			// printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n",
 -			//	*(from_where + 0), *(from_where + 1),
 -			//	*(from_where + 2), *(from_where + 3));
 -			// printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0);
 -			// hexdump(ts, 188);
 +			h.new_ts = 0;
 +			h.priv->ule_skb = NULL;
 +			h.priv->ule_sndu_type_1 = 0;
 +			h.priv->ule_sndu_len = 0;
 +			// pr_warn("More data in current TS: [%#x %#x %#x %#x]\n",
 +			//	*(h.from_where + 0), *(h.from_where + 1),
 +			//	*(h.from_where + 2), *(h.from_where + 3));
 +			// pr_warn("h.ts @ %p, stopped @ %p:\n", h.ts, h.from_where + 0);
 +			// hexdump(h.ts, 188);
  		} else {
 -			new_ts = 1;
 -			ts += TS_SZ;
 -			priv->ts_count++;
 -			if (priv->ule_skb == NULL) {
 -				priv->need_pusi = 1;
 -				priv->ule_sndu_type_1 = 0;
 -				priv->ule_sndu_len = 0;
 +			h.new_ts = 1;
 +			h.ts += TS_SZ;
 +			h.priv->ts_count++;
 +			if (h.priv->ule_skb == NULL) {
 +				h.priv->need_pusi = 1;
 +				h.priv->ule_sndu_type_1 = 0;
 +				h.priv->ule_sndu_len = 0;
  			}
  		}
  	}	/* for all available TS cells */
@@@ -906,10 -766,10 +906,10 @@@ static int dvb_net_ts_callback(const u
  	struct net_device *dev = feed->priv;
  
  	if (buffer2)
 -		printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
 +		pr_warn("buffer2 not NULL: %p.\n", buffer2);
  	if (buffer1_len > 32768)
 -		printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
 -	/* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
 +		pr_warn("length > 32k: %zu.\n", buffer1_len);
 +	/* pr_info("TS callback: %u bytes, %u TS cells @ %p.\n",
  		  buffer1_len, buffer1_len / TS_SZ, buffer1); */
  	dvb_net_ule(dev, buffer1, buffer1_len);
  	return 0;
@@@ -926,7 -786,7 +926,7 @@@ static void dvb_net_sec(struct net_devi
  
  	/* note: pkt_len includes a 32bit checksum */
  	if (pkt_len < 16) {
 -		printk("%s: IP/MPE packet length = %d too small.\n",
 +		pr_warn("%s: IP/MPE packet length = %d too small.\n",
  			dev->name, pkt_len);
  		stats->rx_errors++;
  		stats->rx_length_errors++;
@@@ -964,7 -824,7 +964,7 @@@
  	 * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
  	 */
  	if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
 -		//printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
 +		//pr_notice("%s: Memory squeeze, dropping packet.\n", dev->name);
  		stats->rx_dropped++;
  		return;
  	}
@@@ -1043,7 -903,7 +1043,7 @@@ static int dvb_net_filter_sec_set(struc
  	*secfilter=NULL;
  	ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
  	if (ret<0) {
 -		printk("%s: could not get filter\n", dev->name);
 +		pr_err("%s: could not get filter\n", dev->name);
  		return ret;
  	}
  
@@@ -1084,7 -944,7 +1084,7 @@@ static int dvb_net_feed_start(struct ne
  	netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode);
  	mutex_lock(&priv->mutex);
  	if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
 -		printk("%s: BUG %d\n", __func__, __LINE__);
 +		pr_err("%s: BUG %d\n", __func__, __LINE__);
  
  	priv->secfeed=NULL;
  	priv->secfilter=NULL;
@@@ -1095,15 -955,14 +1095,15 @@@
  		ret=demux->allocate_section_feed(demux, &priv->secfeed,
  					 dvb_net_sec_callback);
  		if (ret<0) {
 -			printk("%s: could not allocate section feed\n", dev->name);
 +			pr_err("%s: could not allocate section feed\n",
 +			       dev->name);
  			goto error;
  		}
  
 -		ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
 +		ret = priv->secfeed->set(priv->secfeed, priv->pid, 1);
  
  		if (ret<0) {
 -			printk("%s: could not set section feed\n", dev->name);
 +			pr_err("%s: could not set section feed\n", dev->name);
  			priv->demux->release_section_feed(priv->demux, priv->secfeed);
  			priv->secfeed=NULL;
  			goto error;
@@@ -1144,7 -1003,7 +1144,7 @@@
  		netdev_dbg(dev, "alloc tsfeed\n");
  		ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
  		if (ret < 0) {
 -			printk("%s: could not allocate ts feed\n", dev->name);
 +			pr_err("%s: could not allocate ts feed\n", dev->name);
  			goto error;
  		}
  
@@@ -1154,11 -1013,12 +1154,11 @@@
  					priv->pid, /* pid */
  					TS_PACKET, /* type */
  					DMX_PES_OTHER, /* pes type */
 -					32768,     /* circular buffer size */
  					timeout    /* timeout */
  					);
  
  		if (ret < 0) {
 -			printk("%s: could not set ts feed\n", dev->name);
 +			pr_err("%s: could not set ts feed\n", dev->name);
  			priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
  			priv->tsfeed = NULL;
  			goto error;
@@@ -1207,7 -1067,7 +1207,7 @@@ static int dvb_net_feed_stop(struct net
  			priv->demux->release_section_feed(priv->demux, priv->secfeed);
  			priv->secfeed = NULL;
  		} else
 -			printk("%s: no feed to stop\n", dev->name);
 +			pr_err("%s: no feed to stop\n", dev->name);
  	} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
  		if (priv->tsfeed) {
  			if (priv->tsfeed->is_filtering) {
@@@ -1218,7 -1078,7 +1218,7 @@@
  			priv->tsfeed = NULL;
  		}
  		else
 -			printk("%s: no ts feed to stop\n", dev->name);
 +			pr_err("%s: no ts feed to stop\n", dev->name);
  	} else
  		ret = -EINVAL;
  	mutex_unlock(&priv->mutex);
@@@ -1338,7 -1198,6 +1338,6 @@@ static const struct net_device_ops dvb_
  	.ndo_start_xmit		= dvb_net_tx,
  	.ndo_set_rx_mode	= dvb_net_set_multicast_list,
  	.ndo_set_mac_address    = dvb_net_set_mac,
- 	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_validate_addr	= eth_validate_addr,
  };
  
@@@ -1349,6 -1208,7 +1348,7 @@@ static void dvb_net_setup(struct net_de
  	dev->header_ops		= &dvb_header_ops;
  	dev->netdev_ops		= &dvb_netdev_ops;
  	dev->mtu		= 4096;
+ 	dev->max_mtu		= 4096;
  
  	dev->flags |= IFF_NOARP;
  }
@@@ -1419,7 -1279,7 +1419,7 @@@ static int dvb_net_add_if(struct dvb_ne
  		free_netdev(net);
  		return result;
  	}
 -	printk("dvb_net: created network interface %s\n", net->name);
 +	pr_info("created network interface %s\n", net->name);
  
  	return if_num;
  }
@@@ -1438,7 -1298,7 +1438,7 @@@ static int dvb_net_remove_if(struct dvb
  	dvb_net_stop(net);
  	flush_work(&priv->set_multicast_list_wq);
  	flush_work(&priv->restart_net_feed_wq);
 -	printk("dvb_net: removed network interface %s\n", net->name);
 +	pr_info("removed network interface %s\n", net->name);
  	unregister_netdev(net);
  	dvbnet->state[num]=0;
  	dvbnet->device[num] = NULL;
diff --combined drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 4febe60,ab990da..688617a
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@@ -10138,7 -10138,7 +10138,7 @@@ static void __bnx2x_add_udp_port(struc
  {
  	struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
  
 -	if (!netif_running(bp->dev) || !IS_PF(bp))
 +	if (!netif_running(bp->dev) || !IS_PF(bp) || CHIP_IS_E1x(bp))
  		return;
  
  	if (udp_port->count && udp_port->dst_port == port) {
@@@ -10163,7 -10163,7 +10163,7 @@@ static void __bnx2x_del_udp_port(struc
  {
  	struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
  
 -	if (!IS_PF(bp))
 +	if (!IS_PF(bp) || CHIP_IS_E1x(bp))
  		return;
  
  	if (!udp_port->count || udp_port->dst_port != port) {
@@@ -12080,8 -12080,7 +12080,7 @@@ static int bnx2x_get_hwinfo(struct bnx2
  					   mtu_size, mtu);
  
  					/* if valid: update device mtu */
- 					if (((mtu_size + ETH_HLEN) >=
- 					     ETH_MIN_PACKET_SIZE) &&
+ 					if ((mtu_size >= ETH_MIN_PACKET_SIZE) &&
  					    (mtu_size <=
  					     ETH_MAX_JUMBO_PACKET_SIZE))
  						bp->dev->mtu = mtu_size;
@@@ -13315,6 -13314,10 +13314,10 @@@ static int bnx2x_init_dev(struct bnx2x 
  	dev->dcbnl_ops = &bnx2x_dcbnl_ops;
  #endif
  
+ 	/* MTU range, 46 - 9600 */
+ 	dev->min_mtu = ETH_MIN_PACKET_SIZE;
+ 	dev->max_mtu = ETH_MAX_JUMBO_PACKET_SIZE;
+ 
  	/* get_port_hwinfo() will set prtad and mmds properly */
  	bp->mdio.prtad = MDIO_PRTAD_NONE;
  	bp->mdio.mmds = 0;
@@@ -13505,7 -13508,6 +13508,7 @@@ static int bnx2x_init_firmware(struct b
  
  	/* Initialize the pointers to the init arrays */
  	/* Blob */
 +	rc = -ENOMEM;
  	BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n);
  
  	/* Opcodes */
diff --combined drivers/net/ethernet/broadcom/bnxt/bnxt.c
index f08a20b,e8ab5fd..e84613a
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@@ -54,6 -54,7 +54,7 @@@
  #include "bnxt.h"
  #include "bnxt_sriov.h"
  #include "bnxt_ethtool.h"
+ #include "bnxt_dcb.h"
  
  #define BNXT_TX_TIMEOUT		(5 * HZ)
  
@@@ -186,11 -187,11 +187,11 @@@ static const u16 bnxt_vf_req_snif[] = 
  };
  
  static const u16 bnxt_async_events_arr[] = {
- 	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE,
- 	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD,
- 	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED,
- 	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE,
- 	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE,
+ 	ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE,
+ 	ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD,
+ 	ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED,
+ 	ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE,
+ 	ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE,
  };
  
  static bool bnxt_vf_pciid(enum board_idx idx)
@@@ -1476,8 -1477,8 +1477,8 @@@ next_rx_no_prod
  }
  
  #define BNXT_GET_EVENT_PORT(data)	\
- 	((data) &				\
- 	 HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK)
+ 	((data) &			\
+ 	 ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK)
  
  static int bnxt_async_event_process(struct bnxt *bp,
  				    struct hwrm_async_event_cmpl *cmpl)
@@@ -1486,7 -1487,7 +1487,7 @@@
  
  	/* TODO CHIMP_FW: Define event id's for link change, error etc */
  	switch (event_id) {
- 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: {
+ 	case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: {
  		u32 data1 = le32_to_cpu(cmpl->event_data1);
  		struct bnxt_link_info *link_info = &bp->link_info;
  
@@@ -1499,15 -1500,16 +1500,16 @@@
  			netdev_warn(bp->dev, "Link speed %d no longer supported\n",
  				    speed);
  		}
+ 		set_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, &bp->sp_event);
  		/* fall thru */
  	}
- 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
+ 	case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
  		set_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event);
  		break;
- 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD:
+ 	case ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD:
  		set_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event);
  		break;
- 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED: {
+ 	case ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED: {
  		u32 data1 = le32_to_cpu(cmpl->event_data1);
  		u16 port_id = BNXT_GET_EVENT_PORT(data1);
  
@@@ -1520,7 -1522,7 +1522,7 @@@
  		set_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event);
  		break;
  	}
- 	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE:
+ 	case ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE:
  		if (BNXT_PF(bp))
  			goto async_event_process_exit;
  		set_bit(BNXT_RESET_TASK_SILENT_SP_EVENT, &bp->sp_event);
@@@ -3433,13 -3435,7 +3435,7 @@@ static int bnxt_hwrm_vnic_set_rss(struc
  
  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_RSS_CFG, -1, -1);
  	if (set_rss) {
- 		vnic->hash_type = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 |
- 				  VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
- 				  VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
- 				  VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
- 
- 		req.hash_type = cpu_to_le32(vnic->hash_type);
- 
+ 		req.hash_type = cpu_to_le32(bp->rss_hash_cfg);
  		if (vnic->flags & BNXT_VNIC_RSS_FLAG) {
  			if (BNXT_CHIP_TYPE_NITRO_A0(bp))
  				max_rings = bp->rx_nr_rings - 1;
@@@ -4120,7 -4116,7 +4116,7 @@@ static int bnxt_hwrm_stat_ctx_alloc(str
  		bp->grp_info[i].fw_stats_ctx = cpr->hw_stats_ctx_id;
  	}
  	mutex_unlock(&bp->hwrm_cmd_lock);
 -	return 0;
 +	return rc;
  }
  
  static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
@@@ -4266,12 -4262,16 +4262,16 @@@ static int bnxt_hwrm_queue_qportcfg(str
  		goto qportcfg_exit;
  	}
  	bp->max_tc = resp->max_configurable_queues;
+ 	bp->max_lltc = resp->max_configurable_lossless_queues;
  	if (bp->max_tc > BNXT_MAX_QUEUE)
  		bp->max_tc = BNXT_MAX_QUEUE;
  
  	if (resp->queue_cfg_info & QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG)
  		bp->max_tc = 1;
  
+ 	if (bp->max_lltc > bp->max_tc)
+ 		bp->max_lltc = bp->max_tc;
+ 
  	qptr = &resp->queue_id0;
  	for (i = 0; i < bp->max_tc; i++) {
  		bp->q_info[i].queue_id = *qptr++;
@@@ -4967,7 -4967,6 +4967,6 @@@ static void bnxt_init_napi(struct bnxt 
  			bnapi = bp->bnapi[cp_nr_rings];
  			netif_napi_add(bp->dev, &bnapi->napi,
  				       bnxt_poll_nitroa0, 64);
- 			napi_hash_add(&bnapi->napi);
  		}
  	} else {
  		bnapi = bp->bnapi[0];
@@@ -4999,7 -4998,7 +4998,7 @@@ static void bnxt_enable_napi(struct bnx
  	}
  }
  
- static void bnxt_tx_disable(struct bnxt *bp)
+ void bnxt_tx_disable(struct bnxt *bp)
  {
  	int i;
  	struct bnxt_tx_ring_info *txr;
@@@ -5017,7 -5016,7 +5016,7 @@@
  	netif_carrier_off(bp->dev);
  }
  
- static void bnxt_tx_enable(struct bnxt *bp)
+ void bnxt_tx_enable(struct bnxt *bp)
  {
  	int i;
  	struct bnxt_tx_ring_info *txr;
@@@ -5109,6 -5108,7 +5108,7 @@@ static int bnxt_update_link(struct bnx
  	struct hwrm_port_phy_qcfg_input req = {0};
  	struct hwrm_port_phy_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
  	u8 link_up = link_info->link_up;
+ 	u16 diff;
  
  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_QCFG, -1, -1);
  
@@@ -5196,6 -5196,23 +5196,23 @@@
  		link_info->link_up = 0;
  	}
  	mutex_unlock(&bp->hwrm_cmd_lock);
+ 
+ 	diff = link_info->support_auto_speeds ^ link_info->advertising;
+ 	if ((link_info->support_auto_speeds | diff) !=
+ 	    link_info->support_auto_speeds) {
+ 		/* An advertised speed is no longer supported, so we need to
+ 		 * update the advertisement settings.  See bnxt_reset() for
+ 		 * comments about the rtnl_lock() sequence below.
+ 		 */
+ 		clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+ 		rtnl_lock();
+ 		link_info->advertising = link_info->support_auto_speeds;
+ 		if (test_bit(BNXT_STATE_OPEN, &bp->state) &&
+ 		    (link_info->autoneg & BNXT_AUTONEG_SPEED))
+ 			bnxt_hwrm_set_link_setting(bp, true, false);
+ 		set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+ 		rtnl_unlock();
+ 	}
  	return 0;
  }
  
@@@ -5360,7 -5377,7 +5377,7 @@@ static int bnxt_hwrm_shutdown_link(stru
  		return 0;
  
  	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1);
- 	req.flags = cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DOWN);
+ 	req.flags = cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DWN);
  	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
  }
  
@@@ -5423,6 -5440,12 +5440,12 @@@ static int bnxt_update_phy_setting(stru
  			update_link = true;
  	}
  
+ 	/* The last close may have shutdown the link, so need to call
+ 	 * PHY_CFG to bring it back up.
+ 	 */
+ 	if (!netif_carrier_ok(bp->dev))
+ 		update_link = true;
+ 
  	if (!bnxt_eee_config_ok(bp))
  		update_eee = true;
  
@@@ -6116,6 -6139,10 +6139,10 @@@ static void bnxt_sp_task(struct work_st
  	if (test_and_clear_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event))
  		bnxt_cfg_ntp_filters(bp);
  	if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) {
+ 		if (test_and_clear_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT,
+ 				       &bp->sp_event))
+ 			bnxt_hwrm_phy_qcaps(bp);
+ 
  		rc = bnxt_update_link(bp, true);
  		if (rc)
  			netdev_err(bp->dev, "SP task can't update link (rc: %x)\n",
@@@ -6303,9 -6330,6 +6330,6 @@@ static int bnxt_change_mtu(struct net_d
  {
  	struct bnxt *bp = netdev_priv(dev);
  
- 	if (new_mtu < 60 || new_mtu > 9500)
- 		return -EINVAL;
- 
  	if (netif_running(dev))
  		bnxt_close_nic(bp, false, false);
  
@@@ -6318,17 -6342,10 +6342,10 @@@
  	return 0;
  }
  
- static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
- 			 struct tc_to_netdev *ntc)
+ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
  {
  	struct bnxt *bp = netdev_priv(dev);
  	bool sh = false;
- 	u8 tc;
- 
- 	if (ntc->type != TC_SETUP_MQPRIO)
- 		return -EINVAL;
- 
- 	tc = ntc->tc;
  
  	if (tc > bp->max_tc) {
  		netdev_err(dev, "too many traffic classes requested: %d Max supported is %d\n",
@@@ -6371,6 -6388,15 +6388,15 @@@
  	return 0;
  }
  
+ static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+ 			 struct tc_to_netdev *ntc)
+ {
+ 	if (ntc->type != TC_SETUP_MQPRIO)
+ 		return -EINVAL;
+ 
+ 	return bnxt_setup_mq_tc(dev, ntc->tc);
+ }
+ 
  #ifdef CONFIG_RFS_ACCEL
  static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1,
  			    struct bnxt_ntuple_filter *f2)
@@@ -6661,6 -6687,7 +6687,7 @@@ static void bnxt_remove_one(struct pci_
  
  	bnxt_hwrm_func_drv_unrgtr(bp);
  	bnxt_free_hwrm_resources(bp);
+ 	bnxt_dcb_free(bp);
  	pci_iounmap(pdev, bp->bar2);
  	pci_iounmap(pdev, bp->bar1);
  	pci_iounmap(pdev, bp->bar0);
@@@ -6884,6 -6911,12 +6911,12 @@@ static int bnxt_init_one(struct pci_de
  	dev->features |= dev->hw_features | NETIF_F_HIGHDMA;
  	dev->priv_flags |= IFF_UNICAST_FLT;
  
+ 	/* MTU range: 60 - 9500 */
+ 	dev->min_mtu = ETH_ZLEN;
+ 	dev->max_mtu = 9500;
+ 
+ 	bnxt_dcb_init(bp);
+ 
  #ifdef CONFIG_BNXT_SRIOV
  	init_waitqueue_head(&bp->sriov_cfg_wait);
  #endif
@@@ -6924,6 -6957,19 +6957,19 @@@
  #endif
  	bnxt_set_dflt_rings(bp);
  
+ 	/* Default RSS hash cfg. */
+ 	bp->rss_hash_cfg = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 |
+ 			   VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
+ 			   VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
+ 			   VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
+ 	if (!BNXT_CHIP_NUM_57X0X(bp->chip_num) &&
+ 	    !BNXT_CHIP_TYPE_NITRO_A0(bp) &&
+ 	    bp->hwrm_spec_code >= 0x10501) {
+ 		bp->flags |= BNXT_FLAG_UDP_RSS_CAP;
+ 		bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 |
+ 				    VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
+ 	}
+ 
  	if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp)) {
  		dev->hw_features |= NETIF_F_NTUPLE;
  		if (bnxt_rfs_capable(bp)) {
diff --combined drivers/net/ethernet/cirrus/ep93xx_eth.c
index 9a161e9,9119af0..a1de0d1
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@@ -468,9 -468,6 +468,9 @@@ static void ep93xx_free_buffers(struct 
  	struct device *dev = ep->dev->dev.parent;
  	int i;
  
 +	if (!ep->descs)
 +		return;
 +
  	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
  		dma_addr_t d;
  
@@@ -493,7 -490,6 +493,7 @@@
  
  	dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs,
  							ep->descs_dma_addr);
 +	ep->descs = NULL;
  }
  
  static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
@@@ -753,7 -749,6 +753,6 @@@ static const struct net_device_ops ep93
  	.ndo_start_xmit		= ep93xx_xmit,
  	.ndo_do_ioctl		= ep93xx_ioctl,
  	.ndo_validate_addr	= eth_validate_addr,
- 	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_set_mac_address	= eth_mac_addr,
  };
  
diff --combined drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 62ae55b,de4e2a2..8e5cb76
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@@ -36,6 -36,7 +36,7 @@@
  #include "qed_int.h"
  #include "qed_ll2.h"
  #include "qed_mcp.h"
+ #include "qed_ooo.h"
  #include "qed_reg_addr.h"
  #include "qed_sp.h"
  #include "qed_roce.h"
@@@ -296,25 -297,34 +297,34 @@@ static void qed_ll2_txq_flush(struct qe
  		list_del(&p_pkt->list_entry);
  		b_last_packet = list_empty(&p_tx->active_descq);
  		list_add_tail(&p_pkt->list_entry, &p_tx->free_descq);
- 		p_tx->cur_completing_packet = *p_pkt;
- 		p_tx->cur_completing_bd_idx = 1;
- 		b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
- 		tx_frag = p_pkt->bds_set[0].tx_frag;
- 		if (p_ll2_conn->gsi_enable)
- 			qed_ll2b_release_tx_gsi_packet(p_hwfn,
- 						       p_ll2_conn->my_id,
- 						       p_pkt->cookie,
- 						       tx_frag,
- 						       b_last_frag,
- 						       b_last_packet);
- 		else
- 			qed_ll2b_complete_tx_packet(p_hwfn,
- 						    p_ll2_conn->my_id,
- 						    p_pkt->cookie,
- 						    tx_frag,
- 						    b_last_frag,
- 						    b_last_packet);
+ 		if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+ 			struct qed_ooo_buffer *p_buffer;
  
+ 			p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
+ 			qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info,
+ 						p_buffer);
+ 		} else {
+ 			p_tx->cur_completing_packet = *p_pkt;
+ 			p_tx->cur_completing_bd_idx = 1;
+ 			b_last_frag =
+ 				p_tx->cur_completing_bd_idx == p_pkt->bd_used;
+ 			tx_frag = p_pkt->bds_set[0].tx_frag;
+ 			if (p_ll2_conn->gsi_enable)
+ 				qed_ll2b_release_tx_gsi_packet(p_hwfn,
+ 							       p_ll2_conn->
+ 							       my_id,
+ 							       p_pkt->cookie,
+ 							       tx_frag,
+ 							       b_last_frag,
+ 							       b_last_packet);
+ 			else
+ 				qed_ll2b_complete_tx_packet(p_hwfn,
+ 							    p_ll2_conn->my_id,
+ 							    p_pkt->cookie,
+ 							    tx_frag,
+ 							    b_last_frag,
+ 							    b_last_packet);
+ 		}
  	}
  }
  
@@@ -540,12 -550,457 +550,457 @@@ static void qed_ll2_rxq_flush(struct qe
  
  		list_move_tail(&p_pkt->list_entry, &p_rx->free_descq);
  
- 		rx_buf_addr = p_pkt->rx_buf_addr;
- 		cookie = p_pkt->cookie;
+ 		if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+ 			struct qed_ooo_buffer *p_buffer;
+ 
+ 			p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
+ 			qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info,
+ 						p_buffer);
+ 		} else {
+ 			rx_buf_addr = p_pkt->rx_buf_addr;
+ 			cookie = p_pkt->cookie;
+ 
+ 			b_last = list_empty(&p_rx->active_descq);
+ 		}
+ 	}
+ }
+ 
+ #if IS_ENABLED(CONFIG_QED_ISCSI)
+ static u8 qed_ll2_convert_rx_parse_to_tx_flags(u16 parse_flags)
+ {
+ 	u8 bd_flags = 0;
+ 
+ 	if (GET_FIELD(parse_flags, PARSING_AND_ERR_FLAGS_TAG8021QEXIST))
+ 		SET_FIELD(bd_flags, CORE_TX_BD_FLAGS_VLAN_INSERTION, 1);
+ 
+ 	return bd_flags;
+ }
+ 
+ static int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn,
+ 				  struct qed_ll2_info *p_ll2_conn)
+ {
+ 	struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue;
+ 	u16 packet_length = 0, parse_flags = 0, vlan = 0;
+ 	struct qed_ll2_rx_packet *p_pkt = NULL;
+ 	u32 num_ooo_add_to_peninsula = 0, cid;
+ 	union core_rx_cqe_union *cqe = NULL;
+ 	u16 cq_new_idx = 0, cq_old_idx = 0;
+ 	struct qed_ooo_buffer *p_buffer;
+ 	struct ooo_opaque *iscsi_ooo;
+ 	u8 placement_offset = 0;
+ 	u8 cqe_type;
+ 
+ 	cq_new_idx = le16_to_cpu(*p_rx->p_fw_cons);
+ 	cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain);
+ 	if (cq_new_idx == cq_old_idx)
+ 		return 0;
+ 
+ 	while (cq_new_idx != cq_old_idx) {
+ 		struct core_rx_fast_path_cqe *p_cqe_fp;
+ 
+ 		cqe = qed_chain_consume(&p_rx->rcq_chain);
+ 		cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain);
+ 		cqe_type = cqe->rx_cqe_sp.type;
+ 
+ 		if (cqe_type != CORE_RX_CQE_TYPE_REGULAR) {
+ 			DP_NOTICE(p_hwfn,
+ 				  "Got a non-regular LB LL2 completion [type 0x%02x]\n",
+ 				  cqe_type);
+ 			return -EINVAL;
+ 		}
+ 		p_cqe_fp = &cqe->rx_cqe_fp;
+ 
+ 		placement_offset = p_cqe_fp->placement_offset;
+ 		parse_flags = le16_to_cpu(p_cqe_fp->parse_flags.flags);
+ 		packet_length = le16_to_cpu(p_cqe_fp->packet_length);
+ 		vlan = le16_to_cpu(p_cqe_fp->vlan);
+ 		iscsi_ooo = (struct ooo_opaque *)&p_cqe_fp->opaque_data;
+ 		qed_ooo_save_history_entry(p_hwfn, p_hwfn->p_ooo_info,
+ 					   iscsi_ooo);
+ 		cid = le32_to_cpu(iscsi_ooo->cid);
+ 
+ 		/* Process delete isle first */
+ 		if (iscsi_ooo->drop_size)
+ 			qed_ooo_delete_isles(p_hwfn, p_hwfn->p_ooo_info, cid,
+ 					     iscsi_ooo->drop_isle,
+ 					     iscsi_ooo->drop_size);
+ 
+ 		if (iscsi_ooo->ooo_opcode == TCP_EVENT_NOP)
+ 			continue;
+ 
+ 		/* Now process create/add/join isles */
+ 		if (list_empty(&p_rx->active_descq)) {
+ 			DP_NOTICE(p_hwfn,
+ 				  "LL2 OOO RX chain has no submitted buffers\n"
+ 				  );
+ 			return -EIO;
+ 		}
+ 
+ 		p_pkt = list_first_entry(&p_rx->active_descq,
+ 					 struct qed_ll2_rx_packet, list_entry);
+ 
+ 		if ((iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_NEW_ISLE) ||
+ 		    (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_ISLE_RIGHT) ||
+ 		    (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_ISLE_LEFT) ||
+ 		    (iscsi_ooo->ooo_opcode == TCP_EVENT_ADD_PEN) ||
+ 		    (iscsi_ooo->ooo_opcode == TCP_EVENT_JOIN)) {
+ 			if (!p_pkt) {
+ 				DP_NOTICE(p_hwfn,
+ 					  "LL2 OOO RX packet is not valid\n");
+ 				return -EIO;
+ 			}
+ 			list_del(&p_pkt->list_entry);
+ 			p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
+ 			p_buffer->packet_length = packet_length;
+ 			p_buffer->parse_flags = parse_flags;
+ 			p_buffer->vlan = vlan;
+ 			p_buffer->placement_offset = placement_offset;
+ 			qed_chain_consume(&p_rx->rxq_chain);
+ 			list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
+ 
+ 			switch (iscsi_ooo->ooo_opcode) {
+ 			case TCP_EVENT_ADD_NEW_ISLE:
+ 				qed_ooo_add_new_isle(p_hwfn,
+ 						     p_hwfn->p_ooo_info,
+ 						     cid,
+ 						     iscsi_ooo->ooo_isle,
+ 						     p_buffer);
+ 				break;
+ 			case TCP_EVENT_ADD_ISLE_RIGHT:
+ 				qed_ooo_add_new_buffer(p_hwfn,
+ 						       p_hwfn->p_ooo_info,
+ 						       cid,
+ 						       iscsi_ooo->ooo_isle,
+ 						       p_buffer,
+ 						       QED_OOO_RIGHT_BUF);
+ 				break;
+ 			case TCP_EVENT_ADD_ISLE_LEFT:
+ 				qed_ooo_add_new_buffer(p_hwfn,
+ 						       p_hwfn->p_ooo_info,
+ 						       cid,
+ 						       iscsi_ooo->ooo_isle,
+ 						       p_buffer,
+ 						       QED_OOO_LEFT_BUF);
+ 				break;
+ 			case TCP_EVENT_JOIN:
+ 				qed_ooo_add_new_buffer(p_hwfn,
+ 						       p_hwfn->p_ooo_info,
+ 						       cid,
+ 						       iscsi_ooo->ooo_isle +
+ 						       1,
+ 						       p_buffer,
+ 						       QED_OOO_LEFT_BUF);
+ 				qed_ooo_join_isles(p_hwfn,
+ 						   p_hwfn->p_ooo_info,
+ 						   cid, iscsi_ooo->ooo_isle);
+ 				break;
+ 			case TCP_EVENT_ADD_PEN:
+ 				num_ooo_add_to_peninsula++;
+ 				qed_ooo_put_ready_buffer(p_hwfn,
+ 							 p_hwfn->p_ooo_info,
+ 							 p_buffer, true);
+ 				break;
+ 			}
+ 		} else {
+ 			DP_NOTICE(p_hwfn,
+ 				  "Unexpected event (%d) TX OOO completion\n",
+ 				  iscsi_ooo->ooo_opcode);
+ 		}
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ static void
+ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn,
+ 			  struct qed_ll2_info *p_ll2_conn)
+ {
+ 	struct qed_ooo_buffer *p_buffer;
+ 	int rc;
+ 	u16 l4_hdr_offset_w;
+ 	dma_addr_t first_frag;
+ 	u16 parse_flags;
+ 	u8 bd_flags;
+ 
+ 	/* Submit Tx buffers here */
+ 	while ((p_buffer = qed_ooo_get_ready_buffer(p_hwfn,
+ 						    p_hwfn->p_ooo_info))) {
+ 		l4_hdr_offset_w = 0;
+ 		bd_flags = 0;
+ 
+ 		first_frag = p_buffer->rx_buffer_phys_addr +
+ 			     p_buffer->placement_offset;
+ 		parse_flags = p_buffer->parse_flags;
+ 		bd_flags = qed_ll2_convert_rx_parse_to_tx_flags(parse_flags);
+ 		SET_FIELD(bd_flags, CORE_TX_BD_FLAGS_FORCE_VLAN_MODE, 1);
+ 		SET_FIELD(bd_flags, CORE_TX_BD_FLAGS_L4_PROTOCOL, 1);
+ 
+ 		rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, 1,
+ 					       p_buffer->vlan, bd_flags,
+ 					       l4_hdr_offset_w,
+ 					       p_ll2_conn->tx_dest, 0,
+ 					       first_frag,
+ 					       p_buffer->packet_length,
+ 					       p_buffer, true);
+ 		if (rc) {
+ 			qed_ooo_put_ready_buffer(p_hwfn, p_hwfn->p_ooo_info,
+ 						 p_buffer, false);
+ 			break;
+ 		}
+ 	}
+ }
+ 
+ static void
+ qed_ooo_submit_rx_buffers(struct qed_hwfn *p_hwfn,
+ 			  struct qed_ll2_info *p_ll2_conn)
+ {
+ 	struct qed_ooo_buffer *p_buffer;
+ 	int rc;
+ 
+ 	while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn,
+ 						   p_hwfn->p_ooo_info))) {
+ 		rc = qed_ll2_post_rx_buffer(p_hwfn,
+ 					    p_ll2_conn->my_id,
+ 					    p_buffer->rx_buffer_phys_addr,
+ 					    0, p_buffer, true);
+ 		if (rc) {
+ 			qed_ooo_put_free_buffer(p_hwfn,
+ 						p_hwfn->p_ooo_info, p_buffer);
+ 			break;
+ 		}
+ 	}
+ }
+ 
+ static int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
+ {
+ 	struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie;
+ 	int rc;
+ 
+ 	rc = qed_ll2_lb_rxq_handler(p_hwfn, p_ll2_conn);
+ 	if (rc)
+ 		return rc;
+ 
+ 	qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn);
+ 	qed_ooo_submit_tx_buffers(p_hwfn, p_ll2_conn);
+ 
+ 	return 0;
+ }
+ 
+ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
+ {
+ 	struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie;
+ 	struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue;
+ 	struct qed_ll2_tx_packet *p_pkt = NULL;
+ 	struct qed_ooo_buffer *p_buffer;
+ 	bool b_dont_submit_rx = false;
+ 	u16 new_idx = 0, num_bds = 0;
+ 	int rc;
+ 
+ 	new_idx = le16_to_cpu(*p_tx->p_fw_cons);
+ 	num_bds = ((s16)new_idx - (s16)p_tx->bds_idx);
+ 
+ 	if (!num_bds)
+ 		return 0;
+ 
+ 	while (num_bds) {
+ 		if (list_empty(&p_tx->active_descq))
+ 			return -EINVAL;
+ 
+ 		p_pkt = list_first_entry(&p_tx->active_descq,
+ 					 struct qed_ll2_tx_packet, list_entry);
+ 		if (!p_pkt)
+ 			return -EINVAL;
+ 
+ 		if (p_pkt->bd_used != 1) {
+ 			DP_NOTICE(p_hwfn,
+ 				  "Unexpectedly many BDs(%d) in TX OOO completion\n",
+ 				  p_pkt->bd_used);
+ 			return -EINVAL;
+ 		}
+ 
+ 		list_del(&p_pkt->list_entry);
+ 
+ 		num_bds--;
+ 		p_tx->bds_idx++;
+ 		qed_chain_consume(&p_tx->txq_chain);
+ 
+ 		p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
+ 		list_add_tail(&p_pkt->list_entry, &p_tx->free_descq);
+ 
+ 		if (b_dont_submit_rx) {
+ 			qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info,
+ 						p_buffer);
+ 			continue;
+ 		}
+ 
+ 		rc = qed_ll2_post_rx_buffer(p_hwfn, p_ll2_conn->my_id,
+ 					    p_buffer->rx_buffer_phys_addr, 0,
+ 					    p_buffer, true);
+ 		if (rc != 0) {
+ 			qed_ooo_put_free_buffer(p_hwfn,
+ 						p_hwfn->p_ooo_info, p_buffer);
+ 			b_dont_submit_rx = true;
+ 		}
+ 	}
+ 
+ 	qed_ooo_submit_tx_buffers(p_hwfn, p_ll2_conn);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn,
+ 			       struct qed_ll2_info *p_ll2_info,
+ 			       u16 rx_num_ooo_buffers, u16 mtu)
+ {
+ 	struct qed_ooo_buffer *p_buf = NULL;
+ 	void *p_virt;
+ 	u16 buf_idx;
+ 	int rc = 0;
+ 
+ 	if (p_ll2_info->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ 		return rc;
+ 
+ 	if (!rx_num_ooo_buffers)
+ 		return -EINVAL;
+ 
+ 	for (buf_idx = 0; buf_idx < rx_num_ooo_buffers; buf_idx++) {
+ 		p_buf = kzalloc(sizeof(*p_buf), GFP_KERNEL);
+ 		if (!p_buf) {
+ 			rc = -ENOMEM;
+ 			goto out;
+ 		}
+ 
+ 		p_buf->rx_buffer_size = mtu + 26 + ETH_CACHE_LINE_SIZE;
+ 		p_buf->rx_buffer_size = (p_buf->rx_buffer_size +
+ 					 ETH_CACHE_LINE_SIZE - 1) &
+ 					~(ETH_CACHE_LINE_SIZE - 1);
+ 		p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
+ 					    p_buf->rx_buffer_size,
+ 					    &p_buf->rx_buffer_phys_addr,
+ 					    GFP_KERNEL);
+ 		if (!p_virt) {
+ 			kfree(p_buf);
+ 			rc = -ENOMEM;
+ 			goto out;
+ 		}
+ 
+ 		p_buf->rx_buffer_virt_addr = p_virt;
+ 		qed_ooo_put_free_buffer(p_hwfn, p_hwfn->p_ooo_info, p_buf);
+ 	}
+ 
+ 	DP_VERBOSE(p_hwfn, QED_MSG_LL2,
+ 		   "Allocated [%04x] LL2 OOO buffers [each of size 0x%08x]\n",
+ 		   rx_num_ooo_buffers, p_buf->rx_buffer_size);
+ 
+ out:
+ 	return rc;
+ }
+ 
+ static void
+ qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn,
+ 				 struct qed_ll2_info *p_ll2_conn)
+ {
+ 	if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ 		return;
+ 
+ 	qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
+ 	qed_ooo_submit_rx_buffers(p_hwfn, p_ll2_conn);
+ }
+ 
+ static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn,
+ 					   struct qed_ll2_info *p_ll2_conn)
+ {
+ 	struct qed_ooo_buffer *p_buffer;
+ 
+ 	if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ 		return;
+ 
+ 	qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
+ 	while ((p_buffer = qed_ooo_get_free_buffer(p_hwfn,
+ 						   p_hwfn->p_ooo_info))) {
+ 		dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+ 				  p_buffer->rx_buffer_size,
+ 				  p_buffer->rx_buffer_virt_addr,
+ 				  p_buffer->rx_buffer_phys_addr);
+ 		kfree(p_buffer);
+ 	}
+ }
+ 
+ static void qed_ll2_stop_ooo(struct qed_dev *cdev)
+ {
+ 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+ 	u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
+ 
+ 	DP_VERBOSE(cdev, QED_MSG_STORAGE, "Stopping LL2 OOO queue [%02x]\n",
+ 		   *handle);
+ 
+ 	qed_ll2_terminate_connection(hwfn, *handle);
+ 	qed_ll2_release_connection(hwfn, *handle);
+ 	*handle = QED_LL2_UNUSED_HANDLE;
+ }
+ 
+ static int qed_ll2_start_ooo(struct qed_dev *cdev,
+ 			     struct qed_ll2_params *params)
+ {
+ 	struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+ 	u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
+ 	struct qed_ll2_info *ll2_info;
+ 	int rc;
+ 
+ 	ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
+ 	if (!ll2_info)
+ 		return -ENOMEM;
+ 	ll2_info->conn_type = QED_LL2_TYPE_ISCSI_OOO;
+ 	ll2_info->mtu = params->mtu;
+ 	ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
+ 	ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
+ 	ll2_info->tx_tc = OOO_LB_TC;
+ 	ll2_info->tx_dest = CORE_TX_DEST_LB;
+ 
+ 	rc = qed_ll2_acquire_connection(hwfn, ll2_info,
+ 					QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
+ 					handle);
+ 	kfree(ll2_info);
+ 	if (rc) {
+ 		DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n");
+ 		goto out;
+ 	}
  
- 		b_last = list_empty(&p_rx->active_descq);
+ 	rc = qed_ll2_establish_connection(hwfn, *handle);
+ 	if (rc) {
+ 		DP_INFO(cdev, "Failed to establist LL2 OOO connection\n");
+ 		goto fail;
  	}
+ 
+ 	return 0;
+ 
+ fail:
+ 	qed_ll2_release_connection(hwfn, *handle);
+ out:
+ 	*handle = QED_LL2_UNUSED_HANDLE;
+ 	return rc;
  }
+ #else /* IS_ENABLED(CONFIG_QED_ISCSI) */
+ static int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn,
+ 				     void *p_cookie) { return -EINVAL; }
+ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn,
+ 				     void *p_cookie) { return -EINVAL; }
+ static inline int
+ qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn,
+ 			       struct qed_ll2_info *p_ll2_info,
+ 			       u16 rx_num_ooo_buffers, u16 mtu) { return 0; }
+ static inline void
+ qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn,
+ 				 struct qed_ll2_info *p_ll2_conn) { return; }
+ static inline void
+ qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn,
+ 			       struct qed_ll2_info *p_ll2_conn) { return; }
+ static inline void qed_ll2_stop_ooo(struct qed_dev *cdev) { return; }
+ static inline int qed_ll2_start_ooo(struct qed_dev *cdev,
+ 				    struct qed_ll2_params *params)
+ 				    { return -EINVAL; }
+ #endif /* IS_ENABLED(CONFIG_QED_ISCSI) */
  
  static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn,
  				     struct qed_ll2_info *p_ll2_conn,
@@@ -588,7 -1043,8 +1043,8 @@@
  	p_ramrod->drop_ttl0_flg = p_ll2_conn->rx_drop_ttl0_flg;
  	p_ramrod->inner_vlan_removal_en = p_ll2_conn->rx_vlan_removal_en;
  	p_ramrod->queue_id = p_ll2_conn->queue_id;
- 	p_ramrod->main_func_queue = 1;
+ 	p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0
+ 									  : 1;
  
  	if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
  	    p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) {
@@@ -619,6 -1075,11 +1075,11 @@@ static int qed_sp_ll2_tx_queue_start(st
  	if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
  		return 0;
  
+ 	if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO)
+ 		p_ll2_conn->tx_stats_en = 0;
+ 	else
+ 		p_ll2_conn->tx_stats_en = 1;
+ 
  	/* Get SPQ entry */
  	memset(&init_data, 0, sizeof(init_data));
  	init_data.cid = p_ll2_conn->cid;
@@@ -636,7 -1097,6 +1097,6 @@@
  	p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn));
  	p_ramrod->sb_index = p_tx->tx_sb_index;
  	p_ramrod->mtu = cpu_to_le16(p_ll2_conn->mtu);
- 	p_ll2_conn->tx_stats_en = 1;
  	p_ramrod->stats_en = p_ll2_conn->tx_stats_en;
  	p_ramrod->stats_id = p_ll2_conn->tx_stats_id;
  
@@@ -860,9 -1320,19 +1320,19 @@@ int qed_ll2_acquire_connection(struct q
  	if (rc)
  		goto q_allocate_fail;
  
+ 	rc = qed_ll2_acquire_connection_ooo(p_hwfn, p_ll2_info,
+ 					    rx_num_desc * 2, p_params->mtu);
+ 	if (rc)
+ 		goto q_allocate_fail;
+ 
  	/* Register callbacks for the Rx/Tx queues */
- 	comp_rx_cb = qed_ll2_rxq_completion;
- 	comp_tx_cb = qed_ll2_txq_completion;
+ 	if (p_params->conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+ 		comp_rx_cb = qed_ll2_lb_rxq_completion;
+ 		comp_tx_cb = qed_ll2_lb_txq_completion;
+ 	} else {
+ 		comp_rx_cb = qed_ll2_rxq_completion;
+ 		comp_tx_cb = qed_ll2_txq_completion;
+ 	}
  
  	if (rx_num_desc) {
  		qed_int_register_cb(p_hwfn, comp_rx_cb,
@@@ -975,6 -1445,8 +1445,8 @@@ int qed_ll2_establish_connection(struc
  	if (p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE)
  		qed_wr(p_hwfn, p_hwfn->p_main_ptt, PRS_REG_USE_LIGHT_L2, 1);
  
+ 	qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn);
+ 
  	return rc;
  }
  
@@@ -1213,6 -1685,7 +1685,7 @@@ int qed_ll2_prepare_tx_packet(struct qe
  			      u16 vlan,
  			      u8 bd_flags,
  			      u16 l4_hdr_offset_w,
+ 			      enum qed_ll2_tx_dest e_tx_dest,
  			      enum qed_ll2_roce_flavor_type qed_roce_flavor,
  			      dma_addr_t first_frag,
  			      u16 first_frag_len, void *cookie, u8 notify_fw)
@@@ -1222,6 -1695,7 +1695,7 @@@
  	enum core_roce_flavor_type roce_flavor;
  	struct qed_ll2_tx_queue *p_tx;
  	struct qed_chain *p_tx_chain;
+ 	enum core_tx_dest tx_dest;
  	unsigned long flags;
  	int rc = 0;
  
@@@ -1252,6 -1726,8 +1726,8 @@@
  		goto out;
  	}
  
+ 	tx_dest = e_tx_dest == QED_LL2_TX_DEST_NW ? CORE_TX_DEST_NW :
+ 						    CORE_TX_DEST_LB;
  	if (qed_roce_flavor == QED_LL2_ROCE) {
  		roce_flavor = CORE_ROCE;
  	} else if (qed_roce_flavor == QED_LL2_RROCE) {
@@@ -1266,7 -1742,7 +1742,7 @@@
  				      num_of_bds, first_frag,
  				      first_frag_len, cookie, notify_fw);
  	qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp,
- 					 num_of_bds, CORE_TX_DEST_NW,
+ 					 num_of_bds, tx_dest,
  					 vlan, bd_flags, l4_hdr_offset_w,
  					 roce_flavor,
  					 first_frag, first_frag_len);
@@@ -1341,6 -1817,9 +1817,9 @@@ int qed_ll2_terminate_connection(struc
  		qed_ll2_rxq_flush(p_hwfn, connection_handle);
  	}
  
+ 	if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO)
+ 		qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
+ 
  	return rc;
  }
  
@@@ -1371,6 -1850,8 +1850,8 @@@ void qed_ll2_release_connection(struct 
  
  	qed_cxt_release_cid(p_hwfn, p_ll2_conn->cid);
  
+ 	qed_ll2_release_connection_ooo(p_hwfn, p_ll2_conn);
+ 
  	mutex_lock(&p_ll2_conn->mutex);
  	p_ll2_conn->b_active = false;
  	mutex_unlock(&p_ll2_conn->mutex);
@@@ -1517,6 -1998,7 +1998,7 @@@ static int qed_ll2_start(struct qed_de
  	enum qed_ll2_conn_type conn_type;
  	struct qed_ptt *p_ptt;
  	int rc, i;
+ 	u8 gsi_enable = 1;
  
  	/* Initialize LL2 locks & lists */
  	INIT_LIST_HEAD(&cdev->ll2->list);
@@@ -1548,6 -2030,7 +2030,7 @@@
  	switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
  	case QED_PCI_ISCSI:
  		conn_type = QED_LL2_TYPE_ISCSI;
+ 		gsi_enable = 0;
  		break;
  	case QED_PCI_ETH_ROCE:
  		conn_type = QED_LL2_TYPE_ROCE;
@@@ -1564,7 -2047,7 +2047,7 @@@
  	ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
  	ll2_info.tx_tc = 0;
  	ll2_info.tx_dest = CORE_TX_DEST_NW;
- 	ll2_info.gsi_enable = 1;
+ 	ll2_info.gsi_enable = gsi_enable;
  
  	rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
  					QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
@@@ -1611,6 -2094,17 +2094,17 @@@
  		goto release_terminate;
  	}
  
+ 	if (cdev->hwfns[0].hw_info.personality == QED_PCI_ISCSI &&
+ 	    cdev->hwfns[0].pf_params.iscsi_pf_params.ooo_enable) {
+ 		DP_VERBOSE(cdev, QED_MSG_STORAGE, "Starting OOO LL2 queue\n");
+ 		rc = qed_ll2_start_ooo(cdev, params);
+ 		if (rc) {
+ 			DP_INFO(cdev,
+ 				"Failed to initialize the OOO LL2 queue\n");
+ 			goto release_terminate;
+ 		}
+ 	}
+ 
  	p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev));
  	if (!p_ptt) {
  		DP_INFO(cdev, "Failed to acquire PTT\n");
@@@ -1660,6 -2154,10 +2154,10 @@@ static int qed_ll2_stop(struct qed_dev 
  	qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt);
  	eth_zero_addr(cdev->ll2_mac_address);
  
+ 	if (cdev->hwfns[0].hw_info.personality == QED_PCI_ISCSI &&
+ 	    cdev->hwfns[0].pf_params.iscsi_pf_params.ooo_enable)
+ 		qed_ll2_stop_ooo(cdev);
+ 
  	rc = qed_ll2_terminate_connection(QED_LEADING_HWFN(cdev),
  					  cdev->ll2->handle);
  	if (rc)
@@@ -1714,7 -2212,8 +2212,8 @@@ static int qed_ll2_start_xmit(struct qe
  	rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev),
  				       cdev->ll2->handle,
  				       1 + skb_shinfo(skb)->nr_frags,
- 				       vlan, flags, 0, 0 /* RoCE FLAVOR */,
+ 				       vlan, flags, 0, QED_LL2_TX_DEST_NW,
+ 				       0 /* RoCE FLAVOR */,
  				       mapping, skb->len, skb, 1);
  	if (rc)
  		goto err;
@@@ -1730,7 -2229,6 +2229,7 @@@
  						       mapping))) {
  				DP_NOTICE(cdev,
  					  "Unable to map frag - dropping packet\n");
 +				rc = -ENOMEM;
  				goto err;
  			}
  		} else {
diff --combined drivers/net/ethernet/smsc/smsc911x.c
index 65fca9c,be09573..9179cb4
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@@ -1956,11 -1956,6 +1956,6 @@@ static void smsc911x_ethtool_getdrvinfo
  		sizeof(info->bus_info));
  }
  
- static int smsc911x_ethtool_nwayreset(struct net_device *dev)
- {
- 	return phy_start_aneg(dev->phydev);
- }
- 
  static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev)
  {
  	struct smsc911x_data *pdata = netdev_priv(dev);
@@@ -2132,7 -2127,7 +2127,7 @@@ static int smsc911x_ethtool_set_eeprom(
  static const struct ethtool_ops smsc911x_ethtool_ops = {
  	.get_link = ethtool_op_get_link,
  	.get_drvinfo = smsc911x_ethtool_getdrvinfo,
- 	.nway_reset = smsc911x_ethtool_nwayreset,
+ 	.nway_reset = phy_ethtool_nway_reset,
  	.get_msglevel = smsc911x_ethtool_getmsglevel,
  	.set_msglevel = smsc911x_ethtool_setmsglevel,
  	.get_regs_len = smsc911x_ethtool_getregslen,
@@@ -2152,7 -2147,6 +2147,6 @@@ static const struct net_device_ops smsc
  	.ndo_get_stats		= smsc911x_get_stats,
  	.ndo_set_rx_mode	= smsc911x_set_multicast_list,
  	.ndo_do_ioctl		= smsc911x_do_ioctl,
- 	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_validate_addr	= eth_validate_addr,
  	.ndo_set_mac_address 	= smsc911x_set_mac_address,
  #ifdef CONFIG_NET_POLL_CONTROLLER
@@@ -2584,9 -2578,6 +2578,9 @@@ static int smsc911x_suspend(struct devi
  		PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ |
  		PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_);
  
 +	pm_runtime_disable(dev);
 +	pm_runtime_set_suspended(dev);
 +
  	return 0;
  }
  
@@@ -2596,9 -2587,6 +2590,9 @@@ static int smsc911x_resume(struct devic
  	struct smsc911x_data *pdata = netdev_priv(ndev);
  	unsigned int to = 100;
  
 +	pm_runtime_enable(dev);
 +	pm_runtime_resume(dev);
 +
  	/* Note 3.11 from the datasheet:
  	 * 	"When the LAN9220 is in a power saving state, a write of any
  	 * 	 data to the BYTE_TEST register will wake-up the device."
diff --combined drivers/net/usb/lan78xx.c
index f33460c,0c459e9..019f758
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@@ -30,13 -30,17 +30,17 @@@
  #include <linux/ipv6.h>
  #include <linux/mdio.h>
  #include <net/ip6_checksum.h>
+ #include <linux/interrupt.h>
+ #include <linux/irqdomain.h>
+ #include <linux/irq.h>
+ #include <linux/irqchip/chained_irq.h>
  #include <linux/microchipphy.h>
  #include "lan78xx.h"
  
  #define DRIVER_AUTHOR	"WOOJUNG HUH <woojung.huh at microchip.com>"
  #define DRIVER_DESC	"LAN78XX USB 3.0 Gigabit Ethernet Devices"
  #define DRIVER_NAME	"lan78xx"
- #define DRIVER_VERSION	"1.0.4"
+ #define DRIVER_VERSION	"1.0.5"
  
  #define TX_TIMEOUT_JIFFIES		(5 * HZ)
  #define THROTTLE_JIFFIES		(HZ / 8)
@@@ -89,6 -93,38 +93,38 @@@
  /* statistic update interval (mSec) */
  #define STAT_UPDATE_TIMER		(1 * 1000)
  
+ /* defines interrupts from interrupt EP */
+ #define MAX_INT_EP			(32)
+ #define INT_EP_INTEP			(31)
+ #define INT_EP_OTP_WR_DONE		(28)
+ #define INT_EP_EEE_TX_LPI_START		(26)
+ #define INT_EP_EEE_TX_LPI_STOP		(25)
+ #define INT_EP_EEE_RX_LPI		(24)
+ #define INT_EP_MAC_RESET_TIMEOUT	(23)
+ #define INT_EP_RDFO			(22)
+ #define INT_EP_TXE			(21)
+ #define INT_EP_USB_STATUS		(20)
+ #define INT_EP_TX_DIS			(19)
+ #define INT_EP_RX_DIS			(18)
+ #define INT_EP_PHY			(17)
+ #define INT_EP_DP			(16)
+ #define INT_EP_MAC_ERR			(15)
+ #define INT_EP_TDFU			(14)
+ #define INT_EP_TDFO			(13)
+ #define INT_EP_UTX			(12)
+ #define INT_EP_GPIO_11			(11)
+ #define INT_EP_GPIO_10			(10)
+ #define INT_EP_GPIO_9			(9)
+ #define INT_EP_GPIO_8			(8)
+ #define INT_EP_GPIO_7			(7)
+ #define INT_EP_GPIO_6			(6)
+ #define INT_EP_GPIO_5			(5)
+ #define INT_EP_GPIO_4			(4)
+ #define INT_EP_GPIO_3			(3)
+ #define INT_EP_GPIO_2			(2)
+ #define INT_EP_GPIO_1			(1)
+ #define INT_EP_GPIO_0			(0)
+ 
  static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = {
  	"RX FCS Errors",
  	"RX Alignment Errors",
@@@ -296,6 -332,15 +332,15 @@@ struct statstage 
  	struct lan78xx_statstage64	curr_stat;
  };
  
+ struct irq_domain_data {
+ 	struct irq_domain	*irqdomain;
+ 	unsigned int		phyirq;
+ 	struct irq_chip		*irqchip;
+ 	irq_flow_handler_t	irq_handler;
+ 	u32			irqenable;
+ 	struct mutex		irq_lock;		/* for irq bus access */
+ };
+ 
  struct lan78xx_net {
  	struct net_device	*net;
  	struct usb_device	*udev;
@@@ -351,6 -396,8 +396,8 @@@
  
  	int			delta;
  	struct statstage	stats;
+ 
+ 	struct irq_domain_data	domain_data;
  };
  
  /* use ethtool to change the level for any given device */
@@@ -1092,15 -1139,10 +1139,10 @@@ static int lan78xx_update_flowcontrol(s
  static int lan78xx_link_reset(struct lan78xx_net *dev)
  {
  	struct phy_device *phydev = dev->net->phydev;
- 	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ 	struct ethtool_link_ksettings ecmd;
  	int ladv, radv, ret;
  	u32 buf;
  
- 	/* clear PHY interrupt status */
- 	ret = phy_read(phydev, LAN88XX_INT_STS);
- 	if (unlikely(ret < 0))
- 		return -EIO;
- 
  	/* clear LAN78xx interrupt status */
  	ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_);
  	if (unlikely(ret < 0))
@@@ -1120,18 -1162,14 +1162,14 @@@
  		if (unlikely(ret < 0))
  			return -EIO;
  
- 		phy_mac_interrupt(phydev, 0);
- 
  		del_timer(&dev->stat_monitor);
  	} else if (phydev->link && !dev->link_on) {
  		dev->link_on = true;
  
- 		phy_ethtool_gset(phydev, &ecmd);
- 
- 		ret = phy_read(phydev, LAN88XX_INT_STS);
+ 		phy_ethtool_ksettings_get(phydev, &ecmd);
  
  		if (dev->udev->speed == USB_SPEED_SUPER) {
- 			if (ethtool_cmd_speed(&ecmd) == 1000) {
+ 			if (ecmd.base.speed == 1000) {
  				/* disable U2 */
  				ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
  				buf &= ~USB_CFG1_DEV_U2_INIT_EN_;
@@@ -1159,10 -1197,10 +1197,10 @@@
  
  		netif_dbg(dev, link, dev->net,
  			  "speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x",
- 			  ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv);
+ 			  ecmd.base.speed, ecmd.base.duplex, ladv, radv);
  
- 		ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv);
- 		phy_mac_interrupt(phydev, 1);
+ 		ret = lan78xx_update_flowcontrol(dev, ecmd.base.duplex, ladv,
+ 						 radv);
  
  		if (!timer_pending(&dev->stat_monitor)) {
  			dev->delta = 1;
@@@ -1201,7 -1239,10 +1239,10 @@@ static void lan78xx_status(struct lan78
  
  	if (intdata & INT_ENP_PHY_INT) {
  		netif_dbg(dev, link, dev->net, "PHY INTR: 0x%08x\n", intdata);
- 			  lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
+ 		lan78xx_defer_kevent(dev, EVENT_LINK_RESET);
+ 
+ 		if (dev->domain_data.phyirq > 0)
+ 			generic_handle_irq(dev->domain_data.phyirq);
  	} else
  		netdev_warn(dev->net,
  			    "unexpected interrupt: 0x%08x\n", intdata);
@@@ -1406,11 -1447,6 +1447,6 @@@ static u32 lan78xx_get_link(struct net_
  	return net->phydev->link;
  }
  
- static int lan78xx_nway_reset(struct net_device *net)
- {
- 	return phy_start_aneg(net->phydev);
- }
- 
  static void lan78xx_get_drvinfo(struct net_device *net,
  				struct ethtool_drvinfo *info)
  {
@@@ -1435,88 -1471,26 +1471,26 @@@ static void lan78xx_set_msglevel(struc
  	dev->msg_enable = level;
  }
  
- static int lan78xx_get_mdix_status(struct net_device *net)
- {
- 	struct phy_device *phydev = net->phydev;
- 	int buf;
- 
- 	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_1);
- 	buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- 	phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0);
- 
- 	return buf;
- }
- 
- static void lan78xx_set_mdix_status(struct net_device *net, __u8 mdix_ctrl)
- {
- 	struct lan78xx_net *dev = netdev_priv(net);
- 	struct phy_device *phydev = net->phydev;
- 	int buf;
- 
- 	if (mdix_ctrl == ETH_TP_MDI) {
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_1);
- 		buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- 		buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- 		phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- 			  buf | LAN88XX_EXT_MODE_CTRL_MDI_);
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_0);
- 	} else if (mdix_ctrl == ETH_TP_MDI_X) {
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_1);
- 		buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- 		buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- 		phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- 			  buf | LAN88XX_EXT_MODE_CTRL_MDI_X_);
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_0);
- 	} else if (mdix_ctrl == ETH_TP_MDI_AUTO) {
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_1);
- 		buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL);
- 		buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- 		phy_write(phydev, LAN88XX_EXT_MODE_CTRL,
- 			  buf | LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_);
- 		phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS,
- 			  LAN88XX_EXT_PAGE_SPACE_0);
- 	}
- 	dev->mdix_ctrl = mdix_ctrl;
- }
- 
- static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
+ static int lan78xx_get_link_ksettings(struct net_device *net,
+ 				      struct ethtool_link_ksettings *cmd)
  {
  	struct lan78xx_net *dev = netdev_priv(net);
  	struct phy_device *phydev = net->phydev;
  	int ret;
- 	int buf;
  
  	ret = usb_autopm_get_interface(dev->intf);
  	if (ret < 0)
  		return ret;
  
- 	ret = phy_ethtool_gset(phydev, cmd);
- 
- 	buf = lan78xx_get_mdix_status(net);
- 
- 	buf &= LAN88XX_EXT_MODE_CTRL_MDIX_MASK_;
- 	if (buf == LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_) {
- 		cmd->eth_tp_mdix = ETH_TP_MDI_AUTO;
- 		cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
- 	} else if (buf == LAN88XX_EXT_MODE_CTRL_MDI_) {
- 		cmd->eth_tp_mdix = ETH_TP_MDI;
- 		cmd->eth_tp_mdix_ctrl = ETH_TP_MDI;
- 	} else if (buf == LAN88XX_EXT_MODE_CTRL_MDI_X_) {
- 		cmd->eth_tp_mdix = ETH_TP_MDI_X;
- 		cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_X;
- 	}
+ 	ret = phy_ethtool_ksettings_get(phydev, cmd);
  
  	usb_autopm_put_interface(dev->intf);
  
  	return ret;
  }
  
- static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+ static int lan78xx_set_link_ksettings(struct net_device *net,
+ 				      const struct ethtool_link_ksettings *cmd)
  {
  	struct lan78xx_net *dev = netdev_priv(net);
  	struct phy_device *phydev = net->phydev;
@@@ -1527,14 -1501,10 +1501,10 @@@
  	if (ret < 0)
  		return ret;
  
- 	if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) {
- 		lan78xx_set_mdix_status(net, cmd->eth_tp_mdix_ctrl);
- 	}
- 
  	/* change speed & duplex */
- 	ret = phy_ethtool_sset(phydev, cmd);
+ 	ret = phy_ethtool_ksettings_set(phydev, cmd);
  
- 	if (!cmd->autoneg) {
+ 	if (!cmd->base.autoneg) {
  		/* force link down */
  		temp = phy_read(phydev, MII_BMCR);
  		phy_write(phydev, MII_BMCR, temp | BMCR_LOOPBACK);
@@@ -1552,9 -1522,9 +1522,9 @@@ static void lan78xx_get_pause(struct ne
  {
  	struct lan78xx_net *dev = netdev_priv(net);
  	struct phy_device *phydev = net->phydev;
- 	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ 	struct ethtool_link_ksettings ecmd;
  
- 	phy_ethtool_gset(phydev, &ecmd);
+ 	phy_ethtool_ksettings_get(phydev, &ecmd);
  
  	pause->autoneg = dev->fc_autoneg;
  
@@@ -1570,12 -1540,12 +1540,12 @@@ static int lan78xx_set_pause(struct net
  {
  	struct lan78xx_net *dev = netdev_priv(net);
  	struct phy_device *phydev = net->phydev;
- 	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ 	struct ethtool_link_ksettings ecmd;
  	int ret;
  
- 	phy_ethtool_gset(phydev, &ecmd);
+ 	phy_ethtool_ksettings_get(phydev, &ecmd);
  
- 	if (pause->autoneg && !ecmd.autoneg) {
+ 	if (pause->autoneg && !ecmd.base.autoneg) {
  		ret = -EINVAL;
  		goto exit;
  	}
@@@ -1587,13 -1557,21 +1557,21 @@@
  	if (pause->tx_pause)
  		dev->fc_request_control |= FLOW_CTRL_TX;
  
- 	if (ecmd.autoneg) {
+ 	if (ecmd.base.autoneg) {
  		u32 mii_adv;
+ 		u32 advertising;
  
- 		ecmd.advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ 		ethtool_convert_link_mode_to_legacy_u32(
+ 			&advertising, ecmd.link_modes.advertising);
+ 
+ 		advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
  		mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
- 		ecmd.advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
- 		phy_ethtool_sset(phydev, &ecmd);
+ 		advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+ 
+ 		ethtool_convert_legacy_u32_to_link_mode(
+ 			ecmd.link_modes.advertising, advertising);
+ 
+ 		phy_ethtool_ksettings_set(phydev, &ecmd);
  	}
  
  	dev->fc_autoneg = pause->autoneg;
@@@ -1605,12 -1583,10 +1583,10 @@@ exit
  
  static const struct ethtool_ops lan78xx_ethtool_ops = {
  	.get_link	= lan78xx_get_link,
- 	.nway_reset	= lan78xx_nway_reset,
+ 	.nway_reset	= phy_ethtool_nway_reset,
  	.get_drvinfo	= lan78xx_get_drvinfo,
  	.get_msglevel	= lan78xx_get_msglevel,
  	.set_msglevel	= lan78xx_set_msglevel,
- 	.get_settings	= lan78xx_get_settings,
- 	.set_settings	= lan78xx_set_settings,
  	.get_eeprom_len = lan78xx_ethtool_get_eeprom_len,
  	.get_eeprom	= lan78xx_ethtool_get_eeprom,
  	.set_eeprom	= lan78xx_ethtool_set_eeprom,
@@@ -1623,6 -1599,8 +1599,8 @@@
  	.set_eee	= lan78xx_set_eee,
  	.get_pauseparam	= lan78xx_get_pause,
  	.set_pauseparam	= lan78xx_set_pause,
+ 	.get_link_ksettings = lan78xx_get_link_ksettings,
+ 	.set_link_ksettings = lan78xx_set_link_ksettings,
  };
  
  static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@@ -1834,6 -1812,127 +1812,127 @@@ static void lan78xx_link_status_change(
  	}
  }
  
+ static int irq_map(struct irq_domain *d, unsigned int irq,
+ 		   irq_hw_number_t hwirq)
+ {
+ 	struct irq_domain_data *data = d->host_data;
+ 
+ 	irq_set_chip_data(irq, data);
+ 	irq_set_chip_and_handler(irq, data->irqchip, data->irq_handler);
+ 	irq_set_noprobe(irq);
+ 
+ 	return 0;
+ }
+ 
+ static void irq_unmap(struct irq_domain *d, unsigned int irq)
+ {
+ 	irq_set_chip_and_handler(irq, NULL, NULL);
+ 	irq_set_chip_data(irq, NULL);
+ }
+ 
+ static const struct irq_domain_ops chip_domain_ops = {
+ 	.map	= irq_map,
+ 	.unmap	= irq_unmap,
+ };
+ 
+ static void lan78xx_irq_mask(struct irq_data *irqd)
+ {
+ 	struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+ 
+ 	data->irqenable &= ~BIT(irqd_to_hwirq(irqd));
+ }
+ 
+ static void lan78xx_irq_unmask(struct irq_data *irqd)
+ {
+ 	struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+ 
+ 	data->irqenable |= BIT(irqd_to_hwirq(irqd));
+ }
+ 
+ static void lan78xx_irq_bus_lock(struct irq_data *irqd)
+ {
+ 	struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+ 
+ 	mutex_lock(&data->irq_lock);
+ }
+ 
+ static void lan78xx_irq_bus_sync_unlock(struct irq_data *irqd)
+ {
+ 	struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
+ 	struct lan78xx_net *dev =
+ 			container_of(data, struct lan78xx_net, domain_data);
+ 	u32 buf;
+ 	int ret;
+ 
+ 	/* call register access here because irq_bus_lock & irq_bus_sync_unlock
+ 	 * are only two callbacks executed in non-atomic contex.
+ 	 */
+ 	ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
+ 	if (buf != data->irqenable)
+ 		ret = lan78xx_write_reg(dev, INT_EP_CTL, data->irqenable);
+ 
+ 	mutex_unlock(&data->irq_lock);
+ }
+ 
+ static struct irq_chip lan78xx_irqchip = {
+ 	.name			= "lan78xx-irqs",
+ 	.irq_mask		= lan78xx_irq_mask,
+ 	.irq_unmask		= lan78xx_irq_unmask,
+ 	.irq_bus_lock		= lan78xx_irq_bus_lock,
+ 	.irq_bus_sync_unlock	= lan78xx_irq_bus_sync_unlock,
+ };
+ 
+ static int lan78xx_setup_irq_domain(struct lan78xx_net *dev)
+ {
+ 	struct device_node *of_node;
+ 	struct irq_domain *irqdomain;
+ 	unsigned int irqmap = 0;
+ 	u32 buf;
+ 	int ret = 0;
+ 
+ 	of_node = dev->udev->dev.parent->of_node;
+ 
+ 	mutex_init(&dev->domain_data.irq_lock);
+ 
+ 	lan78xx_read_reg(dev, INT_EP_CTL, &buf);
+ 	dev->domain_data.irqenable = buf;
+ 
+ 	dev->domain_data.irqchip = &lan78xx_irqchip;
+ 	dev->domain_data.irq_handler = handle_simple_irq;
+ 
+ 	irqdomain = irq_domain_add_simple(of_node, MAX_INT_EP, 0,
+ 					  &chip_domain_ops, &dev->domain_data);
+ 	if (irqdomain) {
+ 		/* create mapping for PHY interrupt */
+ 		irqmap = irq_create_mapping(irqdomain, INT_EP_PHY);
+ 		if (!irqmap) {
+ 			irq_domain_remove(irqdomain);
+ 
+ 			irqdomain = NULL;
+ 			ret = -EINVAL;
+ 		}
+ 	} else {
+ 		ret = -EINVAL;
+ 	}
+ 
+ 	dev->domain_data.irqdomain = irqdomain;
+ 	dev->domain_data.phyirq = irqmap;
+ 
+ 	return ret;
+ }
+ 
+ static void lan78xx_remove_irq_domain(struct lan78xx_net *dev)
+ {
+ 	if (dev->domain_data.phyirq > 0) {
+ 		irq_dispose_mapping(dev->domain_data.phyirq);
+ 
+ 		if (dev->domain_data.irqdomain)
+ 			irq_domain_remove(dev->domain_data.irqdomain);
+ 	}
+ 	dev->domain_data.phyirq = 0;
+ 	dev->domain_data.irqdomain = NULL;
+ }
+ 
  static int lan78xx_phy_init(struct lan78xx_net *dev)
  {
  	int ret;
@@@ -1846,15 -1945,15 +1945,15 @@@
  		return -EIO;
  	}
  
- 	/* Enable PHY interrupts.
- 	 * We handle our own interrupt
- 	 */
- 	ret = phy_read(phydev, LAN88XX_INT_STS);
- 	ret = phy_write(phydev, LAN88XX_INT_MASK,
- 			LAN88XX_INT_MASK_MDINTPIN_EN_ |
- 			LAN88XX_INT_MASK_LINK_CHANGE_);
+ 	/* if phyirq is not set, use polling mode in phylib */
+ 	if (dev->domain_data.phyirq > 0)
+ 		phydev->irq = dev->domain_data.phyirq;
+ 	else
+ 		phydev->irq = 0;
+ 	netdev_dbg(dev->net, "phydev->irq = %d\n", phydev->irq);
  
- 	phydev->irq = PHY_IGNORE_INTERRUPT;
+ 	/* set to AUTOMDIX */
+ 	phydev->mdix = ETH_TP_MDI_AUTO;
  
  	ret = phy_connect_direct(dev->net, phydev,
  				 lan78xx_link_status_change,
@@@ -1865,9 -1964,6 +1964,6 @@@
  		return -EIO;
  	}
  
- 	/* set to AUTOMDIX */
- 	lan78xx_set_mdix_status(dev->net, ETH_TP_MDI_AUTO);
- 
  	/* MAC doesn't support 1000T Half */
  	phydev->supported &= ~SUPPORTED_1000baseT_Half;
  
@@@ -1970,11 -2066,6 +2066,6 @@@ static int lan78xx_change_mtu(struct ne
  	int old_rx_urb_size = dev->rx_urb_size;
  	int ret;
  
- 	if (new_mtu > MAX_SINGLE_PACKET_SIZE)
- 		return -EINVAL;
- 
- 	if (new_mtu <= 0)
- 		return -EINVAL;
  	/* no second zero-length packet read wanted after mtu-sized packets */
  	if ((ll_mtu % dev->maxpacket) == 0)
  		return -EDOM;
@@@ -2250,11 -2341,6 +2341,6 @@@ static int lan78xx_reset(struct lan78xx
  	buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
  	ret = lan78xx_write_reg(dev, MAC_CR, buf);
  
- 	/* enable PHY interrupts */
- 	ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf);
- 	buf |= INT_ENP_PHY_INT;
- 	ret = lan78xx_write_reg(dev, INT_EP_CTL, buf);
- 
  	ret = lan78xx_read_reg(dev, MAC_TX, &buf);
  	buf |= MAC_TX_TXEN_;
  	ret = lan78xx_write_reg(dev, MAC_TX, buf);
@@@ -2663,6 -2749,14 +2749,14 @@@ static int lan78xx_bind(struct lan78xx_
  
  	dev->net->hw_features = dev->net->features;
  
+ 	ret = lan78xx_setup_irq_domain(dev);
+ 	if (ret < 0) {
+ 		netdev_warn(dev->net,
+ 			    "lan78xx_setup_irq_domain() failed : %d", ret);
+ 		kfree(pdata);
+ 		return ret;
+ 	}
+ 
  	/* Init all registers */
  	ret = lan78xx_reset(dev);
  
@@@ -2679,6 -2773,8 +2773,8 @@@ static void lan78xx_unbind(struct lan78
  {
  	struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]);
  
+ 	lan78xx_remove_irq_domain(dev);
+ 
  	lan78xx_remove_mdio(dev);
  
  	if (pdata) {
@@@ -3378,6 -3474,9 +3474,9 @@@ static int lan78xx_probe(struct usb_int
  	if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len))
  		netdev->mtu = dev->hard_mtu - netdev->hard_header_len;
  
+ 	/* MTU range: 68 - 9000 */
+ 	netdev->max_mtu = MAX_SINGLE_PACKET_SIZE;
+ 
  	dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0;
  	dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1;
  	dev->ep_intr = (intf->cur_altsetting)->endpoint + 2;
@@@ -3395,7 -3494,6 +3494,7 @@@
  	if (buf) {
  		dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL);
  		if (!dev->urb_intr) {
 +			ret = -ENOMEM;
  			kfree(buf);
  			goto out3;
  		} else {
diff --combined drivers/thermal/thermal_core.c
index 7daffc1,911fd96..641faab
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@@ -5,9 -5,22 +5,9 @@@
   *  Copyright (C) 2008 Zhang Rui <rui.zhang at intel.com>
   *  Copyright (C) 2008 Sujith Thomas <sujith.thomas at intel.com>
   *
 - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 - *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; version 2 of the License.
 - *
 - *  This program is distributed in the hope that it will be useful, but
 - *  WITHOUT ANY WARRANTY; without even the implied warranty of
 - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - *  General Public License for more details.
 - *
 - *  You should have received a copy of the GNU General Public License along
 - *  with this program; if not, write to the Free Software Foundation, Inc.,
 - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 - *
 - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@@ -51,13 -64,6 +51,13 @@@ static atomic_t in_suspend
  
  static struct thermal_governor *def_governor;
  
 +/*
 + * Governor section: set of functions to handle thermal governors
 + *
 + * Functions to help in the life cycle of thermal governors within
 + * the thermal core and by the thermal governor code.
 + */
 +
  static struct thermal_governor *__find_governor(const char *name)
  {
  	struct thermal_governor *pos;
@@@ -136,16 -142,11 +136,16 @@@ int thermal_register_governor(struct th
  	mutex_lock(&thermal_governor_lock);
  
  	err = -EBUSY;
 -	if (__find_governor(governor->name) == NULL) {
 +	if (!__find_governor(governor->name)) {
 +		bool match_default;
 +
  		err = 0;
  		list_add(&governor->governor_list, &thermal_governor_list);
 -		if (!def_governor && !strncmp(governor->name,
 -			DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
 +		match_default = !strncmp(governor->name,
 +					 DEFAULT_THERMAL_GOVERNOR,
 +					 THERMAL_NAME_LENGTH);
 +
 +		if (!def_governor && match_default)
  			def_governor = governor;
  	}
  
@@@ -187,14 -188,14 +187,14 @@@ void thermal_unregister_governor(struc
  
  	mutex_lock(&thermal_governor_lock);
  
 -	if (__find_governor(governor->name) == NULL)
 +	if (!__find_governor(governor->name))
  		goto exit;
  
  	mutex_lock(&thermal_list_lock);
  
  	list_for_each_entry(pos, &thermal_tz_list, node) {
  		if (!strncasecmp(pos->governor->name, governor->name,
 -						THERMAL_NAME_LENGTH))
 +				 THERMAL_NAME_LENGTH))
  			thermal_set_governor(pos, NULL);
  	}
  
@@@ -202,92 -203,195 +202,92 @@@
  	list_del(&governor->governor_list);
  exit:
  	mutex_unlock(&thermal_governor_lock);
 -	return;
 -}
 -
 -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 -{
 -	int ret;
 -
 -	if (lock)
 -		mutex_lock(lock);
 -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
 -	if (lock)
 -		mutex_unlock(lock);
 -	if (unlikely(ret < 0))
 -		return ret;
 -	*id = ret;
 -	return 0;
 -}
 -
 -static void release_idr(struct idr *idr, struct mutex *lock, int id)
 -{
 -	if (lock)
 -		mutex_lock(lock);
 -	idr_remove(idr, id);
 -	if (lock)
 -		mutex_unlock(lock);
 -}
 -
 -int get_tz_trend(struct thermal_zone_device *tz, int trip)
 -{
 -	enum thermal_trend trend;
 -
 -	if (tz->emul_temperature || !tz->ops->get_trend ||
 -	    tz->ops->get_trend(tz, trip, &trend)) {
 -		if (tz->temperature > tz->last_temperature)
 -			trend = THERMAL_TREND_RAISING;
 -		else if (tz->temperature < tz->last_temperature)
 -			trend = THERMAL_TREND_DROPPING;
 -		else
 -			trend = THERMAL_TREND_STABLE;
 -	}
 -
 -	return trend;
  }
 -EXPORT_SYMBOL(get_tz_trend);
  
 -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
 -			struct thermal_cooling_device *cdev, int trip)
 +int thermal_zone_device_set_policy(struct thermal_zone_device *tz,
 +				   char *policy)
  {
 -	struct thermal_instance *pos = NULL;
 -	struct thermal_instance *target_instance = NULL;
 +	struct thermal_governor *gov;
 +	int ret = -EINVAL;
  
 +	mutex_lock(&thermal_governor_lock);
  	mutex_lock(&tz->lock);
 -	mutex_lock(&cdev->lock);
  
 -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
 -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
 -			target_instance = pos;
 -			break;
 -		}
 -	}
 +	gov = __find_governor(strim(policy));
 +	if (!gov)
 +		goto exit;
  
 -	mutex_unlock(&cdev->lock);
 -	mutex_unlock(&tz->lock);
 +	ret = thermal_set_governor(tz, gov);
  
 -	return target_instance;
 -}
 -EXPORT_SYMBOL(get_thermal_instance);
 +exit:
 +	mutex_unlock(&tz->lock);
 +	mutex_unlock(&thermal_governor_lock);
  
 -static void print_bind_err_msg(struct thermal_zone_device *tz,
 -			struct thermal_cooling_device *cdev, int ret)
 -{
 -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
 -				tz->type, cdev->type, ret);
 +	return ret;
  }
  
 -static void __bind(struct thermal_zone_device *tz, int mask,
 -			struct thermal_cooling_device *cdev,
 -			unsigned long *limits,
 -			unsigned int weight)
 +int thermal_build_list_of_policies(char *buf)
  {
 -	int i, ret;
 +	struct thermal_governor *pos;
 +	ssize_t count = 0;
 +	ssize_t size = PAGE_SIZE;
  
 -	for (i = 0; i < tz->trips; i++) {
 -		if (mask & (1 << i)) {
 -			unsigned long upper, lower;
 +	mutex_lock(&thermal_governor_lock);
  
 -			upper = THERMAL_NO_LIMIT;
 -			lower = THERMAL_NO_LIMIT;
 -			if (limits) {
 -				lower = limits[i * 2];
 -				upper = limits[i * 2 + 1];
 -			}
 -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
 -							       upper, lower,
 -							       weight);
 -			if (ret)
 -				print_bind_err_msg(tz, cdev, ret);
 -		}
 +	list_for_each_entry(pos, &thermal_governor_list, governor_list) {
 +		size = PAGE_SIZE - count;
 +		count += scnprintf(buf + count, size, "%s ", pos->name);
  	}
 -}
 +	count += scnprintf(buf + count, size, "\n");
  
 -static void __unbind(struct thermal_zone_device *tz, int mask,
 -			struct thermal_cooling_device *cdev)
 -{
 -	int i;
 +	mutex_unlock(&thermal_governor_lock);
  
 -	for (i = 0; i < tz->trips; i++)
 -		if (mask & (1 << i))
 -			thermal_zone_unbind_cooling_device(tz, i, cdev);
 +	return count;
  }
  
 -static void bind_cdev(struct thermal_cooling_device *cdev)
 +static int __init thermal_register_governors(void)
  {
 -	int i, ret;
 -	const struct thermal_zone_params *tzp;
 -	struct thermal_zone_device *pos = NULL;
 -
 -	mutex_lock(&thermal_list_lock);
 +	int result;
  
 -	list_for_each_entry(pos, &thermal_tz_list, node) {
 -		if (!pos->tzp && !pos->ops->bind)
 -			continue;
 +	result = thermal_gov_step_wise_register();
 +	if (result)
 +		return result;
  
 -		if (pos->ops->bind) {
 -			ret = pos->ops->bind(pos, cdev);
 -			if (ret)
 -				print_bind_err_msg(pos, cdev, ret);
 -			continue;
 -		}
 +	result = thermal_gov_fair_share_register();
 +	if (result)
 +		return result;
  
 -		tzp = pos->tzp;
 -		if (!tzp || !tzp->tbp)
 -			continue;
 +	result = thermal_gov_bang_bang_register();
 +	if (result)
 +		return result;
  
 -		for (i = 0; i < tzp->num_tbps; i++) {
 -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
 -				continue;
 -			if (tzp->tbp[i].match(pos, cdev))
 -				continue;
 -			tzp->tbp[i].cdev = cdev;
 -			__bind(pos, tzp->tbp[i].trip_mask, cdev,
 -			       tzp->tbp[i].binding_limits,
 -			       tzp->tbp[i].weight);
 -		}
 -	}
 +	result = thermal_gov_user_space_register();
 +	if (result)
 +		return result;
  
 -	mutex_unlock(&thermal_list_lock);
 +	return thermal_gov_power_allocator_register();
  }
  
 -static void bind_tz(struct thermal_zone_device *tz)
 +static void thermal_unregister_governors(void)
  {
 -	int i, ret;
 -	struct thermal_cooling_device *pos = NULL;
 -	const struct thermal_zone_params *tzp = tz->tzp;
 -
 -	if (!tzp && !tz->ops->bind)
 -		return;
 -
 -	mutex_lock(&thermal_list_lock);
 -
 -	/* If there is ops->bind, try to use ops->bind */
 -	if (tz->ops->bind) {
 -		list_for_each_entry(pos, &thermal_cdev_list, node) {
 -			ret = tz->ops->bind(tz, pos);
 -			if (ret)
 -				print_bind_err_msg(tz, pos, ret);
 -		}
 -		goto exit;
 -	}
 -
 -	if (!tzp || !tzp->tbp)
 -		goto exit;
 -
 -	list_for_each_entry(pos, &thermal_cdev_list, node) {
 -		for (i = 0; i < tzp->num_tbps; i++) {
 -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
 -				continue;
 -			if (tzp->tbp[i].match(tz, pos))
 -				continue;
 -			tzp->tbp[i].cdev = pos;
 -			__bind(tz, tzp->tbp[i].trip_mask, pos,
 -			       tzp->tbp[i].binding_limits,
 -			       tzp->tbp[i].weight);
 -		}
 -	}
 -exit:
 -	mutex_unlock(&thermal_list_lock);
 +	thermal_gov_step_wise_unregister();
 +	thermal_gov_fair_share_unregister();
 +	thermal_gov_bang_bang_unregister();
 +	thermal_gov_user_space_unregister();
 +	thermal_gov_power_allocator_unregister();
  }
  
 +/*
 + * Zone update section: main control loop applied to each zone while monitoring
 + *
 + * in polling mode. The monitoring is done using a workqueue.
 + * Same update may be done on a zone by calling thermal_zone_device_update().
 + *
 + * An update means:
 + * - Non-critical trips will invoke the governor responsible for that zone;
 + * - Hot trips will produce a notification to userspace;
 + * - Critical trip point will cause a system shutdown.
 + */
  static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
  					    int delay)
  {
@@@ -316,15 -420,14 +316,15 @@@ static void monitor_thermal_zone(struc
  }
  
  static void handle_non_critical_trips(struct thermal_zone_device *tz,
 -			int trip, enum thermal_trip_type trip_type)
 +				      int trip,
 +				      enum thermal_trip_type trip_type)
  {
  	tz->governor ? tz->governor->throttle(tz, trip) :
  		       def_governor->throttle(tz, trip);
  }
  
  static void handle_critical_trips(struct thermal_zone_device *tz,
 -				int trip, enum thermal_trip_type trip_type)
 +				  int trip, enum thermal_trip_type trip_type)
  {
  	int trip_temp;
  
@@@ -368,6 -471,105 +368,6 @@@ static void handle_thermal_trip(struct 
  	monitor_thermal_zone(tz);
  }
  
 -/**
 - * thermal_zone_get_temp() - returns the temperature of a thermal zone
 - * @tz: a valid pointer to a struct thermal_zone_device
 - * @temp: a valid pointer to where to store the resulting temperature.
 - *
 - * When a valid thermal zone reference is passed, it will fetch its
 - * temperature and fill @temp.
 - *
 - * Return: On success returns 0, an error code otherwise
 - */
 -int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
 -{
 -	int ret = -EINVAL;
 -	int count;
 -	int crit_temp = INT_MAX;
 -	enum thermal_trip_type type;
 -
 -	if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
 -		goto exit;
 -
 -	mutex_lock(&tz->lock);
 -
 -	ret = tz->ops->get_temp(tz, temp);
 -
 -	if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
 -		for (count = 0; count < tz->trips; count++) {
 -			ret = tz->ops->get_trip_type(tz, count, &type);
 -			if (!ret && type == THERMAL_TRIP_CRITICAL) {
 -				ret = tz->ops->get_trip_temp(tz, count,
 -						&crit_temp);
 -				break;
 -			}
 -		}
 -
 -		/*
 -		 * Only allow emulating a temperature when the real temperature
 -		 * is below the critical temperature so that the emulation code
 -		 * cannot hide critical conditions.
 -		 */
 -		if (!ret && *temp < crit_temp)
 -			*temp = tz->emul_temperature;
 -	}
 - 
 -	mutex_unlock(&tz->lock);
 -exit:
 -	return ret;
 -}
 -EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 -
 -void thermal_zone_set_trips(struct thermal_zone_device *tz)
 -{
 -	int low = -INT_MAX;
 -	int high = INT_MAX;
 -	int trip_temp, hysteresis;
 -	int i, ret;
 -
 -	mutex_lock(&tz->lock);
 -
 -	if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
 -		goto exit;
 -
 -	for (i = 0; i < tz->trips; i++) {
 -		int trip_low;
 -
 -		tz->ops->get_trip_temp(tz, i, &trip_temp);
 -		tz->ops->get_trip_hyst(tz, i, &hysteresis);
 -
 -		trip_low = trip_temp - hysteresis;
 -
 -		if (trip_low < tz->temperature && trip_low > low)
 -			low = trip_low;
 -
 -		if (trip_temp > tz->temperature && trip_temp < high)
 -			high = trip_temp;
 -	}
 -
 -	/* No need to change trip points */
 -	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
 -		goto exit;
 -
 -	tz->prev_low_trip = low;
 -	tz->prev_high_trip = high;
 -
 -	dev_dbg(&tz->device,
 -		"new temperature boundaries: %d < x < %d\n", low, high);
 -
 -	/*
 -	 * Set a temperature window. When this window is left the driver
 -	 * must inform the thermal core via thermal_zone_device_update.
 -	 */
 -	ret = tz->ops->set_trips(tz, low, high);
 -	if (ret)
 -		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
 -
 -exit:
 -	mutex_unlock(&tz->lock);
 -}
 -EXPORT_SYMBOL_GPL(thermal_zone_set_trips);
 -
  static void update_temperature(struct thermal_zone_device *tz)
  {
  	int temp, ret;
@@@ -427,24 -629,6 +427,24 @@@ void thermal_zone_device_update(struct 
  }
  EXPORT_SYMBOL_GPL(thermal_zone_device_update);
  
 +/**
 + * thermal_notify_framework - Sensor drivers use this API to notify framework
 + * @tz:		thermal zone device
 + * @trip:	indicates which trip point has been crossed
 + *
 + * This function handles the trip events from sensor drivers. It starts
 + * throttling the cooling devices according to the policy configured.
 + * For CRITICAL and HOT trip points, this notifies the respective drivers,
 + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
 + * The throttling policy is based on the configured platform data; if no
 + * platform data is provided, this uses the step_wise throttling policy.
 + */
 +void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
 +{
 +	handle_thermal_trip(tz, trip);
 +}
 +EXPORT_SYMBOL_GPL(thermal_notify_framework);
 +
  static void thermal_zone_device_check(struct work_struct *work)
  {
  	struct thermal_zone_device *tz = container_of(work, struct
@@@ -453,12 -637,445 +453,12 @@@
  	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
  }
  
 -/* sys I/F for thermal zone */
 -
 -#define to_thermal_zone(_dev) \
 -	container_of(_dev, struct thermal_zone_device, device)
 -
 -static ssize_t
 -type_show(struct device *dev, struct device_attribute *attr, char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -
 -	return sprintf(buf, "%s\n", tz->type);
 -}
 -
 -static ssize_t
 -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int temperature, ret;
 -
 -	ret = thermal_zone_get_temp(tz, &temperature);
 -
 -	if (ret)
 -		return ret;
 -
 -	return sprintf(buf, "%d\n", temperature);
 -}
 -
 -static ssize_t
 -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	enum thermal_device_mode mode;
 -	int result;
 -
 -	if (!tz->ops->get_mode)
 -		return -EPERM;
 -
 -	result = tz->ops->get_mode(tz, &mode);
 -	if (result)
 -		return result;
 -
 -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 -		       : "disabled");
 -}
 -
 -static ssize_t
 -mode_store(struct device *dev, struct device_attribute *attr,
 -	   const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int result;
 -
 -	if (!tz->ops->set_mode)
 -		return -EPERM;
 -
 -	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
 -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
 -	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
 -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
 -	else
 -		result = -EINVAL;
 -
 -	if (result)
 -		return result;
 -
 -	return count;
 -}
 -
 -static ssize_t
 -trip_point_type_show(struct device *dev, struct device_attribute *attr,
 -		     char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	enum thermal_trip_type type;
 -	int trip, result;
 -
 -	if (!tz->ops->get_trip_type)
 -		return -EPERM;
 -
 -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
 -		return -EINVAL;
 -
 -	result = tz->ops->get_trip_type(tz, trip, &type);
 -	if (result)
 -		return result;
 -
 -	switch (type) {
 -	case THERMAL_TRIP_CRITICAL:
 -		return sprintf(buf, "critical\n");
 -	case THERMAL_TRIP_HOT:
 -		return sprintf(buf, "hot\n");
 -	case THERMAL_TRIP_PASSIVE:
 -		return sprintf(buf, "passive\n");
 -	case THERMAL_TRIP_ACTIVE:
 -		return sprintf(buf, "active\n");
 -	default:
 -		return sprintf(buf, "unknown\n");
 -	}
 -}
 -
 -static ssize_t
 -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
 -		     const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int trip, ret;
 -	int temperature;
 -
 -	if (!tz->ops->set_trip_temp)
 -		return -EPERM;
 -
 -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 -		return -EINVAL;
 -
 -	if (kstrtoint(buf, 10, &temperature))
 -		return -EINVAL;
 -
 -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
 -	if (ret)
 -		return ret;
 -
 -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 -
 -	return count;
 -}
 -
 -static ssize_t
 -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
 -		     char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int trip, ret;
 -	int temperature;
 -
 -	if (!tz->ops->get_trip_temp)
 -		return -EPERM;
 -
 -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 -		return -EINVAL;
 -
 -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
 -
 -	if (ret)
 -		return ret;
 -
 -	return sprintf(buf, "%d\n", temperature);
 -}
 -
 -static ssize_t
 -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
 -			const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int trip, ret;
 -	int temperature;
 -
 -	if (!tz->ops->set_trip_hyst)
 -		return -EPERM;
 -
 -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
 -		return -EINVAL;
 -
 -	if (kstrtoint(buf, 10, &temperature))
 -		return -EINVAL;
 -
 -	/*
 -	 * We are not doing any check on the 'temperature' value
 -	 * here. The driver implementing 'set_trip_hyst' has to
 -	 * take care of this.
 -	 */
 -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 -
 -	if (!ret)
 -		thermal_zone_set_trips(tz);
 -
 -	return ret ? ret : count;
 -}
 -
 -static ssize_t
 -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
 -			char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int trip, ret;
 -	int temperature;
 -
 -	if (!tz->ops->get_trip_hyst)
 -		return -EPERM;
 -
 -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
 -		return -EINVAL;
 -
 -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
 -
 -	return ret ? ret : sprintf(buf, "%d\n", temperature);
 -}
 -
 -static ssize_t
 -passive_store(struct device *dev, struct device_attribute *attr,
 -		    const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	struct thermal_cooling_device *cdev = NULL;
 -	int state;
 -
 -	if (!sscanf(buf, "%d\n", &state))
 -		return -EINVAL;
 -
 -	/* sanity check: values below 1000 millicelcius don't make sense
 -	 * and can cause the system to go into a thermal heart attack
 -	 */
 -	if (state && state < 1000)
 -		return -EINVAL;
 -
 -	if (state && !tz->forced_passive) {
 -		mutex_lock(&thermal_list_lock);
 -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
 -			if (!strncmp("Processor", cdev->type,
 -				     sizeof("Processor")))
 -				thermal_zone_bind_cooling_device(tz,
 -						THERMAL_TRIPS_NONE, cdev,
 -						THERMAL_NO_LIMIT,
 -						THERMAL_NO_LIMIT,
 -						THERMAL_WEIGHT_DEFAULT);
 -		}
 -		mutex_unlock(&thermal_list_lock);
 -		if (!tz->passive_delay)
 -			tz->passive_delay = 1000;
 -	} else if (!state && tz->forced_passive) {
 -		mutex_lock(&thermal_list_lock);
 -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
 -			if (!strncmp("Processor", cdev->type,
 -				     sizeof("Processor")))
 -				thermal_zone_unbind_cooling_device(tz,
 -								   THERMAL_TRIPS_NONE,
 -								   cdev);
 -		}
 -		mutex_unlock(&thermal_list_lock);
 -		tz->passive_delay = 0;
 -	}
 -
 -	tz->forced_passive = state;
 -
 -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 -
 -	return count;
 -}
 -
 -static ssize_t
 -passive_show(struct device *dev, struct device_attribute *attr,
 -		   char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -
 -	return sprintf(buf, "%d\n", tz->forced_passive);
 -}
 -
 -static ssize_t
 -policy_store(struct device *dev, struct device_attribute *attr,
 -		    const char *buf, size_t count)
 -{
 -	int ret = -EINVAL;
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	struct thermal_governor *gov;
 -	char name[THERMAL_NAME_LENGTH];
 -
 -	snprintf(name, sizeof(name), "%s", buf);
 -
 -	mutex_lock(&thermal_governor_lock);
 -	mutex_lock(&tz->lock);
 -
 -	gov = __find_governor(strim(name));
 -	if (!gov)
 -		goto exit;
 -
 -	ret = thermal_set_governor(tz, gov);
 -	if (!ret)
 -		ret = count;
 -
 -exit:
 -	mutex_unlock(&tz->lock);
 -	mutex_unlock(&thermal_governor_lock);
 -	return ret;
 -}
 -
 -static ssize_t
 -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -
 -	return sprintf(buf, "%s\n", tz->governor->name);
 -}
 -
 -static ssize_t
 -available_policies_show(struct device *dev, struct device_attribute *devattr,
 -			char *buf)
 -{
 -	struct thermal_governor *pos;
 -	ssize_t count = 0;
 -	ssize_t size = PAGE_SIZE;
 -
 -	mutex_lock(&thermal_governor_lock);
 -
 -	list_for_each_entry(pos, &thermal_governor_list, governor_list) {
 -		size = PAGE_SIZE - count;
 -		count += scnprintf(buf + count, size, "%s ", pos->name);
 -	}
 -	count += scnprintf(buf + count, size, "\n");
 -
 -	mutex_unlock(&thermal_governor_lock);
 -
 -	return count;
 -}
 -
 -static ssize_t
 -emul_temp_store(struct device *dev, struct device_attribute *attr,
 -		     const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	int ret = 0;
 -	int temperature;
 -
 -	if (kstrtoint(buf, 10, &temperature))
 -		return -EINVAL;
 -
 -	if (!tz->ops->set_emul_temp) {
 -		mutex_lock(&tz->lock);
 -		tz->emul_temperature = temperature;
 -		mutex_unlock(&tz->lock);
 -	} else {
 -		ret = tz->ops->set_emul_temp(tz, temperature);
 -	}
 -
 -	if (!ret)
 -		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 -
 -	return ret ? ret : count;
 -}
 -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
 -
 -static ssize_t
 -sustainable_power_show(struct device *dev, struct device_attribute *devattr,
 -		       char *buf)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -
 -	if (tz->tzp)
 -		return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
 -	else
 -		return -EIO;
 -}
 -
 -static ssize_t
 -sustainable_power_store(struct device *dev, struct device_attribute *devattr,
 -			const char *buf, size_t count)
 -{
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);
 -	u32 sustainable_power;
 -
 -	if (!tz->tzp)
 -		return -EIO;
 -
 -	if (kstrtou32(buf, 10, &sustainable_power))
 -		return -EINVAL;
 -
 -	tz->tzp->sustainable_power = sustainable_power;
 -
 -	return count;
 -}
 -static DEVICE_ATTR(sustainable_power, S_IWUSR | S_IRUGO, sustainable_power_show,
 -		sustainable_power_store);
 -
 -#define create_s32_tzp_attr(name)					\
 -	static ssize_t							\
 -	name##_show(struct device *dev, struct device_attribute *devattr, \
 -		char *buf)						\
 -	{								\
 -	struct thermal_zone_device *tz = to_thermal_zone(dev);		\
 -									\
 -	if (tz->tzp)							\
 -		return sprintf(buf, "%d\n", tz->tzp->name);		\
 -	else								\
 -		return -EIO;						\
 -	}								\
 -									\
 -	static ssize_t							\
 -	name##_store(struct device *dev, struct device_attribute *devattr, \
 -		const char *buf, size_t count)				\
 -	{								\
 -		struct thermal_zone_device *tz = to_thermal_zone(dev);	\
 -		s32 value;						\
 -									\
 -		if (!tz->tzp)						\
 -			return -EIO;					\
 -									\
 -		if (kstrtos32(buf, 10, &value))				\
 -			return -EINVAL;					\
 -									\
 -		tz->tzp->name = value;					\
 -									\
 -		return count;						\
 -	}								\
 -	static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store)
 -
 -create_s32_tzp_attr(k_po);
 -create_s32_tzp_attr(k_pu);
 -create_s32_tzp_attr(k_i);
 -create_s32_tzp_attr(k_d);
 -create_s32_tzp_attr(integral_cutoff);
 -create_s32_tzp_attr(slope);
 -create_s32_tzp_attr(offset);
 -#undef create_s32_tzp_attr
 -
 -static struct device_attribute *dev_tzp_attrs[] = {
 -	&dev_attr_sustainable_power,
 -	&dev_attr_k_po,
 -	&dev_attr_k_pu,
 -	&dev_attr_k_i,
 -	&dev_attr_k_d,
 -	&dev_attr_integral_cutoff,
 -	&dev_attr_slope,
 -	&dev_attr_offset,
 -};
 -
 -static int create_tzp_attrs(struct device *dev)
 -{
 -	int i;
 -
 -	for (i = 0; i < ARRAY_SIZE(dev_tzp_attrs); i++) {
 -		int ret;
 -		struct device_attribute *dev_attr = dev_tzp_attrs[i];
 -
 -		ret = device_create_file(dev, dev_attr);
 -		if (ret)
 -			return ret;
 -	}
 -
 -	return 0;
 -}
 +/*
 + * Power actor section: interface to power actors to estimate power
 + *
 + * Set of functions used to interact to cooling devices that know
 + * how to estimate their devices power consumption.
 + */
  
  /**
   * power_actor_get_max_power() - get the maximum power that a cdev can consume
@@@ -510,13 -1127,12 +510,13 @@@ int power_actor_get_min_power(struct th
  }
  
  /**
 - * power_actor_set_power() - limit the maximum power that a cooling device can consume
 + * power_actor_set_power() - limit the maximum power a cooling device consumes
   * @cdev:	pointer to &thermal_cooling_device
   * @instance:	thermal instance to update
   * @power:	the power in milliwatts
   *
 - * Set the cooling device to consume at most @power milliwatts.
 + * Set the cooling device to consume at most @power milliwatts. The limit is
 + * expected to be a cap at the maximum power consumption.
   *
   * Return: 0 on success, -EINVAL if the cooling device does not
   * implement the power actor API or -E* for other failures.
@@@ -543,75 -1159,143 +543,75 @@@ int power_actor_set_power(struct therma
  	return 0;
  }
  
 -static DEVICE_ATTR(type, 0444, type_show, NULL);
 -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
 -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
 -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
 -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 -static DEVICE_ATTR(available_policies, S_IRUGO, available_policies_show, NULL);
 -
 -/* sys I/F for cooling device */
 -#define to_cooling_device(_dev)	\
 -	container_of(_dev, struct thermal_cooling_device, device)
 -
 -static ssize_t
 -thermal_cooling_device_type_show(struct device *dev,
 -				 struct device_attribute *attr, char *buf)
 +void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz,
 +					  const char *cdev_type, size_t size)
  {
 -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
 +	struct thermal_cooling_device *cdev = NULL;
  
 -	return sprintf(buf, "%s\n", cdev->type);
 +	mutex_lock(&thermal_list_lock);
 +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
 +		/* skip non matching cdevs */
 +		if (strncmp(cdev_type, cdev->type, size))
 +			continue;
 +
 +		/* re binding the exception matching the type pattern */
 +		thermal_zone_bind_cooling_device(tz, THERMAL_TRIPS_NONE, cdev,
 +						 THERMAL_NO_LIMIT,
 +						 THERMAL_NO_LIMIT,
 +						 THERMAL_WEIGHT_DEFAULT);
 +	}
 +	mutex_unlock(&thermal_list_lock);
  }
  
 -static ssize_t
 -thermal_cooling_device_max_state_show(struct device *dev,
 -				      struct device_attribute *attr, char *buf)
 +void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz,
 +					  const char *cdev_type, size_t size)
  {
 -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
 -	unsigned long state;
 -	int ret;
 +	struct thermal_cooling_device *cdev = NULL;
  
 -	ret = cdev->ops->get_max_state(cdev, &state);
 -	if (ret)
 -		return ret;
 -	return sprintf(buf, "%ld\n", state);
 +	mutex_lock(&thermal_list_lock);
 +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
 +		/* skip non matching cdevs */
 +		if (strncmp(cdev_type, cdev->type, size))
 +			continue;
 +		/* unbinding the exception matching the type pattern */
 +		thermal_zone_unbind_cooling_device(tz, THERMAL_TRIPS_NONE,
 +						   cdev);
 +	}
 +	mutex_unlock(&thermal_list_lock);
  }
  
 -static ssize_t
 -thermal_cooling_device_cur_state_show(struct device *dev,
 -				      struct device_attribute *attr, char *buf)
 +/*
 + * Device management section: cooling devices, zones devices, and binding
 + *
 + * Set of functions provided by the thermal core for:
 + * - cooling devices lifecycle: registration, unregistration,
 + *				binding, and unbinding.
 + * - thermal zone devices lifecycle: registration, unregistration,
 + *				     binding, and unbinding.
 + */
 +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
  {
 -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
 -	unsigned long state;
  	int ret;
  
 -	ret = cdev->ops->get_cur_state(cdev, &state);
 -	if (ret)
 +	if (lock)
 +		mutex_lock(lock);
 +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
 +	if (lock)
 +		mutex_unlock(lock);
 +	if (unlikely(ret < 0))
  		return ret;
 -	return sprintf(buf, "%ld\n", state);
 -}
 -
 -static ssize_t
 -thermal_cooling_device_cur_state_store(struct device *dev,
 -				       struct device_attribute *attr,
 -				       const char *buf, size_t count)
 -{
 -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
 -	unsigned long state;
 -	int result;
 -
 -	if (!sscanf(buf, "%ld\n", &state))
 -		return -EINVAL;
 -
 -	if ((long)state < 0)
 -		return -EINVAL;
 -
 -	result = cdev->ops->set_cur_state(cdev, state);
 -	if (result)
 -		return result;
 -	return count;
 -}
 -
 -static struct device_attribute dev_attr_cdev_type =
 -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
 -static DEVICE_ATTR(max_state, 0444,
 -		   thermal_cooling_device_max_state_show, NULL);
 -static DEVICE_ATTR(cur_state, 0644,
 -		   thermal_cooling_device_cur_state_show,
 -		   thermal_cooling_device_cur_state_store);
 -
 -static ssize_t
 -thermal_cooling_device_trip_point_show(struct device *dev,
 -				       struct device_attribute *attr, char *buf)
 -{
 -	struct thermal_instance *instance;
 -
 -	instance =
 -	    container_of(attr, struct thermal_instance, attr);
 -
 -	if (instance->trip == THERMAL_TRIPS_NONE)
 -		return sprintf(buf, "-1\n");
 -	else
 -		return sprintf(buf, "%d\n", instance->trip);
 -}
 -
 -static struct attribute *cooling_device_attrs[] = {
 -	&dev_attr_cdev_type.attr,
 -	&dev_attr_max_state.attr,
 -	&dev_attr_cur_state.attr,
 -	NULL,
 -};
 -
 -static const struct attribute_group cooling_device_attr_group = {
 -	.attrs = cooling_device_attrs,
 -};
 -
 -static const struct attribute_group *cooling_device_attr_groups[] = {
 -	&cooling_device_attr_group,
 -	NULL,
 -};
 -
 -static ssize_t
 -thermal_cooling_device_weight_show(struct device *dev,
 -				   struct device_attribute *attr, char *buf)
 -{
 -	struct thermal_instance *instance;
 -
 -	instance = container_of(attr, struct thermal_instance, weight_attr);
 -
 -	return sprintf(buf, "%d\n", instance->weight);
 +	*id = ret;
 +	return 0;
  }
  
 -static ssize_t
 -thermal_cooling_device_weight_store(struct device *dev,
 -				    struct device_attribute *attr,
 -				    const char *buf, size_t count)
 -{
 -	struct thermal_instance *instance;
 -	int ret, weight;
 -
 -	ret = kstrtoint(buf, 0, &weight);
 -	if (ret)
 -		return ret;
 -
 -	instance = container_of(attr, struct thermal_instance, weight_attr);
 -	instance->weight = weight;
 -
 -	return count;
 +static void release_idr(struct idr *idr, struct mutex *lock, int id)
 +{
 +	if (lock)
 +		mutex_lock(lock);
 +	idr_remove(idr, id);
 +	if (lock)
 +		mutex_unlock(lock);
  }
 -/* Device management */
  
  /**
   * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
@@@ -674,7 -1358,8 +674,7 @@@ int thermal_zone_bind_cooling_device(st
  	if (lower > upper || upper > max_state)
  		return -EINVAL;
  
 -	dev =
 -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
 +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  	if (!dev)
  		return -ENOMEM;
  	dev->tz = tz;
@@@ -717,10 -1402,10 +717,10 @@@
  	mutex_lock(&tz->lock);
  	mutex_lock(&cdev->lock);
  	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
 -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
 -		result = -EEXIST;
 -		break;
 -	}
 +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
 +			result = -EEXIST;
 +			break;
 +		}
  	if (!result) {
  		list_add_tail(&dev->tz_node, &tz->thermal_instances);
  		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
@@@ -800,8 -1485,8 +800,8 @@@ static void thermal_release(struct devi
  		     sizeof("thermal_zone") - 1)) {
  		tz = to_thermal_zone(dev);
  		kfree(tz);
 -	} else if(!strncmp(dev_name(dev), "cooling_device",
 -			sizeof("cooling_device") - 1)){
 +	} else if (!strncmp(dev_name(dev), "cooling_device",
 +			    sizeof("cooling_device") - 1)) {
  		cdev = to_cooling_device(dev);
  		kfree(cdev);
  	}
@@@ -812,78 -1497,6 +812,78 @@@ static struct class thermal_class = 
  	.dev_release = thermal_release,
  };
  
 +static inline
 +void print_bind_err_msg(struct thermal_zone_device *tz,
 +			struct thermal_cooling_device *cdev, int ret)
 +{
 +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
 +		tz->type, cdev->type, ret);
 +}
 +
 +static void __bind(struct thermal_zone_device *tz, int mask,
 +		   struct thermal_cooling_device *cdev,
 +		   unsigned long *limits,
 +		   unsigned int weight)
 +{
 +	int i, ret;
 +
 +	for (i = 0; i < tz->trips; i++) {
 +		if (mask & (1 << i)) {
 +			unsigned long upper, lower;
 +
 +			upper = THERMAL_NO_LIMIT;
 +			lower = THERMAL_NO_LIMIT;
 +			if (limits) {
 +				lower = limits[i * 2];
 +				upper = limits[i * 2 + 1];
 +			}
 +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
 +							       upper, lower,
 +							       weight);
 +			if (ret)
 +				print_bind_err_msg(tz, cdev, ret);
 +		}
 +	}
 +}
 +
 +static void bind_cdev(struct thermal_cooling_device *cdev)
 +{
 +	int i, ret;
 +	const struct thermal_zone_params *tzp;
 +	struct thermal_zone_device *pos = NULL;
 +
 +	mutex_lock(&thermal_list_lock);
 +
 +	list_for_each_entry(pos, &thermal_tz_list, node) {
 +		if (!pos->tzp && !pos->ops->bind)
 +			continue;
 +
 +		if (pos->ops->bind) {
 +			ret = pos->ops->bind(pos, cdev);
 +			if (ret)
 +				print_bind_err_msg(pos, cdev, ret);
 +			continue;
 +		}
 +
 +		tzp = pos->tzp;
 +		if (!tzp || !tzp->tbp)
 +			continue;
 +
 +		for (i = 0; i < tzp->num_tbps; i++) {
 +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
 +				continue;
 +			if (tzp->tbp[i].match(pos, cdev))
 +				continue;
 +			tzp->tbp[i].cdev = cdev;
 +			__bind(pos, tzp->tbp[i].trip_mask, cdev,
 +			       tzp->tbp[i].binding_limits,
 +			       tzp->tbp[i].weight);
 +		}
 +	}
 +
 +	mutex_unlock(&thermal_list_lock);
 +}
 +
  /**
   * __thermal_cooling_device_register() - register a new thermal cooling device
   * @np:		a pointer to a device tree node.
@@@ -916,7 -1529,7 +916,7 @@@ __thermal_cooling_device_register(struc
  	    !ops->set_cur_state)
  		return ERR_PTR(-EINVAL);
  
 -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
 +	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
  	if (!cdev)
  		return ERR_PTR(-ENOMEM);
  
@@@ -933,7 -1546,7 +933,7 @@@
  	cdev->ops = ops;
  	cdev->updated = false;
  	cdev->device.class = &thermal_class;
 -	cdev->device.groups = cooling_device_attr_groups;
 +	thermal_cooling_device_setup_sysfs(cdev);
  	cdev->devdata = devdata;
  	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
  	result = device_register(&cdev->device);
@@@ -1006,22 -1619,12 +1006,22 @@@ thermal_of_cooling_device_register(stru
  }
  EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
  
 +static void __unbind(struct thermal_zone_device *tz, int mask,
 +		     struct thermal_cooling_device *cdev)
 +{
 +	int i;
 +
 +	for (i = 0; i < tz->trips; i++)
 +		if (mask & (1 << i))
 +			thermal_zone_unbind_cooling_device(tz, i, cdev);
 +}
 +
  /**
 - * thermal_cooling_device_unregister - removes the registered thermal cooling device
 + * thermal_cooling_device_unregister - removes a thermal cooling device
   * @cdev:	the thermal cooling device to remove.
   *
 - * thermal_cooling_device_unregister() must be called when the device is no
 - * longer needed.
 + * thermal_cooling_device_unregister() must be called when a registered
 + * thermal cooling device is no longer needed.
   */
  void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
  {
@@@ -1035,8 -1638,8 +1035,8 @@@
  
  	mutex_lock(&thermal_list_lock);
  	list_for_each_entry(pos, &thermal_cdev_list, node)
 -	    if (pos == cdev)
 -		break;
 +		if (pos == cdev)
 +			break;
  	if (pos != cdev) {
  		/* thermal cooling device not found */
  		mutex_unlock(&thermal_list_lock);
@@@ -1065,49 -1668,171 +1065,49 @@@
  
  	mutex_unlock(&thermal_list_lock);
  
 -	if (cdev->type[0])
 -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
 -	device_remove_file(&cdev->device, &dev_attr_max_state);
 -	device_remove_file(&cdev->device, &dev_attr_cur_state);
 -
  	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
  	device_unregister(&cdev->device);
 -	return;
  }
  EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
  
 -void thermal_cdev_update(struct thermal_cooling_device *cdev)
 +static void bind_tz(struct thermal_zone_device *tz)
  {
 -	struct thermal_instance *instance;
 -	unsigned long target = 0;
 +	int i, ret;
 +	struct thermal_cooling_device *pos = NULL;
 +	const struct thermal_zone_params *tzp = tz->tzp;
  
 -	mutex_lock(&cdev->lock);
 -	/* cooling device is updated*/
 -	if (cdev->updated) {
 -		mutex_unlock(&cdev->lock);
 +	if (!tzp && !tz->ops->bind)
  		return;
 -	}
 -
 -	/* Make sure cdev enters the deepest cooling state */
 -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
 -		dev_dbg(&cdev->device, "zone%d->target=%lu\n",
 -				instance->tz->id, instance->target);
 -		if (instance->target == THERMAL_NO_TARGET)
 -			continue;
 -		if (instance->target > target)
 -			target = instance->target;
 -	}
 -	cdev->ops->set_cur_state(cdev, target);
 -	cdev->updated = true;
 -	mutex_unlock(&cdev->lock);
 -	trace_cdev_update(cdev, target);
 -	dev_dbg(&cdev->device, "set to state %lu\n", target);
 -}
 -EXPORT_SYMBOL(thermal_cdev_update);
 -
 -/**
 - * thermal_notify_framework - Sensor drivers use this API to notify framework
 - * @tz:		thermal zone device
 - * @trip:	indicates which trip point has been crossed
 - *
 - * This function handles the trip events from sensor drivers. It starts
 - * throttling the cooling devices according to the policy configured.
 - * For CRITICAL and HOT trip points, this notifies the respective drivers,
 - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
 - * The throttling policy is based on the configured platform data; if no
 - * platform data is provided, this uses the step_wise throttling policy.
 - */
 -void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
 -{
 -	handle_thermal_trip(tz, trip);
 -}
 -EXPORT_SYMBOL_GPL(thermal_notify_framework);
 -
 -/**
 - * create_trip_attrs() - create attributes for trip points
 - * @tz:		the thermal zone device
 - * @mask:	Writeable trip point bitmap.
 - *
 - * helper function to instantiate sysfs entries for every trip
 - * point and its properties of a struct thermal_zone_device.
 - *
 - * Return: 0 on success, the proper error value otherwise.
 - */
 -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
 -{
 -	int indx;
 -	int size = sizeof(struct thermal_attr) * tz->trips;
  
 -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
 -	if (!tz->trip_type_attrs)
 -		return -ENOMEM;
 -
 -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
 -	if (!tz->trip_temp_attrs) {
 -		kfree(tz->trip_type_attrs);
 -		return -ENOMEM;
 -	}
 +	mutex_lock(&thermal_list_lock);
  
 -	if (tz->ops->get_trip_hyst) {
 -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
 -		if (!tz->trip_hyst_attrs) {
 -			kfree(tz->trip_type_attrs);
 -			kfree(tz->trip_temp_attrs);
 -			return -ENOMEM;
 +	/* If there is ops->bind, try to use ops->bind */
 +	if (tz->ops->bind) {
 +		list_for_each_entry(pos, &thermal_cdev_list, node) {
 +			ret = tz->ops->bind(tz, pos);
 +			if (ret)
 +				print_bind_err_msg(tz, pos, ret);
  		}
 +		goto exit;
  	}
  
 +	if (!tzp || !tzp->tbp)
 +		goto exit;
  
 -	for (indx = 0; indx < tz->trips; indx++) {
 -		/* create trip type attribute */
 -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
 -			 "trip_point_%d_type", indx);
 -
 -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
 -		tz->trip_type_attrs[indx].attr.attr.name =
 -						tz->trip_type_attrs[indx].name;
 -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
 -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
 -
 -		device_create_file(&tz->device,
 -				   &tz->trip_type_attrs[indx].attr);
 -
 -		/* create trip temp attribute */
 -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
 -			 "trip_point_%d_temp", indx);
 -
 -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
 -		tz->trip_temp_attrs[indx].attr.attr.name =
 -						tz->trip_temp_attrs[indx].name;
 -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
 -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
 -		if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
 -		    mask & (1 << indx)) {
 -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
 -			tz->trip_temp_attrs[indx].attr.store =
 -							trip_point_temp_store;
 -		}
 -
 -		device_create_file(&tz->device,
 -				   &tz->trip_temp_attrs[indx].attr);
 -
 -		/* create Optional trip hyst attribute */
 -		if (!tz->ops->get_trip_hyst)
 -			continue;
 -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
 -			 "trip_point_%d_hyst", indx);
 -
 -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
 -		tz->trip_hyst_attrs[indx].attr.attr.name =
 -					tz->trip_hyst_attrs[indx].name;
 -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
 -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
 -		if (tz->ops->set_trip_hyst) {
 -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
 -			tz->trip_hyst_attrs[indx].attr.store =
 -					trip_point_hyst_store;
 +	list_for_each_entry(pos, &thermal_cdev_list, node) {
 +		for (i = 0; i < tzp->num_tbps; i++) {
 +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
 +				continue;
 +			if (tzp->tbp[i].match(tz, pos))
 +				continue;
 +			tzp->tbp[i].cdev = pos;
 +			__bind(tz, tzp->tbp[i].trip_mask, pos,
 +			       tzp->tbp[i].binding_limits,
 +			       tzp->tbp[i].weight);
  		}
 -
 -		device_create_file(&tz->device,
 -				   &tz->trip_hyst_attrs[indx].attr);
 -	}
 -	return 0;
 -}
 -
 -static void remove_trip_attrs(struct thermal_zone_device *tz)
 -{
 -	int indx;
 -
 -	for (indx = 0; indx < tz->trips; indx++) {
 -		device_remove_file(&tz->device,
 -				   &tz->trip_type_attrs[indx].attr);
 -		device_remove_file(&tz->device,
 -				   &tz->trip_temp_attrs[indx].attr);
 -		if (tz->ops->get_trip_hyst)
 -			device_remove_file(&tz->device,
 -				  &tz->trip_hyst_attrs[indx].attr);
  	}
 -	kfree(tz->trip_type_attrs);
 -	kfree(tz->trip_temp_attrs);
 -	kfree(tz->trip_hyst_attrs);
 +exit:
 +	mutex_unlock(&thermal_list_lock);
  }
  
  /**
@@@ -1134,22 -1859,20 +1134,22 @@@
   * in case of error, an ERR_PTR. Caller must check return value with
   * IS_ERR*() helpers.
   */
 -struct thermal_zone_device *thermal_zone_device_register(const char *type,
 -	int trips, int mask, void *devdata,
 -	struct thermal_zone_device_ops *ops,
 -	struct thermal_zone_params *tzp,
 -	int passive_delay, int polling_delay)
 +struct thermal_zone_device *
 +thermal_zone_device_register(const char *type, int trips, int mask,
 +			     void *devdata, struct thermal_zone_device_ops *ops,
 +			     struct thermal_zone_params *tzp, int passive_delay,
 +			     int polling_delay)
  {
  	struct thermal_zone_device *tz;
  	enum thermal_trip_type trip_type;
  	int trip_temp;
  	int result;
  	int count;
 -	int passive = 0;
  	struct thermal_governor *governor;
  
 +	if (!type || strlen(type) == 0)
 +		return ERR_PTR(-EINVAL);
 +
  	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
  		return ERR_PTR(-EINVAL);
  
@@@ -1162,7 -1885,7 +1162,7 @@@
  	if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
  		return ERR_PTR(-EINVAL);
  
 -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
 +	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
  	if (!tz)
  		return ERR_PTR(-ENOMEM);
  
@@@ -1175,7 -1898,7 +1175,7 @@@
  		return ERR_PTR(result);
  	}
  
 -	strlcpy(tz->type, type ? : "", sizeof(tz->type));
 +	strlcpy(tz->type, type, sizeof(tz->type));
  	tz->ops = ops;
  	tz->tzp = tzp;
  	tz->device.class = &thermal_class;
@@@ -1183,13 -1906,6 +1183,13 @@@
  	tz->trips = trips;
  	tz->passive_delay = passive_delay;
  	tz->polling_delay = polling_delay;
 +
 +	/* sys I/F */
 +	/* Add nodes that are always present via .groups */
 +	result = thermal_zone_create_device_groups(tz, mask);
 +	if (result)
 +		goto unregister;
 +
  	/* A new thermal zone needs to be updated anyway. */
  	atomic_set(&tz->need_update, 1);
  
@@@ -1201,9 -1917,32 +1201,9 @@@
  		return ERR_PTR(result);
  	}
  
 -	/* sys I/F */
 -	if (type) {
 -		result = device_create_file(&tz->device, &dev_attr_type);
 -		if (result)
 -			goto unregister;
 -	}
 -
 -	result = device_create_file(&tz->device, &dev_attr_temp);
 -	if (result)
 -		goto unregister;
 -
 -	if (ops->get_mode) {
 -		result = device_create_file(&tz->device, &dev_attr_mode);
 -		if (result)
 -			goto unregister;
 -	}
 -
 -	result = create_trip_attrs(tz, mask);
 -	if (result)
 -		goto unregister;
 -
  	for (count = 0; count < trips; count++) {
  		if (tz->ops->get_trip_type(tz, count, &trip_type))
  			set_bit(count, &tz->trips_disabled);
 -		if (trip_type == THERMAL_TRIP_PASSIVE)
 -			passive = 1;
  		if (tz->ops->get_trip_temp(tz, count, &trip_temp))
  			set_bit(count, &tz->trips_disabled);
  		/* Check for bogus trip points */
@@@ -1211,6 -1950,33 +1211,6 @@@
  			set_bit(count, &tz->trips_disabled);
  	}
  
 -	if (!passive) {
 -		result = device_create_file(&tz->device, &dev_attr_passive);
 -		if (result)
 -			goto unregister;
 -	}
 -
 -	if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) {
 -		result = device_create_file(&tz->device, &dev_attr_emul_temp);
 -		if (result)
 -			goto unregister;
 -	}
 -
 -	/* Create policy attribute */
 -	result = device_create_file(&tz->device, &dev_attr_policy);
 -	if (result)
 -		goto unregister;
 -
 -	/* Add thermal zone params */
 -	result = create_tzp_attrs(&tz->device);
 -	if (result)
 -		goto unregister;
 -
 -	/* Create available_policies attribute */
 -	result = device_create_file(&tz->device, &dev_attr_available_policies);
 -	if (result)
 -		goto unregister;
 -
  	/* Update 'this' zone's governor information */
  	mutex_lock(&thermal_governor_lock);
  
@@@ -1240,7 -2006,7 +1240,7 @@@
  	/* Bind cooling devices for this zone */
  	bind_tz(tz);
  
 -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
 +	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
  
  	thermal_zone_device_reset(tz);
  	/* Update the new thermal zone and mark it as already updated. */
@@@ -1274,8 -2040,8 +1274,8 @@@ void thermal_zone_device_unregister(str
  
  	mutex_lock(&thermal_list_lock);
  	list_for_each_entry(pos, &thermal_tz_list, node)
 -	    if (pos == tz)
 -		break;
 +		if (pos == tz)
 +			break;
  	if (pos != tz) {
  		/* thermal zone device not found */
  		mutex_unlock(&thermal_list_lock);
@@@ -1305,10 -2071,14 +1305,10 @@@
  
  	thermal_zone_device_set_polling(tz, 0);
  
 -	if (tz->type[0])
 -		device_remove_file(&tz->device, &dev_attr_type);
 -	device_remove_file(&tz->device, &dev_attr_temp);
 -	if (tz->ops->get_mode)
 -		device_remove_file(&tz->device, &dev_attr_mode);
 -	device_remove_file(&tz->device, &dev_attr_policy);
 -	device_remove_file(&tz->device, &dev_attr_available_policies);
 -	remove_trip_attrs(tz);
 +	kfree(tz->trip_type_attrs);
 +	kfree(tz->trip_temp_attrs);
 +	kfree(tz->trip_hyst_attrs);
 +	kfree(tz->trips_attribute_group.attrs);
  	thermal_set_governor(tz, NULL);
  
  	thermal_remove_hwmon_sysfs(tz);
@@@ -1316,7 -2086,7 +1316,7 @@@
  	idr_destroy(&tz->idr);
  	mutex_destroy(&tz->lock);
  	device_unregister(&tz->device);
 -	return;
 +	kfree(tz->device.groups);
  }
  EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
  
@@@ -1358,13 -2128,43 +1358,13 @@@ exit
  }
  EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
  
 -/**
 - * thermal_zone_get_slope - return the slope attribute of the thermal zone
 - * @tz: thermal zone device with the slope attribute
 - *
 - * Return: If the thermal zone device has a slope attribute, return it, else
 - * return 1.
 - */
 -int thermal_zone_get_slope(struct thermal_zone_device *tz)
 -{
 -	if (tz && tz->tzp)
 -		return tz->tzp->slope;
 -	return 1;
 -}
 -EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
 -
 -/**
 - * thermal_zone_get_offset - return the offset attribute of the thermal zone
 - * @tz: thermal zone device with the offset attribute
 - *
 - * Return: If the thermal zone device has a offset attribute, return it, else
 - * return 0.
 - */
 -int thermal_zone_get_offset(struct thermal_zone_device *tz)
 -{
 -	if (tz && tz->tzp)
 -		return tz->tzp->offset;
 -	return 0;
 -}
 -EXPORT_SYMBOL_GPL(thermal_zone_get_offset);
 -
  #ifdef CONFIG_NET
  static const struct genl_multicast_group thermal_event_mcgrps[] = {
  	{ .name = THERMAL_GENL_MCAST_GROUP_NAME, },
  };
  
- static struct genl_family thermal_event_genl_family = {
- 	.id = GENL_ID_GENERATE,
+ static struct genl_family thermal_event_genl_family __ro_after_init = {
+ 	.module = THIS_MODULE,
  	.name = THERMAL_GENL_FAMILY_NAME,
  	.version = THERMAL_GENL_VERSION,
  	.maxattr = THERMAL_GENL_ATTR_MAX,
@@@ -1373,7 -2173,7 +1373,7 @@@
  };
  
  int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 -					enum events event)
 +				   enum events event)
  {
  	struct sk_buff *skb;
  	struct nlattr *attr;
@@@ -1435,7 -2235,7 +1435,7 @@@
  }
  EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
  
- static int genetlink_init(void)
+ static int __init genetlink_init(void)
  {
  	return genl_register_family(&thermal_event_genl_family);
  }
@@@ -1449,8 -2249,40 +1449,8 @@@ static inline int genetlink_init(void) 
  static inline void genetlink_exit(void) {}
  #endif /* !CONFIG_NET */
  
 -static int __init thermal_register_governors(void)
 -{
 -	int result;
 -
 -	result = thermal_gov_step_wise_register();
 -	if (result)
 -		return result;
 -
 -	result = thermal_gov_fair_share_register();
 -	if (result)
 -		return result;
 -
 -	result = thermal_gov_bang_bang_register();
 -	if (result)
 -		return result;
 -
 -	result = thermal_gov_user_space_register();
 -	if (result)
 -		return result;
 -
 -	return thermal_gov_power_allocator_register();
 -}
 -
 -static void thermal_unregister_governors(void)
 -{
 -	thermal_gov_step_wise_unregister();
 -	thermal_gov_fair_share_unregister();
 -	thermal_gov_bang_bang_unregister();
 -	thermal_gov_user_space_unregister();
 -	thermal_gov_power_allocator_unregister();
 -}
 -
  static int thermal_pm_notify(struct notifier_block *nb,
 -				unsigned long mode, void *_unused)
 +			     unsigned long mode, void *_unused)
  {
  	struct thermal_zone_device *tz;
  
diff --combined fs/dlm/netlink.c
index 934ab06,0643ae4..43a96c3
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@@ -16,11 -16,7 +16,7 @@@
  static uint32_t dlm_nl_seqnum;
  static uint32_t listener_nlportid;
  
- static struct genl_family family = {
- 	.id		= GENL_ID_GENERATE,
- 	.name		= DLM_GENL_NAME,
- 	.version	= DLM_GENL_VERSION,
- };
+ static struct genl_family family;
  
  static int prepare_data(u8 cmd, struct sk_buff **skbp, size_t size)
  {
@@@ -69,16 -65,24 +65,24 @@@ static int user_cmd(struct sk_buff *skb
  	return 0;
  }
  
 -static struct genl_ops dlm_nl_ops[] = {
 +static const struct genl_ops dlm_nl_ops[] = {
  	{
  		.cmd	= DLM_CMD_HELLO,
  		.doit	= user_cmd,
  	},
  };
  
+ static struct genl_family family __ro_after_init = {
+ 	.name		= DLM_GENL_NAME,
+ 	.version	= DLM_GENL_VERSION,
+ 	.ops		= dlm_nl_ops,
+ 	.n_ops		= ARRAY_SIZE(dlm_nl_ops),
+ 	.module		= THIS_MODULE,
+ };
+ 
  int __init dlm_netlink_init(void)
  {
- 	return genl_register_family_with_ops(&family, dlm_nl_ops);
+ 	return genl_register_family(&family);
  }
  
  void dlm_netlink_exit(void)
diff --combined fs/nfs/inode.c
index 7de345f,ce42dd0..5864146
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@@ -634,28 -634,15 +634,28 @@@ void nfs_setattr_update_inode(struct in
  }
  EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
  
 -static void nfs_request_parent_use_readdirplus(struct dentry *dentry)
 +static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry)
  {
  	struct dentry *parent;
  
 +	if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS))
 +		return;
  	parent = dget_parent(dentry);
  	nfs_force_use_readdirplus(d_inode(parent));
  	dput(parent);
  }
  
 +static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
 +{
 +	struct dentry *parent;
 +
 +	if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS))
 +		return;
 +	parent = dget_parent(dentry);
 +	nfs_advise_use_readdirplus(d_inode(parent));
 +	dput(parent);
 +}
 +
  static bool nfs_need_revalidate_inode(struct inode *inode)
  {
  	if (NFS_I(inode)->cache_validity &
@@@ -696,10 -683,10 +696,10 @@@ int nfs_getattr(struct vfsmount *mnt, s
  	if (need_atime || nfs_need_revalidate_inode(inode)) {
  		struct nfs_server *server = NFS_SERVER(inode);
  
 -		if (server->caps & NFS_CAP_READDIRPLUS)
 -			nfs_request_parent_use_readdirplus(dentry);
 +		nfs_readdirplus_parent_cache_miss(dentry);
  		err = __nfs_revalidate_inode(server, inode);
 -	}
 +	} else
 +		nfs_readdirplus_parent_cache_hit(dentry);
  	if (!err) {
  		generic_fillattr(inode, stat);
  		stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
@@@ -715,7 -702,8 +715,7 @@@ EXPORT_SYMBOL_GPL(nfs_getattr)
  static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
  {
  	atomic_set(&l_ctx->count, 1);
 -	l_ctx->lockowner.l_owner = current->files;
 -	l_ctx->lockowner.l_pid = current->tgid;
 +	l_ctx->lockowner = current->files;
  	INIT_LIST_HEAD(&l_ctx->list);
  	atomic_set(&l_ctx->io_count, 0);
  }
@@@ -726,7 -714,9 +726,7 @@@ static struct nfs_lock_context *__nfs_f
  	struct nfs_lock_context *pos = head;
  
  	do {
 -		if (pos->lockowner.l_owner != current->files)
 -			continue;
 -		if (pos->lockowner.l_pid != current->tgid)
 +		if (pos->lockowner != current->files)
  			continue;
  		atomic_inc(&pos->count);
  		return pos;
@@@ -809,9 -799,7 +809,9 @@@ void nfs_close_context(struct nfs_open_
  }
  EXPORT_SYMBOL_GPL(nfs_close_context);
  
 -struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode)
 +struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
 +						fmode_t f_mode,
 +						struct file *filp)
  {
  	struct nfs_open_context *ctx;
  	struct rpc_cred *cred = rpc_lookup_cred();
@@@ -830,7 -818,6 +830,7 @@@
  	ctx->mode = f_mode;
  	ctx->flags = 0;
  	ctx->error = 0;
 +	ctx->flock_owner = (fl_owner_t)filp;
  	nfs_init_lock_context(&ctx->lock_context);
  	ctx->lock_context.open_context = ctx;
  	INIT_LIST_HEAD(&ctx->list);
@@@ -955,7 -942,7 +955,7 @@@ int nfs_open(struct inode *inode, struc
  {
  	struct nfs_open_context *ctx;
  
 -	ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
 +	ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp);
  	if (IS_ERR(ctx))
  		return PTR_ERR(ctx);
  	nfs_file_set_open_context(filp, ctx);
@@@ -1112,17 -1099,11 +1112,17 @@@ static int nfs_invalidate_mapping(struc
  	return 0;
  }
  
 -static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 +bool nfs_mapping_need_revalidate_inode(struct inode *inode)
  {
 -	if (nfs_have_delegated_attributes(inode))
 -		return false;
 -	return (NFS_I(inode)->cache_validity & NFS_INO_REVAL_PAGECACHE)
 +	unsigned long cache_validity = NFS_I(inode)->cache_validity;
 +
 +	if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
 +		const unsigned long force_reval =
 +			NFS_INO_REVAL_PAGECACHE|NFS_INO_REVAL_FORCED;
 +		return (cache_validity & force_reval) == force_reval;
 +	}
 +
 +	return (cache_validity & NFS_INO_REVAL_PAGECACHE)
  		|| nfs_attribute_timeout(inode)
  		|| NFS_STALE(inode);
  }
@@@ -1336,7 -1317,7 +1336,7 @@@ static int nfs_check_inode_attributes(s
  		invalid |= NFS_INO_INVALID_ATIME;
  
  	if (invalid != 0)
 -		nfs_set_cache_invalid(inode, invalid);
 +		nfs_set_cache_invalid(inode, invalid | NFS_INO_REVAL_FORCED);
  
  	nfsi->read_cache_jiffies = fattr->time_start;
  	return 0;
@@@ -2034,7 -2015,7 +2034,7 @@@ static void nfsiod_stop(void
  	destroy_workqueue(wq);
  }
  
- int nfs_net_id;
+ unsigned int nfs_net_id;
  EXPORT_SYMBOL_GPL(nfs_net_id);
  
  static int nfs_net_init(struct net *net)
diff --combined fs/nfsd/nfsctl.c
index be13063,2857e46..f3b2f34
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@@ -217,7 -217,7 +217,7 @@@ static const struct file_operations poo
  	.release	= nfsd_pool_stats_release,
  };
  
 -static struct file_operations reply_cache_stats_operations = {
 +static const struct file_operations reply_cache_stats_operations = {
  	.open		= nfsd_reply_cache_stats_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
@@@ -1201,7 -1201,7 +1201,7 @@@ static int create_proc_exports_entry(vo
  }
  #endif
  
- int nfsd_net_id;
+ unsigned int nfsd_net_id;
  
  static __net_init int nfsd_init_net(struct net *net)
  {
diff --combined include/linux/device.h
index 36d3a98,a00105c..94926d3
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@@ -698,6 -698,25 +698,25 @@@ static inline int devm_add_action_or_re
  	return ret;
  }
  
+ /**
+  * devm_alloc_percpu - Resource-managed alloc_percpu
+  * @dev: Device to allocate per-cpu memory for
+  * @type: Type to allocate per-cpu memory for
+  *
+  * Managed alloc_percpu. Per-cpu memory allocated with this function is
+  * automatically freed on driver detach.
+  *
+  * RETURNS:
+  * Pointer to allocated memory on success, NULL on failure.
+  */
+ #define devm_alloc_percpu(dev, type)      \
+ 	((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \
+ 						      __alignof__(type)))
+ 
+ void __percpu *__devm_alloc_percpu(struct device *dev, size_t size,
+ 				   size_t align);
+ void devm_free_percpu(struct device *dev, void __percpu *pdata);
+ 
  struct device_dma_parameters {
  	/*
  	 * a low level driver may set these to teach IOMMU code about
@@@ -733,7 -752,7 +752,7 @@@
   * 		minimizes board-specific #ifdefs in drivers.
   * @driver_data: Private pointer for driver specific info.
   * @power:	For device power management.
 - * 		See Documentation/power/devices.txt for details.
 + * 		See Documentation/power/admin-guide/devices.rst for details.
   * @pm_domain:	Provide callbacks that are executed during system suspend,
   * 		hibernation, system resume and during runtime PM transitions
   * 		along with subsystem-level and driver-level callbacks.
diff --combined init/Kconfig
index 172f80e,405120b..b4f1fdc
--- a/init/Kconfig
+++ b/init/Kconfig
@@@ -1154,6 -1154,18 +1154,18 @@@ config CGROUP_PER
  
  	  Say N if unsure.
  
+ config CGROUP_BPF
+ 	bool "Support for eBPF programs attached to cgroups"
+ 	depends on BPF_SYSCALL && SOCK_CGROUP_DATA
+ 	help
+ 	  Allow attaching eBPF programs to a cgroup using the bpf(2)
+ 	  syscall command BPF_PROG_ATTACH.
+ 
+ 	  In which context these programs are accessed depends on the type
+ 	  of attachment. For instance, programs that are attached using
+ 	  BPF_CGROUP_INET_INGRESS will be executed on the ingress path of
+ 	  inet sockets.
+ 
  config CGROUP_DEBUG
  	bool "Example controller"
  	default n
@@@ -1306,7 -1318,7 +1318,7 @@@ config BLK_DEV_INITR
  	  boot loader (loadlin or lilo) and that is mounted as root
  	  before the normal boot procedure. It is typically used to
  	  load modules needed to mount the "real" root file system,
 -	  etc. See <file:Documentation/initrd.txt> for details.
 +	  etc. See <file:Documentation/admin-guide/initrd.rst> for details.
  
  	  If RAM disk support (BLK_DEV_RAM) is also included, this
  	  also enables initial RAM disk (initrd) support and adds
diff --combined net/batman-adv/translation-table.c
index 0dc85eb,447f949..30ecbfb
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@@ -56,7 -56,6 +56,6 @@@
  #include "hard-interface.h"
  #include "hash.h"
  #include "log.h"
- #include "multicast.h"
  #include "netlink.h"
  #include "originator.h"
  #include "packet.h"
@@@ -647,6 -646,7 +646,7 @@@ bool batadv_tt_local_add(struct net_dev
  	struct net *net = dev_net(soft_iface);
  	struct batadv_softif_vlan *vlan;
  	struct net_device *in_dev = NULL;
+ 	struct batadv_hard_iface *in_hardif = NULL;
  	struct hlist_head *head;
  	struct batadv_tt_orig_list_entry *orig_entry;
  	int hash_added, table_size, packet_size_max;
@@@ -658,6 -658,9 +658,9 @@@
  	if (ifindex != BATADV_NULL_IFINDEX)
  		in_dev = dev_get_by_index(net, ifindex);
  
+ 	if (in_dev)
+ 		in_hardif = batadv_hardif_get_by_netdev(in_dev);
+ 
  	tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
  
  	if (!is_multicast_ether_addr(addr))
@@@ -731,7 -734,7 +734,7 @@@
  	 */
  	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
  	tt_local->common.vid = vid;
- 	if (batadv_is_wifi_netdev(in_dev))
+ 	if (batadv_is_wifi_hardif(in_hardif))
  		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
  	kref_init(&tt_local->common.refcount);
  	tt_local->last_seen = jiffies;
@@@ -791,7 -794,7 +794,7 @@@ check_roaming
  	 */
  	remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
  
- 	if (batadv_is_wifi_netdev(in_dev))
+ 	if (batadv_is_wifi_hardif(in_hardif))
  		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
  	else
  		tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
@@@ -815,6 -818,8 +818,8 @@@
  
  	ret = true;
  out:
+ 	if (in_hardif)
+ 		batadv_hardif_put(in_hardif);
  	if (in_dev)
  		dev_put(in_dev);
  	if (tt_local)
@@@ -3282,7 -3287,7 +3287,7 @@@ static bool batadv_send_my_tt_response(
  							     &tvlv_tt_data,
  							     &tt_change,
  							     &tt_len);
 -		if (!tt_len)
 +		if (!tt_len || !tvlv_len)
  			goto unlock;
  
  		/* Copy the last orig_node's OGM buffer */
@@@ -3300,7 -3305,7 +3305,7 @@@
  							     &tvlv_tt_data,
  							     &tt_change,
  							     &tt_len);
 -		if (!tt_len)
 +		if (!tt_len || !tvlv_len)
  			goto out;
  
  		/* fill the rest of the tvlv with the real TT entries */
@@@ -3795,9 -3800,6 +3800,6 @@@ static void batadv_tt_local_commit_chan
  {
  	lockdep_assert_held(&bat_priv->tt.commit_lock);
  
- 	/* Update multicast addresses in local translation table */
- 	batadv_mcast_mla_update(bat_priv);
- 
  	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
  		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
  			batadv_tt_tvlv_container_update(bat_priv);
@@@ -3835,8 -3837,8 +3837,8 @@@ void batadv_tt_local_commit_changes(str
  bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
  			   unsigned short vid)
  {
- 	struct batadv_tt_local_entry *tt_local_entry = NULL;
- 	struct batadv_tt_global_entry *tt_global_entry = NULL;
+ 	struct batadv_tt_local_entry *tt_local_entry;
+ 	struct batadv_tt_global_entry *tt_global_entry;
  	struct batadv_softif_vlan *vlan;
  	bool ret = false;
  
@@@ -3845,27 -3847,24 +3847,24 @@@
  		return false;
  
  	if (!atomic_read(&vlan->ap_isolation))
- 		goto out;
+ 		goto vlan_put;
  
  	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
  	if (!tt_local_entry)
- 		goto out;
+ 		goto vlan_put;
  
  	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
  	if (!tt_global_entry)
- 		goto out;
+ 		goto local_entry_put;
  
- 	if (!_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
- 		goto out;
- 
- 	ret = true;
+ 	if (_batadv_is_ap_isolated(tt_local_entry, tt_global_entry))
+ 		ret = true;
  
- out:
+ 	batadv_tt_global_entry_put(tt_global_entry);
+ local_entry_put:
+ 	batadv_tt_local_entry_put(tt_local_entry);
+ vlan_put:
  	batadv_softif_vlan_put(vlan);
- 	if (tt_global_entry)
- 		batadv_tt_global_entry_put(tt_global_entry);
- 	if (tt_local_entry)
- 		batadv_tt_local_entry_put(tt_local_entry);
  	return ret;
  }
  
diff --combined net/bridge/br_sysfs_br.c
index f88c4df,c9d2e0a..a181482
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@@ -440,6 -440,23 +440,23 @@@ static ssize_t hash_max_store(struct de
  }
  static DEVICE_ATTR_RW(hash_max);
  
+ static ssize_t multicast_igmp_version_show(struct device *d,
+ 					   struct device_attribute *attr,
+ 					   char *buf)
+ {
+ 	struct net_bridge *br = to_bridge(d);
+ 
+ 	return sprintf(buf, "%u\n", br->multicast_igmp_version);
+ }
+ 
+ static ssize_t multicast_igmp_version_store(struct device *d,
+ 					    struct device_attribute *attr,
+ 					    const char *buf, size_t len)
+ {
+ 	return store_bridge_parm(d, buf, len, br_multicast_set_igmp_version);
+ }
+ static DEVICE_ATTR_RW(multicast_igmp_version);
+ 
  static ssize_t multicast_last_member_count_show(struct device *d,
  						struct device_attribute *attr,
  						char *buf)
@@@ -642,6 -659,25 +659,25 @@@ static ssize_t multicast_stats_enabled_
  	return store_bridge_parm(d, buf, len, set_stats_enabled);
  }
  static DEVICE_ATTR_RW(multicast_stats_enabled);
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ static ssize_t multicast_mld_version_show(struct device *d,
+ 					  struct device_attribute *attr,
+ 					  char *buf)
+ {
+ 	struct net_bridge *br = to_bridge(d);
+ 
+ 	return sprintf(buf, "%u\n", br->multicast_mld_version);
+ }
+ 
+ static ssize_t multicast_mld_version_store(struct device *d,
+ 					   struct device_attribute *attr,
+ 					   const char *buf, size_t len)
+ {
+ 	return store_bridge_parm(d, buf, len, br_multicast_set_mld_version);
+ }
+ static DEVICE_ATTR_RW(multicast_mld_version);
+ #endif
  #endif
  #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
  static ssize_t nf_call_iptables_show(
@@@ -809,6 -845,10 +845,10 @@@ static struct attribute *bridge_attrs[
  	&dev_attr_multicast_query_response_interval.attr,
  	&dev_attr_multicast_startup_query_interval.attr,
  	&dev_attr_multicast_stats_enabled.attr,
+ 	&dev_attr_multicast_igmp_version.attr,
+ #if IS_ENABLED(CONFIG_IPV6)
+ 	&dev_attr_multicast_mld_version.attr,
+ #endif
  #endif
  #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
  	&dev_attr_nf_call_iptables.attr,
@@@ -898,7 -938,6 +938,7 @@@ int br_sysfs_addbr(struct net_device *d
  	if (!br->ifobj) {
  		pr_info("%s: can't add kobject (directory) %s/%s\n",
  			__func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
 +		err = -ENOMEM;
  		goto out3;
  	}
  	return 0;
diff --combined net/ipv4/fib_trie.c
index e3665bf,73a6270..1b0e7d1
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@@ -84,25 -84,114 +84,114 @@@
  #include <trace/events/fib.h>
  #include "fib_lookup.h"
  
- static BLOCKING_NOTIFIER_HEAD(fib_chain);
+ static unsigned int fib_seq_sum(void)
+ {
+ 	unsigned int fib_seq = 0;
+ 	struct net *net;
+ 
+ 	rtnl_lock();
+ 	for_each_net(net)
+ 		fib_seq += net->ipv4.fib_seq;
+ 	rtnl_unlock();
+ 
+ 	return fib_seq;
+ }
+ 
+ static ATOMIC_NOTIFIER_HEAD(fib_chain);
+ 
+ static int call_fib_notifier(struct notifier_block *nb, struct net *net,
+ 			     enum fib_event_type event_type,
+ 			     struct fib_notifier_info *info)
+ {
+ 	info->net = net;
+ 	return nb->notifier_call(nb, event_type, info);
+ }
+ 
+ static void fib_rules_notify(struct net *net, struct notifier_block *nb,
+ 			     enum fib_event_type event_type)
+ {
+ #ifdef CONFIG_IP_MULTIPLE_TABLES
+ 	struct fib_notifier_info info;
+ 
+ 	if (net->ipv4.fib_has_custom_rules)
+ 		call_fib_notifier(nb, net, event_type, &info);
+ #endif
+ }
+ 
+ static void fib_notify(struct net *net, struct notifier_block *nb,
+ 		       enum fib_event_type event_type);
+ 
+ static int call_fib_entry_notifier(struct notifier_block *nb, struct net *net,
+ 				   enum fib_event_type event_type, u32 dst,
+ 				   int dst_len, struct fib_info *fi,
+ 				   u8 tos, u8 type, u32 tb_id, u32 nlflags)
+ {
+ 	struct fib_entry_notifier_info info = {
+ 		.dst = dst,
+ 		.dst_len = dst_len,
+ 		.fi = fi,
+ 		.tos = tos,
+ 		.type = type,
+ 		.tb_id = tb_id,
+ 		.nlflags = nlflags,
+ 	};
+ 	return call_fib_notifier(nb, net, event_type, &info.info);
+ }
+ 
+ static bool fib_dump_is_consistent(struct notifier_block *nb,
+ 				   void (*cb)(struct notifier_block *nb),
+ 				   unsigned int fib_seq)
+ {
+ 	atomic_notifier_chain_register(&fib_chain, nb);
+ 	if (fib_seq == fib_seq_sum())
+ 		return true;
+ 	atomic_notifier_chain_unregister(&fib_chain, nb);
+ 	if (cb)
+ 		cb(nb);
+ 	return false;
+ }
  
- int register_fib_notifier(struct notifier_block *nb)
+ #define FIB_DUMP_MAX_RETRIES 5
+ int register_fib_notifier(struct notifier_block *nb,
+ 			  void (*cb)(struct notifier_block *nb))
  {
- 	return blocking_notifier_chain_register(&fib_chain, nb);
+ 	int retries = 0;
+ 
+ 	do {
+ 		unsigned int fib_seq = fib_seq_sum();
+ 		struct net *net;
+ 
+ 		/* Mutex semantics guarantee that every change done to
+ 		 * FIB tries before we read the change sequence counter
+ 		 * is now visible to us.
+ 		 */
+ 		rcu_read_lock();
+ 		for_each_net_rcu(net) {
+ 			fib_rules_notify(net, nb, FIB_EVENT_RULE_ADD);
+ 			fib_notify(net, nb, FIB_EVENT_ENTRY_ADD);
+ 		}
+ 		rcu_read_unlock();
+ 
+ 		if (fib_dump_is_consistent(nb, cb, fib_seq))
+ 			return 0;
+ 	} while (++retries < FIB_DUMP_MAX_RETRIES);
+ 
+ 	return -EBUSY;
  }
  EXPORT_SYMBOL(register_fib_notifier);
  
  int unregister_fib_notifier(struct notifier_block *nb)
  {
- 	return blocking_notifier_chain_unregister(&fib_chain, nb);
+ 	return atomic_notifier_chain_unregister(&fib_chain, nb);
  }
  EXPORT_SYMBOL(unregister_fib_notifier);
  
  int call_fib_notifiers(struct net *net, enum fib_event_type event_type,
  		       struct fib_notifier_info *info)
  {
+ 	net->ipv4.fib_seq++;
  	info->net = net;
- 	return blocking_notifier_call_chain(&fib_chain, event_type, info);
+ 	return atomic_notifier_call_chain(&fib_chain, event_type, info);
  }
  
  static int call_fib_entry_notifiers(struct net *net,
@@@ -719,13 -808,6 +808,13 @@@ static unsigned char update_suffix(stru
  {
  	unsigned char slen = tn->pos;
  	unsigned long stride, i;
 +	unsigned char slen_max;
 +
 +	/* only vector 0 can have a suffix length greater than or equal to
 +	 * tn->pos + tn->bits, the second highest node will have a suffix
 +	 * length at most of tn->pos + tn->bits - 1
 +	 */
 +	slen_max = min_t(unsigned char, tn->pos + tn->bits - 1, tn->slen);
  
  	/* search though the list of children looking for nodes that might
  	 * have a suffix greater than the one we currently have.  This is
@@@ -743,8 -825,12 +832,8 @@@
  		slen = n->slen;
  		i &= ~(stride - 1);
  
 -		/* if slen covers all but the last bit we can stop here
 -		 * there will be nothing longer than that since only node
 -		 * 0 and 1 << (bits - 1) could have that as their suffix
 -		 * length.
 -		 */
 -		if ((slen + 1) >= (tn->pos + tn->bits))
 +		/* stop searching if we have hit the maximum possible value */
 +		if (slen >= slen_max)
  			break;
  	}
  
@@@ -916,27 -1002,39 +1005,27 @@@ static struct key_vector *resize(struc
  		return collapse(t, tn);
  
  	/* update parent in case halve failed */
 -	tp = node_parent(tn);
 -
 -	/* Return if at least one deflate was run */
 -	if (max_work != MAX_WORK)
 -		return tp;
 -
 -	/* push the suffix length to the parent node */
 -	if (tn->slen > tn->pos) {
 -		unsigned char slen = update_suffix(tn);
 -
 -		if (slen > tp->slen)
 -			tp->slen = slen;
 -	}
 -
 -	return tp;
 +	return node_parent(tn);
  }
  
 -static void leaf_pull_suffix(struct key_vector *tp, struct key_vector *l)
 +static void node_pull_suffix(struct key_vector *tn, unsigned char slen)
  {
 -	while ((tp->slen > tp->pos) && (tp->slen > l->slen)) {
 -		if (update_suffix(tp) > l->slen)
 +	unsigned char node_slen = tn->slen;
 +
 +	while ((node_slen > tn->pos) && (node_slen > slen)) {
 +		slen = update_suffix(tn);
 +		if (node_slen == slen)
  			break;
 -		tp = node_parent(tp);
 +
 +		tn = node_parent(tn);
 +		node_slen = tn->slen;
  	}
  }
  
 -static void leaf_push_suffix(struct key_vector *tn, struct key_vector *l)
 +static void node_push_suffix(struct key_vector *tn, unsigned char slen)
  {
 -	/* if this is a new leaf then tn will be NULL and we can sort
 -	 * out parent suffix lengths as a part of trie_rebalance
 -	 */
 -	while (tn->slen < l->slen) {
 -		tn->slen = l->slen;
 +	while (tn->slen < slen) {
 +		tn->slen = slen;
  		tn = node_parent(tn);
  	}
  }
@@@ -1057,7 -1155,6 +1146,7 @@@ static int fib_insert_node(struct trie 
  	}
  
  	/* Case 3: n is NULL, and will just insert a new leaf */
 +	node_push_suffix(tp, new->fa_slen);
  	NODE_INIT_PARENT(l, tp);
  	put_child_root(tp, key, l);
  	trie_rebalance(t, tp);
@@@ -1099,7 -1196,7 +1188,7 @@@ static int fib_insert_alias(struct tri
  	/* if we added to the tail node then we need to update slen */
  	if (l->slen < new->fa_slen) {
  		l->slen = new->fa_slen;
 -		leaf_push_suffix(tp, l);
 +		node_push_suffix(tp, new->fa_slen);
  	}
  
  	return 0;
@@@ -1491,8 -1588,6 +1580,8 @@@ static void fib_remove_alias(struct tri
  	 * out parent suffix lengths as a part of trie_rebalance
  	 */
  	if (hlist_empty(&l->leaf)) {
 +		if (tp->slen == l->slen)
 +			node_pull_suffix(tp, tp->pos);
  		put_child_root(tp, l->key, NULL);
  		node_free(l);
  		trie_rebalance(t, tp);
@@@ -1505,7 -1600,7 +1594,7 @@@
  
  	/* update the trie with the latest suffix length */
  	l->slen = fa->fa_slen;
 -	leaf_pull_suffix(tp, l);
 +	node_pull_suffix(tp, fa->fa_slen);
  }
  
  /* Caller must hold RTNL. */
@@@ -1777,10 -1872,6 +1866,10 @@@ void fib_table_flush_external(struct fi
  			if (IS_TRIE(pn))
  				break;
  
 +			/* update the suffix to address pulled leaves */
 +			if (pn->slen > pn->pos)
 +				update_suffix(pn);
 +
  			/* resize completed node */
  			pn = resize(t, pn);
  			cindex = get_index(pkey, pn);
@@@ -1847,10 -1938,6 +1936,10 @@@ int fib_table_flush(struct net *net, st
  			if (IS_TRIE(pn))
  				break;
  
 +			/* update the suffix to address pulled leaves */
 +			if (pn->slen > pn->pos)
 +				update_suffix(pn);
 +
  			/* resize completed node */
  			pn = resize(t, pn);
  			cindex = get_index(pkey, pn);
@@@ -1903,6 -1990,62 +1992,62 @@@
  	return found;
  }
  
+ static void fib_leaf_notify(struct net *net, struct key_vector *l,
+ 			    struct fib_table *tb, struct notifier_block *nb,
+ 			    enum fib_event_type event_type)
+ {
+ 	struct fib_alias *fa;
+ 
+ 	hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
+ 		struct fib_info *fi = fa->fa_info;
+ 
+ 		if (!fi)
+ 			continue;
+ 
+ 		/* local and main table can share the same trie,
+ 		 * so don't notify twice for the same entry.
+ 		 */
+ 		if (tb->tb_id != fa->tb_id)
+ 			continue;
+ 
+ 		call_fib_entry_notifier(nb, net, event_type, l->key,
+ 					KEYLENGTH - fa->fa_slen, fi, fa->fa_tos,
+ 					fa->fa_type, fa->tb_id, 0);
+ 	}
+ }
+ 
+ static void fib_table_notify(struct net *net, struct fib_table *tb,
+ 			     struct notifier_block *nb,
+ 			     enum fib_event_type event_type)
+ {
+ 	struct trie *t = (struct trie *)tb->tb_data;
+ 	struct key_vector *l, *tp = t->kv;
+ 	t_key key = 0;
+ 
+ 	while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
+ 		fib_leaf_notify(net, l, tb, nb, event_type);
+ 
+ 		key = l->key + 1;
+ 		/* stop in case of wrap around */
+ 		if (key < l->key)
+ 			break;
+ 	}
+ }
+ 
+ static void fib_notify(struct net *net, struct notifier_block *nb,
+ 		       enum fib_event_type event_type)
+ {
+ 	unsigned int h;
+ 
+ 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+ 		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+ 		struct fib_table *tb;
+ 
+ 		hlist_for_each_entry_rcu(tb, head, tb_hlist)
+ 			fib_table_notify(net, tb, nb, event_type);
+ 	}
+ }
+ 
  static void __trie_free_rcu(struct rcu_head *head)
  {
  	struct fib_table *tb = container_of(head, struct fib_table, rcu);
diff --combined net/ipv4/ping.c
index 96b8e2b,d11129f..5b2635e
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@@ -657,10 -657,6 +657,10 @@@ int ping_common_sendmsg(int family, str
  	if (len > 0xFFFF)
  		return -EMSGSIZE;
  
 +	/* Must have at least a full ICMP header. */
 +	if (len < icmph_len)
 +		return -EINVAL;
 +
  	/*
  	 *	Check the flags.
  	 */
@@@ -793,7 -789,8 +793,8 @@@ static int ping_v4_sendmsg(struct sock 
  
  	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
  			   RT_SCOPE_UNIVERSE, sk->sk_protocol,
- 			   inet_sk_flowi_flags(sk), faddr, saddr, 0, 0);
+ 			   inet_sk_flowi_flags(sk), faddr, saddr, 0, 0,
+ 			   sk->sk_uid);
  
  	security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
  	rt = ip_route_output_flow(net, &fl4, sk);
diff --combined net/unix/af_unix.c
index 6f72508,1752d6b..310882f
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@@ -315,7 -315,7 +315,7 @@@ static struct sock *unix_find_socket_by
  		    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
  		struct dentry *dentry = unix_sk(s)->path.dentry;
  
 -		if (dentry && d_real_inode(dentry) == i) {
 +		if (dentry && d_backing_inode(dentry) == i) {
  			sock_hold(s);
  			goto found;
  		}
@@@ -913,7 -913,7 +913,7 @@@ static struct sock *unix_find_other(str
  		err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
  		if (err)
  			goto fail;
 -		inode = d_real_inode(path.dentry);
 +		inode = d_backing_inode(path.dentry);
  		err = inode_permission(inode, MAY_WRITE);
  		if (err)
  			goto put_fail;
@@@ -1040,7 -1040,7 +1040,7 @@@ static int unix_bind(struct socket *soc
  			goto out_up;
  		}
  		addr->hash = UNIX_HASH_SIZE;
 -		hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
 +		hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
  		spin_lock(&unix_table_lock);
  		u->path = path;
  		list = &unix_socket_table[hash];
@@@ -2113,8 -2113,8 +2113,8 @@@ static int unix_dgram_recvmsg(struct so
  		mutex_lock(&u->iolock);
  
  		skip = sk_peek_offset(sk, flags);
- 		skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err,
- 					      &last);
+ 		skb = __skb_try_recv_datagram(sk, flags, NULL, &peeked, &skip,
+ 					      &err, &last);
  		if (skb)
  			break;
  

-- 
LinuxNextTracking


More information about the linux-merge mailing list