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

batman at open-mesh.org batman at open-mesh.org
Thu Dec 8 00:15:50 CET 2016


The following commit has been merged in the master branch:
commit aacdf859371b4afbbfd1c6afd507030f9299e7c2
Merge: 31220b926d00793cb9fba8137ea739657dd485c3 862b3d2090ae3d8b10bb4ee9275fd932bc4d0d44
Author: Stephen Rothwell <sfr at canb.auug.org.au>
Date:   Wed Dec 7 10:40:55 2016 +1100

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

diff --combined MAINTAINERS
index 8633ded,331f6af..14709cc
--- 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
@@@ -577,6 -577,11 +577,11 @@@ T:	git git://linuxtv.org/anttip/media_t
  S:	Maintained
  F:	drivers/media/usb/airspy/
  
+ ALACRITECH GIGABIT ETHERNET DRIVER
+ M:	Lino Sanfilippo <LinoSanfilippo at gmx.de>
+ S:	Maintained
+ F:	drivers/net/ethernet/alacritech/*
+ 
  ALCATEL SPEEDTOUCH USB DRIVER
  M:	Duncan Sands <duncan.sands at free.fr>
  L:	linux-usb at vger.kernel.org
@@@ -1026,7 -1031,6 +1031,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 -1491,8 +1492,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 -1613,6 +1615,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 -1792,9 +1795,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 -2542,8 +2543,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 -2756,6 +2757,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 -2770,7 +2779,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 -2944,7 +2953,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 -2978,15 +2987,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 -3092,7 +3101,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 -3348,6 +3357,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 -3387,6 +3397,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
  
@@@ -5156,7 -5152,6 +5163,7 @@@ F:	include/linux/fscache*.
  FS-CRYPTO: FILE SYSTEM LEVEL ENCRYPTION SUPPORT
  M:	Theodore Y. Ts'o <tytso at mit.edu>
  M:	Jaegeuk Kim <jaegeuk at kernel.org>
 +L:	linux-fsdevel at vger.kernel.org
  S:	Supported
  F:	fs/crypto/
  F:	include/linux/fscrypto.h
@@@ -6115,6 -6110,7 +6122,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
@@@ -6301,11 -6297,9 +6309,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
  
@@@ -7579,8 -7573,10 +7587,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>
@@@ -7748,15 -7744,6 +7758,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
@@@ -7863,24 -7850,6 +7873,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
@@@ -7931,15 -7900,6 +7941,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
@@@ -8507,7 -8467,6 +8517,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>
@@@ -9018,11 -8977,9 +9027,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
@@@ -9840,7 -9797,7 +9849,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>
@@@ -10465,7 -10422,7 +10474,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
@@@ -10660,12 -10617,6 +10669,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
@@@ -11529,7 -11480,7 +11538,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>
@@@ -11715,7 -11666,6 +11724,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
  
@@@ -11976,16 -11926,6 +11985,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
@@@ -12416,12 -12356,6 +12425,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
@@@ -12988,7 -12922,7 +12997,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*
@@@ -13212,7 -13146,7 +13221,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/hisi-x5hd2.dtsi
index 506fdc1,0da76c5..c02e092
--- a/arch/arm/boot/dts/hisi-x5hd2.dtsi
+++ b/arch/arm/boot/dts/hisi-x5hd2.dtsi
@@@ -7,12 -7,10 +7,12 @@@
   * publishhed by the Free Software Foundation.
   */
  
 -#include "skeleton.dtsi"
  #include <dt-bindings/clock/hix5hd2-clock.h>
  
  / {
 +	#address-cells = <1>;
 +	#size-cells = <1>;
 +
  	aliases {
  		serial0 = &uart0;
  	};
@@@ -438,18 -436,20 +438,20 @@@
  		};
  
  		gmac0: ethernet at 1840000 {
- 			compatible = "hisilicon,hix5hd2-gmac";
+ 			compatible = "hisilicon,hix5hd2-gemac", "hisilicon,hisi-gemac-v1";
  			reg = <0x1840000 0x1000>,<0x184300c 0x4>;
  			interrupts = <0 71 4>;
  			clocks = <&clock HIX5HD2_MAC0_CLK>;
+ 			clock-names = "mac_core";
  			status = "disabled";
  		};
  
  		gmac1: ethernet at 1841000 {
- 			compatible = "hisilicon,hix5hd2-gmac";
+ 			compatible = "hisilicon,hix5hd2-gemac", "hisilicon,hisi-gemac-v1";
  			reg = <0x1841000 0x1000>,<0x1843010 0x4>;
  			interrupts = <0 72 4>;
  			clocks = <&clock HIX5HD2_MAC1_CLK>;
+ 			clock-names = "mac_core";
  			status = "disabled";
  		};
  
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/freescale/fec_main.c
index 12aef1b,ecaa7a9..38160c2
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@@ -1841,11 -1841,11 +1841,11 @@@ static int fec_enet_clk_enable(struct n
  		ret = clk_prepare_enable(fep->clk_ahb);
  		if (ret)
  			return ret;
- 		if (fep->clk_enet_out) {
- 			ret = clk_prepare_enable(fep->clk_enet_out);
- 			if (ret)
- 				goto failed_clk_enet_out;
- 		}
+ 
+ 		ret = clk_prepare_enable(fep->clk_enet_out);
+ 		if (ret)
+ 			goto failed_clk_enet_out;
+ 
  		if (fep->clk_ptp) {
  			mutex_lock(&fep->ptp_clk_mutex);
  			ret = clk_prepare_enable(fep->clk_ptp);
@@@ -1857,23 -1857,20 +1857,20 @@@
  			}
  			mutex_unlock(&fep->ptp_clk_mutex);
  		}
- 		if (fep->clk_ref) {
- 			ret = clk_prepare_enable(fep->clk_ref);
- 			if (ret)
- 				goto failed_clk_ref;
- 		}
+ 
+ 		ret = clk_prepare_enable(fep->clk_ref);
+ 		if (ret)
+ 			goto failed_clk_ref;
  	} else {
  		clk_disable_unprepare(fep->clk_ahb);
- 		if (fep->clk_enet_out)
- 			clk_disable_unprepare(fep->clk_enet_out);
+ 		clk_disable_unprepare(fep->clk_enet_out);
  		if (fep->clk_ptp) {
  			mutex_lock(&fep->ptp_clk_mutex);
  			clk_disable_unprepare(fep->clk_ptp);
  			fep->ptp_clk_on = false;
  			mutex_unlock(&fep->ptp_clk_mutex);
  		}
- 		if (fep->clk_ref)
- 			clk_disable_unprepare(fep->clk_ref);
+ 		clk_disable_unprepare(fep->clk_ref);
  	}
  
  	return 0;
@@@ -2313,8 -2310,6 +2310,8 @@@ static const struct fec_stat 
  	{ "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK },
  };
  
 +#define FEC_STATS_SIZE		(ARRAY_SIZE(fec_stats) * sizeof(u64))
 +
  static void fec_enet_update_ethtool_stats(struct net_device *dev)
  {
  	struct fec_enet_private *fep = netdev_priv(dev);
@@@ -2332,7 -2327,7 +2329,7 @@@ static void fec_enet_get_ethtool_stats(
  	if (netif_running(dev))
  		fec_enet_update_ethtool_stats(dev);
  
 -	memcpy(data, fep->ethtool_stats, ARRAY_SIZE(fec_stats) * sizeof(u64));
 +	memcpy(data, fep->ethtool_stats, FEC_STATS_SIZE);
  }
  
  static void fec_enet_get_strings(struct net_device *netdev,
@@@ -2357,24 -2352,8 +2354,14 @@@ static int fec_enet_get_sset_count(stru
  		return -EOPNOTSUPP;
  	}
  }
 +
 +#else	/* !defined(CONFIG_M5272) */
 +#define FEC_STATS_SIZE	0
 +static inline void fec_enet_update_ethtool_stats(struct net_device *dev)
 +{
 +}
  #endif /* !defined(CONFIG_M5272) */
  
- static int fec_enet_nway_reset(struct net_device *dev)
- {
- 	struct phy_device *phydev = dev->phydev;
- 
- 	if (!phydev)
- 		return -ENODEV;
- 
- 	return genphy_restart_aneg(phydev);
- }
- 
  /* ITR clock source is enet system clock (clk_ahb).
   * TCTT unit is cycle_ns * 64 cycle
   * So, the ICTT value = X us / (cycle_ns * 64)
@@@ -2574,7 -2553,7 +2561,7 @@@ static const struct ethtool_ops fec_ene
  	.get_drvinfo		= fec_enet_get_drvinfo,
  	.get_regs_len		= fec_enet_get_regs_len,
  	.get_regs		= fec_enet_get_regs,
- 	.nway_reset		= fec_enet_nway_reset,
+ 	.nway_reset		= phy_ethtool_nway_reset,
  	.get_link		= ethtool_op_get_link,
  	.get_coalesce		= fec_enet_get_coalesce,
  	.set_coalesce		= fec_enet_set_coalesce,
@@@ -3075,7 -3054,6 +3062,6 @@@ static const struct net_device_ops fec_
  	.ndo_stop		= fec_enet_close,
  	.ndo_start_xmit		= fec_enet_start_xmit,
  	.ndo_set_rx_mode	= set_multicast_list,
- 	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_validate_addr	= eth_validate_addr,
  	.ndo_tx_timeout		= fec_timeout,
  	.ndo_set_mac_address	= fec_set_mac_address,
@@@ -3301,7 -3279,8 +3287,7 @@@ fec_probe(struct platform_device *pdev
  
  	/* Init network device */
  	ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
 -				  ARRAY_SIZE(fec_stats) * sizeof(u64),
 -				  num_tx_qs, num_rx_qs);
 +				  FEC_STATS_SIZE, num_tx_qs, num_rx_qs);
  	if (!ndev)
  		return -ENOMEM;
  
diff --combined drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index bfe410e,b0448b5..3797cc7
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@@ -54,14 -54,6 +54,6 @@@ enum 
  };
  
  enum {
- 	NUM_LONG_LISTS	  = 2,
- 	NUM_MED_LISTS	  = 64,
- 	LONG_LIST_SIZE	  = (2ULL * 1024 * 1024 * 1024 / PAGE_SIZE) * 8 + 16 +
- 				MLX5_CMD_DATA_BLOCK_SIZE,
- 	MED_LIST_SIZE	  = 16 + MLX5_CMD_DATA_BLOCK_SIZE,
- };
- 
- enum {
  	MLX5_CMD_DELIVERY_STAT_OK			= 0x0,
  	MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR		= 0x1,
  	MLX5_CMD_DELIVERY_STAT_TOK_ERR			= 0x2,
@@@ -268,6 -260,11 +260,6 @@@ static void dump_buf(void *buf, int siz
  		pr_debug("\n");
  }
  
 -enum {
 -	MLX5_DRIVER_STATUS_ABORTED = 0xfe,
 -	MLX5_DRIVER_SYND = 0xbadd00de,
 -};
 -
  static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,
  				       u32 *synd, u8 *status)
  {
@@@ -313,6 -310,8 +305,8 @@@
  	case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY:
  	case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT:
  	case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER:
+ 	case MLX5_CMD_OP_DESTROY_SCHEDULING_ELEMENT:
+ 	case MLX5_CMD_OP_DESTROY_QOS_PARA_VPORT:
  		return MLX5_CMD_STAT_OK;
  
  	case MLX5_CMD_OP_QUERY_HCA_CAP:
@@@ -414,11 -413,14 +408,14 @@@
  	case MLX5_CMD_OP_QUERY_FLOW_TABLE:
  	case MLX5_CMD_OP_CREATE_FLOW_GROUP:
  	case MLX5_CMD_OP_QUERY_FLOW_GROUP:
- 
  	case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY:
  	case MLX5_CMD_OP_ALLOC_FLOW_COUNTER:
  	case MLX5_CMD_OP_QUERY_FLOW_COUNTER:
  	case MLX5_CMD_OP_ALLOC_ENCAP_HEADER:
+ 	case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT:
+ 	case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT:
+ 	case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT:
+ 	case MLX5_CMD_OP_CREATE_QOS_PARA_VPORT:
  		*status = MLX5_DRIVER_STATUS_ABORTED;
  		*synd = MLX5_DRIVER_SYND;
  		return -EIO;
@@@ -575,6 -577,12 +572,12 @@@ const char *mlx5_command_str(int comman
  	MLX5_COMMAND_STR_CASE(MODIFY_FLOW_TABLE);
  	MLX5_COMMAND_STR_CASE(ALLOC_ENCAP_HEADER);
  	MLX5_COMMAND_STR_CASE(DEALLOC_ENCAP_HEADER);
+ 	MLX5_COMMAND_STR_CASE(CREATE_SCHEDULING_ELEMENT);
+ 	MLX5_COMMAND_STR_CASE(DESTROY_SCHEDULING_ELEMENT);
+ 	MLX5_COMMAND_STR_CASE(QUERY_SCHEDULING_ELEMENT);
+ 	MLX5_COMMAND_STR_CASE(MODIFY_SCHEDULING_ELEMENT);
+ 	MLX5_COMMAND_STR_CASE(CREATE_QOS_PARA_VPORT);
+ 	MLX5_COMMAND_STR_CASE(DESTROY_QOS_PARA_VPORT);
  	default: return "unknown command opcode";
  	}
  }
@@@ -1058,14 -1066,13 +1061,13 @@@ static struct mlx5_cmd_mailbox *alloc_c
  	if (!mailbox)
  		return ERR_PTR(-ENOMEM);
  
- 	mailbox->buf = pci_pool_alloc(dev->cmd.pool, flags,
- 				      &mailbox->dma);
+ 	mailbox->buf = pci_pool_zalloc(dev->cmd.pool, flags,
+ 				       &mailbox->dma);
  	if (!mailbox->buf) {
  		mlx5_core_dbg(dev, "failed allocation\n");
  		kfree(mailbox);
  		return ERR_PTR(-ENOMEM);
  	}
- 	memset(mailbox->buf, 0, sizeof(struct mlx5_cmd_prot_block));
  	mailbox->next = NULL;
  
  	return mailbox;
@@@ -1356,10 -1363,10 +1358,10 @@@ static void free_msg(struct mlx5_core_d
  {
  	unsigned long flags;
  
- 	if (msg->cache) {
- 		spin_lock_irqsave(&msg->cache->lock, flags);
- 		list_add_tail(&msg->list, &msg->cache->head);
- 		spin_unlock_irqrestore(&msg->cache->lock, flags);
+ 	if (msg->parent) {
+ 		spin_lock_irqsave(&msg->parent->lock, flags);
+ 		list_add_tail(&msg->list, &msg->parent->head);
+ 		spin_unlock_irqrestore(&msg->parent->lock, flags);
  	} else {
  		mlx5_free_cmd_msg(dev, msg);
  	}
@@@ -1456,30 -1463,37 +1458,37 @@@ static struct mlx5_cmd_msg *alloc_msg(s
  				      gfp_t gfp)
  {
  	struct mlx5_cmd_msg *msg = ERR_PTR(-ENOMEM);
+ 	struct cmd_msg_cache *ch = NULL;
  	struct mlx5_cmd *cmd = &dev->cmd;
- 	struct cache_ent *ent = NULL;
- 
- 	if (in_size > MED_LIST_SIZE && in_size <= LONG_LIST_SIZE)
- 		ent = &cmd->cache.large;
- 	else if (in_size > 16 && in_size <= MED_LIST_SIZE)
- 		ent = &cmd->cache.med;
- 
- 	if (ent) {
- 		spin_lock_irq(&ent->lock);
- 		if (!list_empty(&ent->head)) {
- 			msg = list_entry(ent->head.next, typeof(*msg), list);
- 			/* For cached lists, we must explicitly state what is
- 			 * the real size
- 			 */
- 			msg->len = in_size;
- 			list_del(&msg->list);
+ 	int i;
+ 
+ 	if (in_size <= 16)
+ 		goto cache_miss;
+ 
+ 	for (i = 0; i < MLX5_NUM_COMMAND_CACHES; i++) {
+ 		ch = &cmd->cache[i];
+ 		if (in_size > ch->max_inbox_size)
+ 			continue;
+ 		spin_lock_irq(&ch->lock);
+ 		if (list_empty(&ch->head)) {
+ 			spin_unlock_irq(&ch->lock);
+ 			continue;
  		}
- 		spin_unlock_irq(&ent->lock);
+ 		msg = list_entry(ch->head.next, typeof(*msg), list);
+ 		/* For cached lists, we must explicitly state what is
+ 		 * the real size
+ 		 */
+ 		msg->len = in_size;
+ 		list_del(&msg->list);
+ 		spin_unlock_irq(&ch->lock);
+ 		break;
  	}
  
- 	if (IS_ERR(msg))
- 		msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
+ 	if (!IS_ERR(msg))
+ 		return msg;
  
+ cache_miss:
+ 	msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
  	return msg;
  }
  
@@@ -1577,58 -1591,56 +1586,56 @@@ EXPORT_SYMBOL(mlx5_cmd_exec_cb)
  
  static void destroy_msg_cache(struct mlx5_core_dev *dev)
  {
- 	struct mlx5_cmd *cmd = &dev->cmd;
+ 	struct cmd_msg_cache *ch;
  	struct mlx5_cmd_msg *msg;
  	struct mlx5_cmd_msg *n;
+ 	int i;
  
- 	list_for_each_entry_safe(msg, n, &cmd->cache.large.head, list) {
- 		list_del(&msg->list);
- 		mlx5_free_cmd_msg(dev, msg);
- 	}
- 
- 	list_for_each_entry_safe(msg, n, &cmd->cache.med.head, list) {
- 		list_del(&msg->list);
- 		mlx5_free_cmd_msg(dev, msg);
+ 	for (i = 0; i < MLX5_NUM_COMMAND_CACHES; i++) {
+ 		ch = &dev->cmd.cache[i];
+ 		list_for_each_entry_safe(msg, n, &ch->head, list) {
+ 			list_del(&msg->list);
+ 			mlx5_free_cmd_msg(dev, msg);
+ 		}
  	}
  }
  
- static int create_msg_cache(struct mlx5_core_dev *dev)
+ static unsigned cmd_cache_num_ent[MLX5_NUM_COMMAND_CACHES] = {
+ 	512, 32, 16, 8, 2
+ };
+ 
+ static unsigned cmd_cache_ent_size[MLX5_NUM_COMMAND_CACHES] = {
+ 	16 + MLX5_CMD_DATA_BLOCK_SIZE,
+ 	16 + MLX5_CMD_DATA_BLOCK_SIZE * 2,
+ 	16 + MLX5_CMD_DATA_BLOCK_SIZE * 16,
+ 	16 + MLX5_CMD_DATA_BLOCK_SIZE * 256,
+ 	16 + MLX5_CMD_DATA_BLOCK_SIZE * 512,
+ };
+ 
+ static void create_msg_cache(struct mlx5_core_dev *dev)
  {
  	struct mlx5_cmd *cmd = &dev->cmd;
+ 	struct cmd_msg_cache *ch;
  	struct mlx5_cmd_msg *msg;
- 	int err;
  	int i;
- 
- 	spin_lock_init(&cmd->cache.large.lock);
- 	INIT_LIST_HEAD(&cmd->cache.large.head);
- 	spin_lock_init(&cmd->cache.med.lock);
- 	INIT_LIST_HEAD(&cmd->cache.med.head);
- 
- 	for (i = 0; i < NUM_LONG_LISTS; i++) {
- 		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE, 0);
- 		if (IS_ERR(msg)) {
- 			err = PTR_ERR(msg);
- 			goto ex_err;
- 		}
- 		msg->cache = &cmd->cache.large;
- 		list_add_tail(&msg->list, &cmd->cache.large.head);
- 	}
- 
- 	for (i = 0; i < NUM_MED_LISTS; i++) {
- 		msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE, 0);
- 		if (IS_ERR(msg)) {
- 			err = PTR_ERR(msg);
- 			goto ex_err;
+ 	int k;
+ 
+ 	/* Initialize and fill the caches with initial entries */
+ 	for (k = 0; k < MLX5_NUM_COMMAND_CACHES; k++) {
+ 		ch = &cmd->cache[k];
+ 		spin_lock_init(&ch->lock);
+ 		INIT_LIST_HEAD(&ch->head);
+ 		ch->num_ent = cmd_cache_num_ent[k];
+ 		ch->max_inbox_size = cmd_cache_ent_size[k];
+ 		for (i = 0; i < ch->num_ent; i++) {
+ 			msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL | __GFP_NOWARN,
+ 						 ch->max_inbox_size, 0);
+ 			if (IS_ERR(msg))
+ 				break;
+ 			msg->parent = ch;
+ 			list_add_tail(&msg->list, &ch->head);
  		}
- 		msg->cache = &cmd->cache.med;
- 		list_add_tail(&msg->list, &cmd->cache.med.head);
  	}
- 
- 	return 0;
- 
- ex_err:
- 	destroy_msg_cache(dev);
- 	return err;
  }
  
  static int alloc_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd)
@@@ -1751,11 -1763,7 +1758,7 @@@ int mlx5_cmd_init(struct mlx5_core_dev 
  
  	cmd->mode = CMD_MODE_POLLING;
  
- 	err = create_msg_cache(dev);
- 	if (err) {
- 		dev_err(&dev->pdev->dev, "failed to create command cache\n");
- 		goto err_free_page;
- 	}
+ 	create_msg_cache(dev);
  
  	set_wqname(dev);
  	cmd->wq = create_singlethread_workqueue(cmd->wq_name);
diff --combined drivers/net/ethernet/mellanox/mlx5/core/en.h
index 71382df,63dd639..951dbd5
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@@ -77,9 -77,9 +77,9 @@@
  						 MLX5_MPWRQ_WQE_PAGE_ORDER)
  
  #define MLX5_MTT_OCTW(npages) (ALIGN(npages, 8) / 2)
- #define MLX5E_REQUIRED_MTTS(rqs, wqes)\
- 	(rqs * wqes * ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8))
- #define MLX5E_VALID_NUM_MTTS(num_mtts) (MLX5_MTT_OCTW(num_mtts) <= U16_MAX)
+ #define MLX5E_REQUIRED_MTTS(wqes)		\
+ 	(wqes * ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8))
+ #define MLX5E_VALID_NUM_MTTS(num_mtts) (MLX5_MTT_OCTW(num_mtts) - 1 <= U16_MAX)
  
  #define MLX5_UMR_ALIGN				(2048)
  #define MLX5_MPWRQ_SMALL_PACKET_THRESHOLD	(128)
@@@ -150,12 -150,6 +150,6 @@@ static inline int mlx5_max_log_rq_size(
  	}
  }
  
- enum {
- 	MLX5E_INLINE_MODE_L2,
- 	MLX5E_INLINE_MODE_VPORT_CONTEXT,
- 	MLX5_INLINE_MODE_NOT_REQUIRED,
- };
- 
  struct mlx5e_tx_wqe {
  	struct mlx5_wqe_ctrl_seg ctrl;
  	struct mlx5_wqe_eth_seg  eth;
@@@ -173,22 -167,28 +167,28 @@@ struct mlx5e_umr_wqe 
  	struct mlx5_wqe_data_seg       data;
  };
  
+ extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
+ 
  static const char mlx5e_priv_flags[][ETH_GSTRING_LEN] = {
  	"rx_cqe_moder",
+ 	"rx_cqe_compress",
  };
  
  enum mlx5e_priv_flag {
  	MLX5E_PFLAG_RX_CQE_BASED_MODER = (1 << 0),
+ 	MLX5E_PFLAG_RX_CQE_COMPRESS = (1 << 1),
  };
  
- #define MLX5E_SET_PRIV_FLAG(priv, pflag, enable)    \
- 	do {                                        \
- 		if (enable)                         \
- 			priv->pflags |= pflag;      \
- 		else                                \
- 			priv->pflags &= ~pflag;     \
+ #define MLX5E_SET_PFLAG(priv, pflag, enable)			\
+ 	do {							\
+ 		if (enable)					\
+ 			(priv)->params.pflags |= (pflag);	\
+ 		else						\
+ 			(priv)->params.pflags &= ~(pflag);	\
  	} while (0)
  
+ #define MLX5E_GET_PFLAG(priv, pflag) (!!((priv)->params.pflags & (pflag)))
+ 
  #ifdef CONFIG_MLX5_CORE_EN_DCB
  #define MLX5E_MAX_BW_ALLOC 100 /* Max percentage of BW allocation */
  #endif
@@@ -207,8 -207,7 +207,7 @@@ struct mlx5e_params 
  	u16 num_channels;
  	u8  num_tc;
  	u8  rx_cq_period_mode;
- 	bool rx_cqe_compress_admin;
- 	bool rx_cqe_compress;
+ 	bool rx_cqe_compress_def;
  	struct mlx5e_cq_moder rx_cq_moderation;
  	struct mlx5e_cq_moder tx_cq_moderation;
  	u16 min_rx_wqes;
@@@ -220,12 -219,34 +219,34 @@@
  	u8  toeplitz_hash_key[40];
  	u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE];
  	bool vlan_strip_disable;
- #ifdef CONFIG_MLX5_CORE_EN_DCB
- 	struct ieee_ets ets;
- #endif
  	bool rx_am_enabled;
  	u32 lro_timeout;
+ 	u32 pflags;
+ };
+ 
+ #ifdef CONFIG_MLX5_CORE_EN_DCB
+ struct mlx5e_cee_config {
+ 	/* bw pct for priority group */
+ 	u8                         pg_bw_pct[CEE_DCBX_MAX_PGS];
+ 	u8                         prio_to_pg_map[CEE_DCBX_MAX_PRIO];
+ 	bool                       pfc_setting[CEE_DCBX_MAX_PRIO];
+ 	bool                       pfc_enable;
+ };
+ 
+ enum {
+ 	MLX5_DCB_CHG_RESET,
+ 	MLX5_DCB_NO_CHG,
+ 	MLX5_DCB_CHG_NO_RESET,
+ };
+ 
+ struct mlx5e_dcbx {
+ 	enum mlx5_dcbx_oper_mode   mode;
+ 	struct mlx5e_cee_config    cee_cfg; /* pending configuration */
+ 
+ 	/* The only setting that cannot be read from FW */
+ 	u8                         tc_tsa[IEEE_8021QAZ_MAX_TCS];
  };
+ #endif
  
  struct mlx5e_tstamp {
  	rwlock_t                   lock;
@@@ -241,7 -262,7 +262,7 @@@
  };
  
  enum {
 -	MLX5E_RQ_STATE_FLUSH,
 +	MLX5E_RQ_STATE_ENABLED,
  	MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS,
  	MLX5E_RQ_STATE_AM,
  };
@@@ -265,7 -286,7 +286,7 @@@ struct mlx5e_cq 
  	u16                        decmprs_wqe_counter;
  
  	/* control */
- 	struct mlx5_wq_ctrl        wq_ctrl;
+ 	struct mlx5_frag_wq_ctrl   wq_ctrl;
  } ____cacheline_aligned_in_smp;
  
  struct mlx5e_rq;
@@@ -326,7 -347,6 +347,6 @@@ struct mlx5e_rq 
  		struct {
  			struct mlx5e_mpw_info *info;
  			void                  *mtt_no_align;
- 			u32                    mtt_offset;
  		} mpwqe;
  	};
  	struct {
@@@ -361,6 -381,7 +381,7 @@@
  	u32                    rqn;
  	struct mlx5e_channel  *channel;
  	struct mlx5e_priv     *priv;
+ 	struct mlx5_core_mkey  umr_mkey;
  } ____cacheline_aligned_in_smp;
  
  struct mlx5e_umr_dma_info {
@@@ -394,7 -415,7 +415,7 @@@ struct mlx5e_sq_dma 
  };
  
  enum {
 -	MLX5E_SQ_STATE_FLUSH,
 +	MLX5E_SQ_STATE_ENABLED,
  	MLX5E_SQ_STATE_BF_ENABLE,
  };
  
@@@ -524,7 -545,7 +545,7 @@@ struct mlx5e_vxlan_db 
  
  struct mlx5e_l2_rule {
  	u8  addr[ETH_ALEN + 2];
- 	struct mlx5_flow_rule *rule;
+ 	struct mlx5_flow_handle *rule;
  };
  
  struct mlx5e_flow_table {
@@@ -545,10 -566,10 +566,10 @@@ struct mlx5e_tc_table 
  struct mlx5e_vlan_table {
  	struct mlx5e_flow_table		ft;
  	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
- 	struct mlx5_flow_rule	*active_vlans_rule[VLAN_N_VID];
- 	struct mlx5_flow_rule	*untagged_rule;
- 	struct mlx5_flow_rule	*any_vlan_rule;
- 	bool          filter_disabled;
+ 	struct mlx5_flow_handle	*active_vlans_rule[VLAN_N_VID];
+ 	struct mlx5_flow_handle	*untagged_rule;
+ 	struct mlx5_flow_handle	*any_vlan_rule;
+ 	bool		filter_disabled;
  };
  
  struct mlx5e_l2_table {
@@@ -566,14 -587,14 +587,14 @@@
  /* L3/L4 traffic type classifier */
  struct mlx5e_ttc_table {
  	struct mlx5e_flow_table  ft;
- 	struct mlx5_flow_rule	 *rules[MLX5E_NUM_TT];
+ 	struct mlx5_flow_handle	 *rules[MLX5E_NUM_TT];
  };
  
  #define ARFS_HASH_SHIFT BITS_PER_BYTE
  #define ARFS_HASH_SIZE BIT(BITS_PER_BYTE)
  struct arfs_table {
  	struct mlx5e_flow_table  ft;
- 	struct mlx5_flow_rule    *default_rule;
+ 	struct mlx5_flow_handle	 *default_rule;
  	struct hlist_head	 rules_hash[ARFS_HASH_SIZE];
  };
  
@@@ -668,7 -689,6 +689,6 @@@ struct mlx5e_priv 
  
  	unsigned long              state;
  	struct mutex               state_lock; /* Protects Interface state */
- 	struct mlx5_core_mkey      umr_mkey;
  	struct mlx5e_rq            drop_rq;
  
  	struct mlx5e_channel     **channel;
@@@ -688,12 -708,15 +708,15 @@@
  	struct work_struct         tx_timeout_work;
  	struct delayed_work        update_stats_work;
  
- 	u32                        pflags;
  	struct mlx5_core_dev      *mdev;
  	struct net_device         *netdev;
  	struct mlx5e_stats         stats;
  	struct mlx5e_tstamp        tstamp;
  	u16 q_counter;
+ #ifdef CONFIG_MLX5_CORE_EN_DCB
+ 	struct mlx5e_dcbx          dcbx;
+ #endif
+ 
  	const struct mlx5e_profile *profile;
  	void                      *ppriv;
  };
@@@ -735,6 -758,9 +758,9 @@@ int mlx5e_create_flow_steering(struct m
  void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv);
  void mlx5e_init_l2_addr(struct mlx5e_priv *priv);
  void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft);
+ int mlx5e_self_test_num(struct mlx5e_priv *priv);
+ void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
+ 		     u64 *buf);
  int mlx5e_ethtool_get_flow(struct mlx5e_priv *priv, struct ethtool_rxnfc *info,
  			   int location);
  int mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,
@@@ -811,8 -837,7 +837,7 @@@ static inline void mlx5e_cq_arm(struct 
  
  static inline u32 mlx5e_get_wqe_mtt_offset(struct mlx5e_rq *rq, u16 wqe_ix)
  {
- 	return rq->mpwqe.mtt_offset +
- 		wqe_ix * ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8);
+ 	return wqe_ix * ALIGN(MLX5_MPWRQ_PAGES_PER_WQE, 8);
  }
  
  static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
@@@ -825,6 -850,7 +850,7 @@@ extern const struct ethtool_ops mlx5e_e
  #ifdef CONFIG_MLX5_CORE_EN_DCB
  extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
  int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets);
+ void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv);
  #endif
  
  #ifndef CONFIG_RFS_ACCEL
@@@ -860,7 -886,8 +886,8 @@@ void mlx5e_destroy_tir(struct mlx5_core
  		       struct mlx5e_tir *tir);
  int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev);
  void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev);
- int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5_core_dev *mdev);
+ int mlx5e_refresh_tirs_self_loopback(struct mlx5_core_dev *mdev,
+ 				     bool enable_uc_lb);
  
  struct mlx5_eswitch_rep;
  int mlx5e_vport_rep_load(struct mlx5_eswitch *esw,
@@@ -874,6 -901,7 +901,7 @@@ int mlx5e_add_sqs_fwd_rules(struct mlx5
  void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv);
  int mlx5e_attr_get(struct net_device *dev, struct switchdev_attr *attr);
  void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
+ void mlx5e_update_hw_rep_counters(struct mlx5e_priv *priv);
  
  int mlx5e_create_direct_rqts(struct mlx5e_priv *priv);
  void mlx5e_destroy_rqt(struct mlx5e_priv *priv, struct mlx5e_rqt *rqt);
@@@ -890,8 -918,16 +918,16 @@@ struct net_device *mlx5e_create_netdev(
  void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv);
  int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
  void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
- struct rtnl_link_stats64 *
- mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
  u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout);
+ void mlx5e_add_vxlan_port(struct net_device *netdev,
+ 			  struct udp_tunnel_info *ti);
+ void mlx5e_del_vxlan_port(struct net_device *netdev,
+ 			  struct udp_tunnel_info *ti);
+ 
+ int mlx5e_get_offload_stats(int attr_id, const struct net_device *dev,
+ 			    void *sp);
+ bool mlx5e_has_offload_stats(const struct net_device *dev, int attr_id);
  
+ bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv);
+ bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv);
  #endif /* __MLX5_EN_H__ */
diff --combined drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 246d98e,9def5cc..0702027
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@@ -84,7 -84,8 +84,8 @@@ static void mlx5e_set_rq_type_params(st
  	switch (priv->params.rq_wq_type) {
  	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
  		priv->params.log_rq_size = MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE_MPW;
- 		priv->params.mpwqe_log_stride_sz = priv->params.rx_cqe_compress ?
+ 		priv->params.mpwqe_log_stride_sz =
+ 			MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS) ?
  			MLX5_MPWRQ_LOG_STRIDE_SIZE_CQE_COMPRESS :
  			MLX5_MPWRQ_LOG_STRIDE_SIZE;
  		priv->params.mpwqe_log_num_strides = MLX5_MPWRQ_LOG_WQE_SZ -
@@@ -101,7 -102,7 +102,7 @@@
  		       priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ,
  		       BIT(priv->params.log_rq_size),
  		       BIT(priv->params.mpwqe_log_stride_sz),
- 		       priv->params.rx_cqe_compress_admin);
+ 		       MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS));
  }
  
  static void mlx5e_set_rq_priv_params(struct mlx5e_priv *priv)
@@@ -290,12 -291,36 +291,36 @@@ static void mlx5e_update_q_counter(stru
  				      &qcnt->rx_out_of_buffer);
  }
  
+ static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv)
+ {
+ 	struct mlx5e_pcie_stats *pcie_stats = &priv->stats.pcie;
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+ 	int sz = MLX5_ST_SZ_BYTES(mpcnt_reg);
+ 	void *out;
+ 	u32 *in;
+ 
+ 	in = mlx5_vzalloc(sz);
+ 	if (!in)
+ 		return;
+ 
+ 	out = pcie_stats->pcie_perf_counters;
+ 	MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
+ 	mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0);
+ 
+ 	out = pcie_stats->pcie_tas_counters;
+ 	MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP);
+ 	mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0);
+ 
+ 	kvfree(in);
+ }
+ 
  void mlx5e_update_stats(struct mlx5e_priv *priv)
  {
  	mlx5e_update_q_counter(priv);
  	mlx5e_update_vport_counters(priv);
  	mlx5e_update_pport_counters(priv);
  	mlx5e_update_sw_counters(priv);
+ 	mlx5e_update_pcie_counters(priv);
  }
  
  void mlx5e_update_stats_work(struct work_struct *work)
@@@ -446,14 -471,50 +471,50 @@@ static void mlx5e_rq_free_mpwqe_info(st
  	kfree(rq->mpwqe.info);
  }
  
- static bool mlx5e_is_vf_vport_rep(struct mlx5e_priv *priv)
+ static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv,
+ 				 u64 npages, u8 page_shift,
+ 				 struct mlx5_core_mkey *umr_mkey)
  {
- 	struct mlx5_eswitch_rep *rep = (struct mlx5_eswitch_rep *)priv->ppriv;
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+ 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+ 	void *mkc;
+ 	u32 *in;
+ 	int err;
+ 
+ 	if (!MLX5E_VALID_NUM_MTTS(npages))
+ 		return -EINVAL;
+ 
+ 	in = mlx5_vzalloc(inlen);
+ 	if (!in)
+ 		return -ENOMEM;
+ 
+ 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
+ 
+ 	MLX5_SET(mkc, mkc, free, 1);
+ 	MLX5_SET(mkc, mkc, umr_en, 1);
+ 	MLX5_SET(mkc, mkc, lw, 1);
+ 	MLX5_SET(mkc, mkc, lr, 1);
+ 	MLX5_SET(mkc, mkc, access_mode, MLX5_MKC_ACCESS_MODE_MTT);
+ 
+ 	MLX5_SET(mkc, mkc, qpn, 0xffffff);
+ 	MLX5_SET(mkc, mkc, pd, mdev->mlx5e_res.pdn);
+ 	MLX5_SET64(mkc, mkc, len, npages << page_shift);
+ 	MLX5_SET(mkc, mkc, translations_octword_size,
+ 		 MLX5_MTT_OCTW(npages));
+ 	MLX5_SET(mkc, mkc, log_page_size, page_shift);
  
- 	if (rep && rep->vport != FDB_UPLINK_VPORT)
- 		return true;
+ 	err = mlx5_core_create_mkey(mdev, umr_mkey, in, inlen);
  
- 	return false;
+ 	kvfree(in);
+ 	return err;
+ }
+ 
+ static int mlx5e_create_rq_umr_mkey(struct mlx5e_rq *rq)
+ {
+ 	struct mlx5e_priv *priv = rq->priv;
+ 	u64 num_mtts = MLX5E_REQUIRED_MTTS(BIT(priv->params.log_rq_size));
+ 
+ 	return mlx5e_create_umr_mkey(priv, num_mtts, PAGE_SHIFT, &rq->umr_mkey);
  }
  
  static int mlx5e_create_rq(struct mlx5e_channel *c,
@@@ -489,7 -550,13 +550,13 @@@
  	rq->channel = c;
  	rq->ix      = c->ix;
  	rq->priv    = c->priv;
- 	rq->xdp_prog = priv->xdp_prog;
+ 
+ 	rq->xdp_prog = priv->xdp_prog ? bpf_prog_inc(priv->xdp_prog) : NULL;
+ 	if (IS_ERR(rq->xdp_prog)) {
+ 		err = PTR_ERR(rq->xdp_prog);
+ 		rq->xdp_prog = NULL;
+ 		goto err_rq_wq_destroy;
+ 	}
  
  	rq->buff.map_dir = DMA_FROM_DEVICE;
  	if (rq->xdp_prog)
@@@ -506,18 -573,20 +573,20 @@@
  		rq->alloc_wqe = mlx5e_alloc_rx_mpwqe;
  		rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe;
  
- 		rq->mpwqe.mtt_offset = c->ix *
- 			MLX5E_REQUIRED_MTTS(1, BIT(priv->params.log_rq_size));
- 
  		rq->mpwqe_stride_sz = BIT(priv->params.mpwqe_log_stride_sz);
  		rq->mpwqe_num_strides = BIT(priv->params.mpwqe_log_num_strides);
  
  		rq->buff.wqe_sz = rq->mpwqe_stride_sz * rq->mpwqe_num_strides;
  		byte_count = rq->buff.wqe_sz;
- 		rq->mkey_be = cpu_to_be32(c->priv->umr_mkey.key);
- 		err = mlx5e_rq_alloc_mpwqe_info(rq, c);
+ 
+ 		err = mlx5e_create_rq_umr_mkey(rq);
  		if (err)
  			goto err_rq_wq_destroy;
+ 		rq->mkey_be = cpu_to_be32(rq->umr_mkey.key);
+ 
+ 		err = mlx5e_rq_alloc_mpwqe_info(rq, c);
+ 		if (err)
+ 			goto err_destroy_umr_mkey;
  		break;
  	default: /* MLX5_WQ_TYPE_LINKED_LIST */
  		rq->dma_info = kzalloc_node(wq_sz * sizeof(*rq->dma_info),
@@@ -566,12 -635,14 +635,14 @@@
  	rq->page_cache.head = 0;
  	rq->page_cache.tail = 0;
  
- 	if (rq->xdp_prog)
- 		bpf_prog_add(rq->xdp_prog, 1);
- 
  	return 0;
  
+ err_destroy_umr_mkey:
+ 	mlx5_core_destroy_mkey(mdev, &rq->umr_mkey);
+ 
  err_rq_wq_destroy:
+ 	if (rq->xdp_prog)
+ 		bpf_prog_put(rq->xdp_prog);
  	mlx5_wq_destroy(&rq->wq_ctrl);
  
  	return err;
@@@ -587,6 -658,7 +658,7 @@@ static void mlx5e_destroy_rq(struct mlx
  	switch (rq->wq_type) {
  	case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
  		mlx5e_rq_free_mpwqe_info(rq);
+ 		mlx5_core_destroy_mkey(rq->priv->mdev, &rq->umr_mkey);
  		break;
  	default: /* MLX5_WQ_TYPE_LINKED_LIST */
  		kfree(rq->dma_info);
@@@ -759,7 -831,6 +831,7 @@@ static int mlx5e_open_rq(struct mlx5e_c
  	if (err)
  		goto err_destroy_rq;
  
 +	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
  	err = mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
  	if (err)
  		goto err_disable_rq;
@@@ -774,7 -845,6 +846,7 @@@
  	return 0;
  
  err_disable_rq:
 +	clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
  	mlx5e_disable_rq(rq);
  err_destroy_rq:
  	mlx5e_destroy_rq(rq);
@@@ -784,7 -854,7 +856,7 @@@
  
  static void mlx5e_close_rq(struct mlx5e_rq *rq)
  {
 -	set_bit(MLX5E_RQ_STATE_FLUSH, &rq->state);
 +	clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
  	napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
  	cancel_work_sync(&rq->am.work);
  
@@@ -940,7 -1010,7 +1012,7 @@@ static int mlx5e_create_sq(struct mlx5e
  	sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2;
  	sq->max_inline  = param->max_inline;
  	sq->min_inline_mode =
- 		MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5E_INLINE_MODE_VPORT_CONTEXT ?
+ 		MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5_CAP_INLINE_MODE_VPORT_CONTEXT ?
  		param->min_inline_mode : 0;
  
  	err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu));
@@@ -1008,6 -1078,7 +1080,6 @@@ static int mlx5e_enable_sq(struct mlx5e
  	MLX5_SET(sqc,  sqc, min_wqe_inline_mode, sq->min_inline_mode);
  	MLX5_SET(sqc,  sqc, state,		MLX5_SQC_STATE_RST);
  	MLX5_SET(sqc,  sqc, tis_lst_sz, param->type == MLX5E_SQ_ICO ? 0 : 1);
 -	MLX5_SET(sqc,  sqc, flush_in_error_en,	1);
  
  	MLX5_SET(wq,   wq, wq_type,       MLX5_WQ_TYPE_CYCLIC);
  	MLX5_SET(wq,   wq, uar_page,      sq->uar.index);
@@@ -1084,7 -1155,6 +1156,7 @@@ static int mlx5e_open_sq(struct mlx5e_c
  	if (err)
  		goto err_destroy_sq;
  
 +	set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
  	err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
  			      false, 0);
  	if (err)
@@@ -1098,7 -1168,6 +1170,7 @@@
  	return 0;
  
  err_disable_sq:
 +	clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
  	mlx5e_disable_sq(sq);
  err_destroy_sq:
  	mlx5e_destroy_sq(sq);
@@@ -1115,7 -1184,7 +1187,7 @@@ static inline void netif_tx_disable_que
  
  static void mlx5e_close_sq(struct mlx5e_sq *sq)
  {
 -	set_bit(MLX5E_SQ_STATE_FLUSH, &sq->state);
 +	clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
  	/* prevent netif_tx_wake_queue */
  	napi_synchronize(&sq->channel->napi);
  
@@@ -1184,7 -1253,7 +1256,7 @@@ static int mlx5e_create_cq(struct mlx5e
  
  static void mlx5e_destroy_cq(struct mlx5e_cq *cq)
  {
- 	mlx5_wq_destroy(&cq->wq_ctrl);
+ 	mlx5_cqwq_destroy(&cq->wq_ctrl);
  }
  
  static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
@@@ -1201,7 -1270,7 +1273,7 @@@
  	int err;
  
  	inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
- 		sizeof(u64) * cq->wq_ctrl.buf.npages;
+ 		sizeof(u64) * cq->wq_ctrl.frag_buf.npages;
  	in = mlx5_vzalloc(inlen);
  	if (!in)
  		return -ENOMEM;
@@@ -1210,15 -1279,15 +1282,15 @@@
  
  	memcpy(cqc, param->cqc, sizeof(param->cqc));
  
- 	mlx5_fill_page_array(&cq->wq_ctrl.buf,
- 			     (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
+ 	mlx5_fill_page_frag_array(&cq->wq_ctrl.frag_buf,
+ 				  (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
  
  	mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
  
  	MLX5_SET(cqc,   cqc, cq_period_mode, param->cq_period_mode);
  	MLX5_SET(cqc,   cqc, c_eqn,         eqn);
  	MLX5_SET(cqc,   cqc, uar_page,      mcq->uar->index);
- 	MLX5_SET(cqc,   cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
+ 	MLX5_SET(cqc,   cqc, log_page_size, cq->wq_ctrl.frag_buf.page_shift -
  					    MLX5_ADAPTER_PAGE_SHIFT);
  	MLX5_SET64(cqc, cqc, dbr_addr,      cq->wq_ctrl.db.dma);
  
@@@ -1536,7 -1605,6 +1608,6 @@@ err_close_icosq_cq
  
  err_napi_del:
  	netif_napi_del(&c->napi);
- 	napi_hash_del(&c->napi);
  	kfree(c);
  
  	return err;
@@@ -1557,9 -1625,6 +1628,6 @@@ static void mlx5e_close_channel(struct 
  	mlx5e_close_cq(&c->icosq.cq);
  	netif_napi_del(&c->napi);
  
- 	napi_hash_del(&c->napi);
- 	synchronize_rcu();
- 
  	kfree(c);
  }
  
@@@ -1652,7 -1717,7 +1720,7 @@@ static void mlx5e_build_rx_cq_param(str
  	}
  
  	MLX5_SET(cqc, cqc, log_cq_size, log_cq_size);
- 	if (priv->params.rx_cqe_compress) {
+ 	if (MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS)) {
  		MLX5_SET(cqc, cqc, mini_cqe_res_format, MLX5_CQE_FORMAT_CSUM);
  		MLX5_SET(cqc, cqc, cqe_comp_en, 1);
  	}
@@@ -2124,7 -2189,7 +2192,7 @@@ int mlx5e_open_locked(struct net_devic
  		goto err_clear_state_opened_flag;
  	}
  
- 	err = mlx5e_refresh_tirs_self_loopback_enable(priv->mdev);
+ 	err = mlx5e_refresh_tirs_self_loopback(priv->mdev, false);
  	if (err) {
  		netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
  			   __func__, err);
@@@ -2642,7 -2707,7 +2710,7 @@@ mqprio
  	return mlx5e_setup_tc(dev, tc->tc);
  }
  
- struct rtnl_link_stats64 *
+ static struct rtnl_link_stats64 *
  mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
  {
  	struct mlx5e_priv *priv = netdev_priv(dev);
@@@ -2650,13 -2715,20 +2718,20 @@@
  	struct mlx5e_vport_stats *vstats = &priv->stats.vport;
  	struct mlx5e_pport_stats *pstats = &priv->stats.pport;
  
- 	stats->rx_packets = sstats->rx_packets;
- 	stats->rx_bytes   = sstats->rx_bytes;
- 	stats->tx_packets = sstats->tx_packets;
- 	stats->tx_bytes   = sstats->tx_bytes;
+ 	if (mlx5e_is_uplink_rep(priv)) {
+ 		stats->rx_packets = PPORT_802_3_GET(pstats, a_frames_received_ok);
+ 		stats->rx_bytes   = PPORT_802_3_GET(pstats, a_octets_received_ok);
+ 		stats->tx_packets = PPORT_802_3_GET(pstats, a_frames_transmitted_ok);
+ 		stats->tx_bytes   = PPORT_802_3_GET(pstats, a_octets_transmitted_ok);
+ 	} else {
+ 		stats->rx_packets = sstats->rx_packets;
+ 		stats->rx_bytes   = sstats->rx_bytes;
+ 		stats->tx_packets = sstats->tx_packets;
+ 		stats->tx_bytes   = sstats->tx_bytes;
+ 		stats->tx_dropped = sstats->tx_queue_dropped;
+ 	}
  
  	stats->rx_dropped = priv->stats.qcnt.rx_out_of_buffer;
- 	stats->tx_dropped = sstats->tx_queue_dropped;
  
  	stats->rx_length_errors =
  		PPORT_802_3_GET(pstats, a_in_range_length_errors) +
@@@ -2853,31 -2925,13 +2928,13 @@@ static int mlx5e_set_features(struct ne
  	return err ? -EINVAL : 0;
  }
  
- #define MXL5_HW_MIN_MTU 64
- #define MXL5E_MIN_MTU (MXL5_HW_MIN_MTU + ETH_FCS_LEN)
- 
  static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
  {
  	struct mlx5e_priv *priv = netdev_priv(netdev);
- 	struct mlx5_core_dev *mdev = priv->mdev;
  	bool was_opened;
- 	u16 max_mtu;
- 	u16 min_mtu;
  	int err = 0;
  	bool reset;
  
- 	mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
- 
- 	max_mtu = MLX5E_HW2SW_MTU(max_mtu);
- 	min_mtu = MLX5E_HW2SW_MTU(MXL5E_MIN_MTU);
- 
- 	if (new_mtu > max_mtu || new_mtu < min_mtu) {
- 		netdev_err(netdev,
- 			   "%s: Bad MTU (%d), valid range is: [%d..%d]\n",
- 			   __func__, new_mtu, min_mtu, max_mtu);
- 		return -EINVAL;
- 	}
- 
  	mutex_lock(&priv->state_lock);
  
  	reset = !priv->params.lro_en &&
@@@ -2947,6 -3001,20 +3004,20 @@@ static int mlx5e_set_vf_trust(struct ne
  
  	return mlx5_eswitch_set_vport_trust(mdev->priv.eswitch, vf + 1, setting);
  }
+ 
+ static int mlx5e_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate,
+ 			     int max_tx_rate)
+ {
+ 	struct mlx5e_priv *priv = netdev_priv(dev);
+ 	struct mlx5_core_dev *mdev = priv->mdev;
+ 
+ 	if (min_tx_rate)
+ 		return -EOPNOTSUPP;
+ 
+ 	return mlx5_eswitch_set_vport_rate(mdev->priv.eswitch, vf + 1,
+ 					   max_tx_rate);
+ }
+ 
  static int mlx5_vport_link2ifla(u8 esw_link)
  {
  	switch (esw_link) {
@@@ -3003,8 -3071,8 +3074,8 @@@ static int mlx5e_get_vf_stats(struct ne
  					    vf_stats);
  }
  
- static void mlx5e_add_vxlan_port(struct net_device *netdev,
- 				 struct udp_tunnel_info *ti)
+ void mlx5e_add_vxlan_port(struct net_device *netdev,
+ 			  struct udp_tunnel_info *ti)
  {
  	struct mlx5e_priv *priv = netdev_priv(netdev);
  
@@@ -3017,8 -3085,8 +3088,8 @@@
  	mlx5e_vxlan_queue_work(priv, ti->sa_family, be16_to_cpu(ti->port), 1);
  }
  
- static void mlx5e_del_vxlan_port(struct net_device *netdev,
- 				 struct udp_tunnel_info *ti)
+ void mlx5e_del_vxlan_port(struct net_device *netdev,
+ 			  struct udp_tunnel_info *ti)
  {
  	struct mlx5e_priv *priv = netdev_priv(netdev);
  
@@@ -3095,7 -3163,7 +3166,7 @@@ static void mlx5e_tx_timeout(struct net
  		if (!netif_xmit_stopped(netdev_get_tx_queue(dev, i)))
  			continue;
  		sched_work = true;
 -		set_bit(MLX5E_SQ_STATE_FLUSH, &sq->state);
 +		clear_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
  		netdev_err(dev, "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x\n",
  			   i, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc);
  	}
@@@ -3126,11 -3194,21 +3197,21 @@@ static int mlx5e_xdp_set(struct net_dev
  
  	if (was_opened && reset)
  		mlx5e_close_locked(netdev);
+ 	if (was_opened && !reset) {
+ 		/* num_channels is invariant here, so we can take the
+ 		 * batched reference right upfront.
+ 		 */
+ 		prog = bpf_prog_add(prog, priv->params.num_channels);
+ 		if (IS_ERR(prog)) {
+ 			err = PTR_ERR(prog);
+ 			goto unlock;
+ 		}
+ 	}
  
- 	/* exchange programs */
+ 	/* exchange programs, extra prog reference we got from caller
+ 	 * as long as we don't fail from this point onwards.
+ 	 */
  	old_prog = xchg(&priv->xdp_prog, prog);
- 	if (prog)
- 		bpf_prog_add(prog, 1);
  	if (old_prog)
  		bpf_prog_put(old_prog);
  
@@@ -3146,17 -3224,16 +3227,16 @@@
  	/* exchanging programs w/o reset, we update ref counts on behalf
  	 * of the channels RQs here.
  	 */
- 	bpf_prog_add(prog, priv->params.num_channels);
  	for (i = 0; i < priv->params.num_channels; i++) {
  		struct mlx5e_channel *c = priv->channel[i];
  
 -		set_bit(MLX5E_RQ_STATE_FLUSH, &c->rq.state);
 +		clear_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
  		napi_synchronize(&c->napi);
  		/* prevent mlx5e_poll_rx_cq from accessing rq->xdp_prog */
  
  		old_prog = xchg(&c->rq.xdp_prog, prog);
  
 -		clear_bit(MLX5E_RQ_STATE_FLUSH, &c->rq.state);
 +		set_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
  		/* napi_schedule in case we have missed anything */
  		set_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags);
  		napi_schedule(&c->napi);
@@@ -3254,6 -3331,7 +3334,7 @@@ static const struct net_device_ops mlx5
  	.ndo_set_vf_vlan         = mlx5e_set_vf_vlan,
  	.ndo_set_vf_spoofchk     = mlx5e_set_vf_spoofchk,
  	.ndo_set_vf_trust        = mlx5e_set_vf_trust,
+ 	.ndo_set_vf_rate         = mlx5e_set_vf_rate,
  	.ndo_get_vf_config       = mlx5e_get_vf_config,
  	.ndo_set_vf_link_state   = mlx5e_set_vf_link_state,
  	.ndo_get_vf_stats        = mlx5e_get_vf_stats,
@@@ -3262,6 -3340,8 +3343,8 @@@
  #ifdef CONFIG_NET_POLL_CONTROLLER
  	.ndo_poll_controller     = mlx5e_netpoll,
  #endif
+ 	.ndo_has_offload_stats	 = mlx5e_has_offload_stats,
+ 	.ndo_get_offload_stats	 = mlx5e_get_offload_stats,
  };
  
  static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
@@@ -3298,24 -3378,6 +3381,6 @@@ u16 mlx5e_get_max_inline_cap(struct mlx
  	       2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
  }
  
- #ifdef CONFIG_MLX5_CORE_EN_DCB
- static void mlx5e_ets_init(struct mlx5e_priv *priv)
- {
- 	int i;
- 
- 	priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
- 	for (i = 0; i < priv->params.ets.ets_cap; i++) {
- 		priv->params.ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
- 		priv->params.ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
- 		priv->params.ets.prio_tc[i] = i;
- 	}
- 
- 	/* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
- 	priv->params.ets.prio_tc[0] = 1;
- 	priv->params.ets.prio_tc[1] = 0;
- }
- #endif
- 
  void mlx5e_build_default_indir_rqt(struct mlx5_core_dev *mdev,
  				   u32 *indirection_rqt, int len,
  				   int num_channels)
@@@ -3390,14 -3452,13 +3455,13 @@@ static void mlx5e_query_min_inline(stru
  				   u8 *min_inline_mode)
  {
  	switch (MLX5_CAP_ETH(mdev, wqe_inline_mode)) {
- 	case MLX5E_INLINE_MODE_L2:
+ 	case MLX5_CAP_INLINE_MODE_L2:
  		*min_inline_mode = MLX5_INLINE_MODE_L2;
  		break;
- 	case MLX5E_INLINE_MODE_VPORT_CONTEXT:
- 		mlx5_query_nic_vport_min_inline(mdev,
- 						min_inline_mode);
+ 	case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
+ 		mlx5_query_nic_vport_min_inline(mdev, 0, min_inline_mode);
  		break;
- 	case MLX5_INLINE_MODE_NOT_REQUIRED:
+ 	case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
  		*min_inline_mode = MLX5_INLINE_MODE_NONE;
  		break;
  	}
@@@ -3439,17 -3500,16 +3503,16 @@@ static void mlx5e_build_nic_netdev_priv
  	priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
  
  	/* set CQE compression */
- 	priv->params.rx_cqe_compress_admin = false;
+ 	priv->params.rx_cqe_compress_def = false;
  	if (MLX5_CAP_GEN(mdev, cqe_compression) &&
  	    MLX5_CAP_GEN(mdev, vport_group_manager)) {
  		mlx5e_get_max_linkspeed(mdev, &link_speed);
  		mlx5e_get_pci_bw(mdev, &pci_bw);
  		mlx5_core_dbg(mdev, "Max link speed = %d, PCI BW = %d\n",
  			      link_speed, pci_bw);
- 		priv->params.rx_cqe_compress_admin =
+ 		priv->params.rx_cqe_compress_def =
  			cqe_compress_heuristic(link_speed, pci_bw);
  	}
- 	priv->params.rx_cqe_compress = priv->params.rx_cqe_compress_admin;
  
  	mlx5e_set_rq_priv_params(priv);
  	if (priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
@@@ -3480,12 -3540,9 +3543,9 @@@
  		SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
  
  	/* Initialize pflags */
- 	MLX5E_SET_PRIV_FLAG(priv, MLX5E_PFLAG_RX_CQE_BASED_MODER,
- 			    priv->params.rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
- 
- #ifdef CONFIG_MLX5_CORE_EN_DCB
- 	mlx5e_ets_init(priv);
- #endif
+ 	MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_BASED_MODER,
+ 			priv->params.rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
+ 	MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS, priv->params.rx_cqe_compress_def);
  
  	mutex_init(&priv->state_lock);
  
@@@ -3523,7 -3580,8 +3583,8 @@@ static void mlx5e_build_nic_netdev(stru
  	if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
  		netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
  #ifdef CONFIG_MLX5_CORE_EN_DCB
- 		netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
+ 		if (MLX5_CAP_GEN(mdev, qos))
+ 			netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
  #endif
  	} else {
  		netdev->netdev_ops = &mlx5e_netdev_ops_basic;
@@@ -3619,43 -3677,6 +3680,6 @@@ static void mlx5e_destroy_q_counter(str
  	mlx5_core_dealloc_q_counter(priv->mdev, priv->q_counter);
  }
  
- static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv)
- {
- 	struct mlx5_core_dev *mdev = priv->mdev;
- 	u64 npages = MLX5E_REQUIRED_MTTS(priv->profile->max_nch(mdev),
- 					 BIT(MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE_MPW));
- 	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
- 	void *mkc;
- 	u32 *in;
- 	int err;
- 
- 	in = mlx5_vzalloc(inlen);
- 	if (!in)
- 		return -ENOMEM;
- 
- 	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
- 
- 	npages = min_t(u32, ALIGN(U16_MAX, 4) * 2, npages);
- 
- 	MLX5_SET(mkc, mkc, free, 1);
- 	MLX5_SET(mkc, mkc, umr_en, 1);
- 	MLX5_SET(mkc, mkc, lw, 1);
- 	MLX5_SET(mkc, mkc, lr, 1);
- 	MLX5_SET(mkc, mkc, access_mode, MLX5_MKC_ACCESS_MODE_MTT);
- 
- 	MLX5_SET(mkc, mkc, qpn, 0xffffff);
- 	MLX5_SET(mkc, mkc, pd, mdev->mlx5e_res.pdn);
- 	MLX5_SET64(mkc, mkc, len, npages << PAGE_SHIFT);
- 	MLX5_SET(mkc, mkc, translations_octword_size,
- 		 MLX5_MTT_OCTW(npages));
- 	MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT);
- 
- 	err = mlx5_core_create_mkey(mdev, &priv->umr_mkey, in, inlen);
- 
- 	kvfree(in);
- 	return err;
- }
- 
  static void mlx5e_nic_init(struct mlx5_core_dev *mdev,
  			   struct net_device *netdev,
  			   const struct mlx5e_profile *profile,
@@@ -3677,6 -3698,9 +3701,9 @@@ static void mlx5e_nic_cleanup(struct ml
  
  	if (MLX5_CAP_GEN(mdev, vport_group_manager))
  		mlx5_eswitch_unregister_vport_rep(esw, 0);
+ 
+ 	if (priv->xdp_prog)
+ 		bpf_prog_put(priv->xdp_prog);
  }
  
  static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
@@@ -3759,7 -3783,7 +3786,7 @@@ static int mlx5e_init_nic_tx(struct mlx
  	}
  
  #ifdef CONFIG_MLX5_CORE_EN_DCB
- 	mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
+ 	mlx5e_dcbnl_initialize(priv);
  #endif
  	return 0;
  }
@@@ -3787,7 -3811,7 +3814,7 @@@ static void mlx5e_nic_enable(struct mlx
  		rep.load = mlx5e_nic_rep_load;
  		rep.unload = mlx5e_nic_rep_unload;
  		rep.vport = FDB_UPLINK_VPORT;
- 		rep.priv_data = priv;
+ 		rep.netdev = netdev;
  		mlx5_eswitch_register_vport_rep(esw, 0, &rep);
  	}
  }
@@@ -3852,21 -3876,16 +3879,16 @@@ int mlx5e_attach_netdev(struct mlx5_cor
  {
  	const struct mlx5e_profile *profile;
  	struct mlx5e_priv *priv;
+ 	u16 max_mtu;
  	int err;
  
  	priv = netdev_priv(netdev);
  	profile = priv->profile;
  	clear_bit(MLX5E_STATE_DESTROYING, &priv->state);
  
- 	err = mlx5e_create_umr_mkey(priv);
- 	if (err) {
- 		mlx5_core_err(mdev, "create umr mkey failed, %d\n", err);
- 		goto out;
- 	}
- 
  	err = profile->init_tx(priv);
  	if (err)
- 		goto err_destroy_umr_mkey;
+ 		goto out;
  
  	err = mlx5e_open_drop_rq(priv);
  	if (err) {
@@@ -3882,6 -3901,11 +3904,11 @@@
  
  	mlx5e_init_l2_addr(priv);
  
+ 	/* MTU range: 68 - hw-specific max */
+ 	netdev->min_mtu = ETH_MIN_MTU;
+ 	mlx5_query_port_max_mtu(priv->mdev, &max_mtu, 1);
+ 	netdev->max_mtu = MLX5E_HW2SW_MTU(max_mtu);
+ 
  	mlx5e_set_dev_port_mtu(netdev);
  
  	if (profile->enable)
@@@ -3901,9 -3925,6 +3928,6 @@@ err_close_drop_rq
  err_cleanup_tx:
  	profile->cleanup_tx(priv);
  
- err_destroy_umr_mkey:
- 	mlx5_core_destroy_mkey(mdev, &priv->umr_mkey);
- 
  out:
  	return err;
  }
@@@ -3952,7 -3973,6 +3976,6 @@@ void mlx5e_detach_netdev(struct mlx5_co
  	profile->cleanup_rx(priv);
  	mlx5e_close_drop_rq(priv);
  	profile->cleanup_tx(priv);
- 	mlx5_core_destroy_mkey(priv->mdev, &priv->umr_mkey);
  	cancel_delayed_work_sync(&priv->update_stats_work);
  }
  
diff --combined drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 33495d8,42cd687..0e2fb3e
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@@ -164,14 -164,14 +164,14 @@@ void mlx5e_modify_rx_cqe_compression(st
  
  	mutex_lock(&priv->state_lock);
  
- 	if (priv->params.rx_cqe_compress == val)
+ 	if (MLX5E_GET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS) == val)
  		goto unlock;
  
  	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
  	if (was_opened)
  		mlx5e_close_locked(priv->netdev);
  
- 	priv->params.rx_cqe_compress = val;
+ 	MLX5E_SET_PFLAG(priv, MLX5E_PFLAG_RX_CQE_COMPRESS, val);
  
  	if (was_opened)
  		mlx5e_open_locked(priv->netdev);
@@@ -340,7 -340,7 +340,7 @@@ static inline void mlx5e_post_umr_wqe(s
  	while ((pi = (sq->pc & wq->sz_m1)) > sq->edge) {
  		sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_NOP;
  		sq->db.ico_wqe[pi].num_wqebbs = 1;
 -		mlx5e_send_nop(sq, true);
 +		mlx5e_send_nop(sq, false);
  	}
  
  	wqe = mlx5_wq_cyc_get_wqe(wq, pi);
@@@ -412,7 -412,7 +412,7 @@@ void mlx5e_post_rx_mpwqe(struct mlx5e_r
  
  	clear_bit(MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, &rq->state);
  
 -	if (unlikely(test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state))) {
 +	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state))) {
  		mlx5e_free_rx_mpwqe(rq, &rq->mpwqe.info[wq->head]);
  		return;
  	}
@@@ -445,7 -445,7 +445,7 @@@ void mlx5e_dealloc_rx_mpwqe(struct mlx5
  }
  
  #define RQ_CANNOT_POST(rq) \
 -	(test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state) || \
 +	(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state) || \
  	 test_bit(MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, &rq->state))
  
  bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq)
@@@ -737,10 -737,10 +737,10 @@@ static inlin
  struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
  			     u16 wqe_counter, u32 cqe_bcnt)
  {
- 	struct bpf_prog *xdp_prog = READ_ONCE(rq->xdp_prog);
  	struct mlx5e_dma_info *di;
  	struct sk_buff *skb;
  	void *va, *data;
+ 	bool consumed;
  
  	di             = &rq->dma_info[wqe_counter];
  	va             = page_address(di->page);
@@@ -759,7 -759,11 +759,11 @@@
  		return NULL;
  	}
  
- 	if (mlx5e_xdp_handle(rq, xdp_prog, di, data, cqe_bcnt))
+ 	rcu_read_lock();
+ 	consumed = mlx5e_xdp_handle(rq, READ_ONCE(rq->xdp_prog), di, data,
+ 				    cqe_bcnt);
+ 	rcu_read_unlock();
+ 	if (consumed)
  		return NULL; /* page/packet was consumed by XDP */
  
  	skb = build_skb(va, RQ_PAGE_SIZE(rq));
@@@ -924,7 -928,7 +928,7 @@@ int mlx5e_poll_rx_cq(struct mlx5e_cq *c
  	struct mlx5e_sq *xdp_sq = &rq->channel->xdp_sq;
  	int work_done = 0;
  
 -	if (unlikely(test_bit(MLX5E_RQ_STATE_FLUSH, &rq->state)))
 +	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
  		return 0;
  
  	if (cq->decmprs_left)
diff --combined drivers/net/ethernet/mellanox/mlx5/core/main.c
index ada24e1,2dc2869..7b4c339
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@@ -62,13 -62,13 +62,13 @@@ MODULE_DESCRIPTION("Mellanox Connect-IB
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_VERSION(DRIVER_VERSION);
  
 -int mlx5_core_debug_mask;
 -module_param_named(debug_mask, mlx5_core_debug_mask, int, 0644);
 +unsigned int mlx5_core_debug_mask;
 +module_param_named(debug_mask, mlx5_core_debug_mask, uint, 0644);
  MODULE_PARM_DESC(debug_mask, "debug mask: 1 = dump cmd data, 2 = dump cmd exec time, 3 = both. Default=0");
  
  #define MLX5_DEFAULT_PROF	2
 -static int prof_sel = MLX5_DEFAULT_PROF;
 -module_param_named(prof_sel, prof_sel, int, 0444);
 +static unsigned int prof_sel = MLX5_DEFAULT_PROF;
 +module_param_named(prof_sel, prof_sel, uint, 0444);
  MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
  
  enum {
@@@ -174,6 -174,41 +174,41 @@@ static int wait_fw_init(struct mlx5_cor
  	return err;
  }
  
+ static void mlx5_set_driver_version(struct mlx5_core_dev *dev)
+ {
+ 	int driver_ver_sz = MLX5_FLD_SZ_BYTES(set_driver_version_in,
+ 					      driver_version);
+ 	u8 in[MLX5_ST_SZ_BYTES(set_driver_version_in)] = {0};
+ 	u8 out[MLX5_ST_SZ_BYTES(set_driver_version_out)] = {0};
+ 	int remaining_size = driver_ver_sz;
+ 	char *string;
+ 
+ 	if (!MLX5_CAP_GEN(dev, driver_version))
+ 		return;
+ 
+ 	string = MLX5_ADDR_OF(set_driver_version_in, in, driver_version);
+ 
+ 	strncpy(string, "Linux", remaining_size);
+ 
+ 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+ 	strncat(string, ",", remaining_size);
+ 
+ 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+ 	strncat(string, DRIVER_NAME, remaining_size);
+ 
+ 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+ 	strncat(string, ",", remaining_size);
+ 
+ 	remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
+ 	strncat(string, DRIVER_VERSION, remaining_size);
+ 
+ 	/*Send the command*/
+ 	MLX5_SET(set_driver_version_in, in, opcode,
+ 		 MLX5_CMD_OP_SET_DRIVER_VERSION);
+ 
+ 	mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ }
+ 
  static int set_dma_caps(struct pci_dev *pdev)
  {
  	int err;
@@@ -732,15 -767,13 +767,15 @@@ static int mlx5_core_set_issi(struct ml
  		u8 status;
  
  		mlx5_cmd_mbox_status(query_out, &status, &syndrome);
 -		if (status == MLX5_CMD_STAT_BAD_OP_ERR) {
 -			pr_debug("Only ISSI 0 is supported\n");
 -			return 0;
 +		if (!status || syndrome == MLX5_DRIVER_SYND) {
 +			mlx5_core_err(dev, "Failed to query ISSI err(%d) status(%d) synd(%d)\n",
 +				      err, status, syndrome);
 +			return err;
  		}
  
 -		pr_err("failed to query ISSI err(%d)\n", err);
 -		return err;
 +		mlx5_core_warn(dev, "Query ISSI is not supported by FW, ISSI is 0\n");
 +		dev->issi = 0;
 +		return 0;
  	}
  
  	sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0);
@@@ -754,8 -787,7 +789,8 @@@
  		err = mlx5_cmd_exec(dev, set_in, sizeof(set_in),
  				    set_out, sizeof(set_out));
  		if (err) {
 -			pr_err("failed to set ISSI=1 err(%d)\n", err);
 +			mlx5_core_err(dev, "Failed to set ISSI to 1 err(%d)\n",
 +				      err);
  			return err;
  		}
  
@@@ -1017,6 -1049,8 +1052,8 @@@ static int mlx5_load_one(struct mlx5_co
  		goto err_pagealloc_stop;
  	}
  
+ 	mlx5_set_driver_version(dev);
+ 
  	mlx5_start_health_poll(dev);
  
  	err = mlx5_query_hca_caps(dev);
@@@ -1204,6 -1238,8 +1241,8 @@@ static const struct devlink_ops mlx5_de
  #ifdef CONFIG_MLX5_CORE_EN
  	.eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
  	.eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
+ 	.eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
+ 	.eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
  #endif
  };
  
@@@ -1230,6 -1266,13 +1269,6 @@@ static int init_one(struct pci_dev *pde
  
  	dev->pdev = pdev;
  	dev->event = mlx5_core_event;
 -
 -	if (prof_sel < 0 || prof_sel >= ARRAY_SIZE(profile)) {
 -		mlx5_core_warn(dev,
 -			       "selected profile out of range, selecting default (%d)\n",
 -			       MLX5_DEFAULT_PROF);
 -		prof_sel = MLX5_DEFAULT_PROF;
 -	}
  	dev->profile = &profile[prof_sel];
  
  	INIT_LIST_HEAD(&priv->ctx_list);
@@@ -1419,6 -1462,7 +1458,7 @@@ static const struct pci_device_id mlx5_
  	{ PCI_VDEVICE(MELLANOX, 0x1017) },			/* ConnectX-5, PCIe 3.0 */
  	{ PCI_VDEVICE(MELLANOX, 0x1018), MLX5_PCI_DEV_IS_VF},	/* ConnectX-5 VF */
  	{ PCI_VDEVICE(MELLANOX, 0x1019) },			/* ConnectX-5, PCIe 4.0 */
+ 	{ PCI_VDEVICE(MELLANOX, 0x101a), MLX5_PCI_DEV_IS_VF},	/* ConnectX-5, PCIe 4.0 VF */
  	{ 0, }
  };
  
@@@ -1446,22 -1490,10 +1486,22 @@@ static struct pci_driver mlx5_core_driv
  	.sriov_configure   = mlx5_core_sriov_configure,
  };
  
 +static void mlx5_core_verify_params(void)
 +{
 +	if (prof_sel >= ARRAY_SIZE(profile)) {
 +		pr_warn("mlx5_core: WARNING: Invalid module parameter prof_sel %d, valid range 0-%zu, changing back to default(%d)\n",
 +			prof_sel,
 +			ARRAY_SIZE(profile) - 1,
 +			MLX5_DEFAULT_PROF);
 +		prof_sel = MLX5_DEFAULT_PROF;
 +	}
 +}
 +
  static int __init init(void)
  {
  	int err;
  
 +	mlx5_core_verify_params();
  	mlx5_register_debugfs();
  
  	err = pci_register_driver(&mlx5_core_driver);
diff --combined drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 63b9a0d,7e635eb..e0a8fbd
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@@ -44,11 -44,11 +44,11 @@@
  
  #define MLX5_TOTAL_VPORTS(mdev) (1 + pci_sriov_get_totalvfs(mdev->pdev))
  
 -extern int mlx5_core_debug_mask;
 +extern uint mlx5_core_debug_mask;
  
  #define mlx5_core_dbg(__dev, format, ...)				\
 -	dev_dbg(&(__dev)->pdev->dev, "%s:%s:%d:(pid %d): " format,	\
 -		 (__dev)->priv.name, __func__, __LINE__, current->pid,	\
 +	dev_dbg(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
 +		 __func__, __LINE__, current->pid,			\
  		 ##__VA_ARGS__)
  
  #define mlx5_core_dbg_mask(__dev, mask, format, ...)			\
@@@ -63,8 -63,8 +63,8 @@@ do {									
  	       ##__VA_ARGS__)
  
  #define mlx5_core_warn(__dev, format, ...)				\
 -	dev_warn(&(__dev)->pdev->dev, "%s:%s:%d:(pid %d): " format,	\
 -		(__dev)->priv.name, __func__, __LINE__, current->pid,	\
 +	dev_warn(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,	\
 +		 __func__, __LINE__, current->pid,			\
  		##__VA_ARGS__)
  
  #define mlx5_core_info(__dev, format, ...)				\
@@@ -75,17 -75,13 +75,18 @@@ enum 
  	MLX5_CMD_TIME, /* print command execution time */
  };
  
 +enum {
 +	MLX5_DRIVER_STATUS_ABORTED = 0xfe,
 +	MLX5_DRIVER_SYND = 0xbadd00de,
 +};
 +
  int mlx5_query_hca_caps(struct mlx5_core_dev *dev);
  int mlx5_query_board_id(struct mlx5_core_dev *dev);
  int mlx5_cmd_init_hca(struct mlx5_core_dev *dev);
  int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev);
  void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
  		     unsigned long param);
+ void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe);
  void mlx5_enter_error_state(struct mlx5_core_dev *dev);
  void mlx5_disable_device(struct mlx5_core_dev *dev);
  void mlx5_recover_device(struct mlx5_core_dev *dev);
@@@ -97,6 -93,13 +98,13 @@@ int mlx5_core_sriov_configure(struct pc
  bool mlx5_sriov_is_enabled(struct mlx5_core_dev *dev);
  int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
  int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
+ int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
+ 				       void *context, u32 *element_id);
+ int mlx5_modify_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
+ 				       void *context, u32 element_id,
+ 				       u32 modify_bitmask);
+ int mlx5_destroy_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
+ 					u32 element_id);
  int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev);
  cycle_t mlx5_read_internal_timer(struct mlx5_core_dev *dev);
  u32 mlx5_get_msix_vec(struct mlx5_core_dev *dev, int vecidx);
@@@ -119,6 -122,12 +127,12 @@@ struct mlx5_core_dev *mlx5_get_next_phy
  void mlx5_dev_list_lock(void);
  void mlx5_dev_list_unlock(void);
  int mlx5_dev_list_trylock(void);
+ int mlx5_encap_alloc(struct mlx5_core_dev *dev,
+ 		     int header_type,
+ 		     size_t size,
+ 		     void *encap_header,
+ 		     u32 *encap_id);
+ void mlx5_encap_dealloc(struct mlx5_core_dev *dev, u32 encap_id);
  
  bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv);
  
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/ethernet/stmicro/stmmac/dwmac4_dma.c
index 32bc2fc,577316d..e81b6e5
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@@ -30,11 -30,9 +30,11 @@@ static void dwmac4_dma_axi(void __iome
  	if (axi->axi_xit_frm)
  		value |= DMA_AXI_LPI_XIT_FRM;
  
 +	value &= ~DMA_AXI_WR_OSR_LMT;
  	value |= (axi->axi_wr_osr_lmt & DMA_AXI_OSR_MAX) <<
  		 DMA_AXI_WR_OSR_LMT_SHIFT;
  
 +	value &= ~DMA_AXI_RD_OSR_LMT;
  	value |= (axi->axi_rd_osr_lmt & DMA_AXI_OSR_MAX) <<
  		 DMA_AXI_RD_OSR_LMT_SHIFT;
  
@@@ -215,7 -213,17 +215,17 @@@ static void dwmac4_dma_chan_op_mode(voi
  		else
  			mtl_tx_op |= MTL_OP_MODE_TTC_512;
  	}
- 
+ 	/* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
+ 	 * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
+ 	 * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
+ 	 * with reset values: TXQEN off, TQS 256 bytes.
+ 	 *
+ 	 * Write the bits in both cases, since it will have no effect when RO.
+ 	 * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
+ 	 * be RO, however, writing the whole TQS field will result in a value
+ 	 * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
+ 	 */
+ 	mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
  	writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
  
  	mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
diff --combined drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index ac3d39c,98bf86d..e528e71
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@@ -126,10 -126,8 +126,10 @@@ static struct stmmac_axi *stmmac_axi_se
  	axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
  	axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
  
 -	of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt);
 -	of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt);
 +	if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
 +		axi->axi_wr_osr_lmt = 1;
 +	if (of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt))
 +		axi->axi_rd_osr_lmt = 1;
  	of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
  	of_node_put(np);
  
@@@ -444,9 -442,7 +444,7 @@@ static int stmmac_pltfr_suspend(struct 
  	struct platform_device *pdev = to_platform_device(dev);
  
  	ret = stmmac_suspend(dev);
- 	if (priv->plat->suspend)
- 		priv->plat->suspend(pdev, priv->plat->bsp_priv);
- 	else if (priv->plat->exit)
+ 	if (priv->plat->exit)
  		priv->plat->exit(pdev, priv->plat->bsp_priv);
  
  	return ret;
@@@ -465,9 -461,7 +463,7 @@@ static int stmmac_pltfr_resume(struct d
  	struct stmmac_priv *priv = netdev_priv(ndev);
  	struct platform_device *pdev = to_platform_device(dev);
  
- 	if (priv->plat->resume)
- 		priv->plat->resume(pdev, priv->plat->bsp_priv);
- 	else if (priv->plat->init)
+ 	if (priv->plat->init)
  		priv->plat->init(pdev, priv->plat->bsp_priv);
  
  	return stmmac_resume(dev);
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/net/virtio_net.c
index cbf1c61,a21d93a..b425fa1
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@@ -969,17 -969,12 +969,17 @@@ static int virtnet_set_mac_address(stru
  	struct virtnet_info *vi = netdev_priv(dev);
  	struct virtio_device *vdev = vi->vdev;
  	int ret;
 -	struct sockaddr *addr = p;
 +	struct sockaddr *addr;
  	struct scatterlist sg;
  
 -	ret = eth_prepare_mac_addr_change(dev, p);
 +	addr = kmalloc(sizeof(*addr), GFP_KERNEL);
 +	if (!addr)
 +		return -ENOMEM;
 +	memcpy(addr, p, sizeof(*addr));
 +
 +	ret = eth_prepare_mac_addr_change(dev, addr);
  	if (ret)
 -		return ret;
 +		goto out;
  
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
  		sg_init_one(&sg, addr->sa_data, dev->addr_len);
@@@ -987,8 -982,7 +987,8 @@@
  					  VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
  			dev_warn(&vdev->dev,
  				 "Failed to set mac address by vq command.\n");
 -			return -EINVAL;
 +			ret = -EINVAL;
 +			goto out;
  		}
  	} else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
  		   !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
@@@ -1002,11 -996,8 +1002,11 @@@
  	}
  
  	eth_commit_mac_addr_change(dev, p);
 +	ret = 0;
  
 -	return 0;
 +out:
 +	kfree(addr);
 +	return ret;
  }
  
  static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
@@@ -1428,17 -1419,6 +1428,6 @@@ static const struct ethtool_ops virtnet
  	.set_settings = virtnet_set_settings,
  };
  
- #define MIN_MTU 68
- #define MAX_MTU 65535
- 
- static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
- {
- 	if (new_mtu < MIN_MTU || new_mtu > MAX_MTU)
- 		return -EINVAL;
- 	dev->mtu = new_mtu;
- 	return 0;
- }
- 
  static const struct net_device_ops virtnet_netdev = {
  	.ndo_open            = virtnet_open,
  	.ndo_stop   	     = virtnet_close,
@@@ -1446,7 -1426,6 +1435,6 @@@
  	.ndo_validate_addr   = eth_validate_addr,
  	.ndo_set_mac_address = virtnet_set_mac_address,
  	.ndo_set_rx_mode     = virtnet_set_rx_mode,
- 	.ndo_change_mtu	     = virtnet_change_mtu,
  	.ndo_get_stats64     = virtnet_stats,
  	.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
  	.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
@@@ -1762,6 -1741,9 +1750,9 @@@ static bool virtnet_validate_features(s
  	return true;
  }
  
+ #define MIN_MTU ETH_MIN_MTU
+ #define MAX_MTU ETH_MAX_MTU
+ 
  static int virtnet_probe(struct virtio_device *vdev)
  {
  	int i, err;
@@@ -1835,6 -1817,10 +1826,10 @@@
  
  	dev->vlan_features = dev->features;
  
+ 	/* MTU range: 68 - 65535 */
+ 	dev->min_mtu = MIN_MTU;
+ 	dev->max_mtu = MAX_MTU;
+ 
  	/* Configuration may specify what MAC to use.  Otherwise random. */
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
  		virtio_cread_bytes(vdev,
@@@ -1889,15 -1875,22 +1884,22 @@@
  		mtu = virtio_cread16(vdev,
  				     offsetof(struct virtio_net_config,
  					      mtu));
- 		if (virtnet_change_mtu(dev, mtu))
+ 		if (mtu < dev->min_mtu) {
  			__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
+ 		} else {
+ 			dev->mtu = mtu;
+ 			dev->max_mtu = mtu;
+ 		}
  	}
  
  	if (vi->any_header_sg)
  		dev->needed_headroom = vi->hdr_len;
  
- 	/* Use single tx/rx queue pair as default */
- 	vi->curr_queue_pairs = 1;
+ 	/* Enable multiqueue by default */
+ 	if (num_online_cpus() >= max_queue_pairs)
+ 		vi->curr_queue_pairs = max_queue_pairs;
+ 	else
+ 		vi->curr_queue_pairs = num_online_cpus();
  	vi->max_queue_pairs = max_queue_pairs;
  
  	/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
@@@ -1928,6 -1921,8 +1930,8 @@@
  		goto free_unregister_netdev;
  	}
  
+ 	virtnet_set_affinity(vi);
+ 
  	/* Assume link up if device can't report link status,
  	   otherwise get link status from config. */
  	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
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/ipv4/tcp_input.c
index c71d49c,fe668c1..6c79075
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@@ -85,6 -85,7 +85,7 @@@ int sysctl_tcp_dsack __read_mostly = 1
  int sysctl_tcp_app_win __read_mostly = 31;
  int sysctl_tcp_adv_win_scale __read_mostly = 1;
  EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
+ EXPORT_SYMBOL(sysctl_tcp_timestamps);
  
  /* rfc5961 challenge ack rate limiting */
  int sysctl_tcp_challenge_ack_limit = 1000;
@@@ -128,23 -129,6 +129,23 @@@ int sysctl_tcp_invalid_ratelimit __read
  #define REXMIT_LOST	1 /* retransmit packets marked lost */
  #define REXMIT_NEW	2 /* FRTO-style transmit of unsent/new packets */
  
 +static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb)
 +{
 +	static bool __once __read_mostly;
 +
 +	if (!__once) {
 +		struct net_device *dev;
 +
 +		__once = true;
 +
 +		rcu_read_lock();
 +		dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
 +		pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n",
 +			dev ? dev->name : "Unknown driver");
 +		rcu_read_unlock();
 +	}
 +}
 +
  /* Adapt the MSS value used to make delayed ack decision to the
   * real world.
   */
@@@ -161,10 -145,7 +162,10 @@@ static void tcp_measure_rcv_mss(struct 
  	 */
  	len = skb_shinfo(skb)->gso_size ? : skb->len;
  	if (len >= icsk->icsk_ack.rcv_mss) {
 -		icsk->icsk_ack.rcv_mss = len;
 +		icsk->icsk_ack.rcv_mss = min_t(unsigned int, len,
 +					       tcp_sk(sk)->advmss);
 +		if (unlikely(icsk->icsk_ack.rcv_mss != len))
 +			tcp_gro_dev_warn(sk, skb);
  	} else {
  		/* Otherwise, we make more careful check taking into account,
  		 * that SACKs block is variable.
@@@ -2414,10 -2395,7 +2415,7 @@@ static void tcp_undo_cwnd_reduction(str
  	if (tp->prior_ssthresh) {
  		const struct inet_connection_sock *icsk = inet_csk(sk);
  
- 		if (icsk->icsk_ca_ops->undo_cwnd)
- 			tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk);
- 		else
- 			tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh << 1);
+ 		tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk);
  
  		if (tp->prior_ssthresh > tp->snd_ssthresh) {
  			tp->snd_ssthresh = tp->prior_ssthresh;
@@@ -3201,6 -3179,9 +3199,9 @@@ static int tcp_clean_rtx_queue(struct s
  			tp->lost_skb_hint = NULL;
  	}
  
+ 	if (!skb)
+ 		tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
+ 
  	if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))
  		tp->snd_up = tp->snd_una;
  
@@@ -3371,9 -3352,7 +3372,7 @@@ static void tcp_snd_una_update(struct t
  	u32 delta = ack - tp->snd_una;
  
  	sock_owned_by_me((struct sock *)tp);
- 	u64_stats_update_begin_raw(&tp->syncp);
  	tp->bytes_acked += delta;
- 	u64_stats_update_end_raw(&tp->syncp);
  	tp->snd_una = ack;
  }
  
@@@ -3383,9 -3362,7 +3382,7 @@@ static void tcp_rcv_nxt_update(struct t
  	u32 delta = seq - tp->rcv_nxt;
  
  	sock_owned_by_me((struct sock *)tp);
- 	u64_stats_update_begin_raw(&tp->syncp);
  	tp->bytes_received += delta;
- 	u64_stats_update_end_raw(&tp->syncp);
  	tp->rcv_nxt = seq;
  }
  
@@@ -5083,8 -5060,11 +5080,11 @@@ static void tcp_check_space(struct soc
  		/* pairs with tcp_poll() */
  		smp_mb__after_atomic();
  		if (sk->sk_socket &&
- 		    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
+ 		    test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
  			tcp_new_space(sk);
+ 			if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
+ 				tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
+ 		}
  	}
  }
  
@@@ -6318,13 -6298,7 +6318,7 @@@ int tcp_conn_request(struct request_soc
  			goto drop;
  	}
  
- 
- 	/* Accept backlog is full. If we have already queued enough
- 	 * of warm entries in syn queue, drop request. It is better than
- 	 * clogging syn queue with openreqs with exponentially increasing
- 	 * timeout.
- 	 */
- 	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
+ 	if (sk_acceptq_is_full(sk)) {
  		NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
  		goto drop;
  	}
@@@ -6334,6 -6308,7 +6328,7 @@@
  		goto drop;
  
  	tcp_rsk(req)->af_specific = af_ops;
+ 	tcp_rsk(req)->ts_off = 0;
  
  	tcp_clear_options(&tmp_opt);
  	tmp_opt.mss_clamp = af_ops->mss_clamp;
@@@ -6355,6 -6330,9 +6350,9 @@@
  	if (security_inet_conn_request(sk, skb, req))
  		goto drop_and_free;
  
+ 	if (isn && tmp_opt.tstamp_ok)
+ 		af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
+ 
  	if (!want_cookie && !isn) {
  		/* VJ's idea. We save last timestamp seen
  		 * from the destination in peer table, when entering
@@@ -6395,7 -6373,7 +6393,7 @@@
  			goto drop_and_release;
  		}
  
- 		isn = af_ops->init_seq(skb);
+ 		isn = af_ops->init_seq(skb, &tcp_rsk(req)->ts_off);
  	}
  	if (!dst) {
  		dst = af_ops->route_req(sk, &fl, req, NULL);
@@@ -6407,6 -6385,7 +6405,7 @@@
  
  	if (want_cookie) {
  		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
+ 		tcp_rsk(req)->ts_off = 0;
  		req->cookie_ts = tmp_opt.tstamp_ok;
  		if (!tmp_opt.tstamp_ok)
  			inet_rsk(req)->ecn_ok = 0;
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