The following commit has been merged in the master branch: commit 6caaac2455ba284a68127841ebf074eff154fc57 Merge: b52b7db550949fd55d3aa5f83b6e7c28381fdf0d bd3606c29fccd0fe3d1061a61811cabf1abf7110 Author: Stephen Rothwell sfr@canb.auug.org.au Date: Wed Feb 13 11:29:56 2019 +1100
Merge remote-tracking branch 'net-next/master'
diff --combined Documentation/admin-guide/kernel-parameters.txt index 4947ee621071,7afb2fedde0a..ea3f74abefb0 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@@ -461,6 -461,11 +461,11 @@@ possible to determine what the correct size should be. This option provides an override for these situations.
+ carrier_timeout= + [NET] Specifies amount of time (in seconds) that + the kernel should wait for a network carrier. By default + it waits 120 seconds. + ca_keys= [KEYS] This parameter identifies a specific key(s) on the system trusted keyring to be used for certificate trust validation. @@@ -1182,10 -1187,9 +1187,10 @@@ arch/x86/kernel/cpu/cpufreq/elanfreq.c.
elevator= [IOSCHED] - Format: {"cfq" | "deadline" | "noop"} - See Documentation/block/cfq-iosched.txt and - Documentation/block/deadline-iosched.txt for details. + Format: { "mq-deadline" | "kyber" | "bfq" } + See Documentation/block/deadline-iosched.txt, + Documentation/block/kyber-iosched.txt and + Documentation/block/bfq-iosched.txt for details.
elfcorehdr=[size[KMG]@]offset[KMG] [IA64,PPC,SH,X86,S390] Specifies physical address of start of kernel core @@@ -1697,11 -1701,12 +1702,11 @@@ By default, super page will be supported if Intel IOMMU has the capability. With this option, super page will not be supported. - sm_off [Default Off] - By default, scalable mode will be supported if the + sm_on [Default Off] + By default, scalable mode will be disabled even if the hardware advertises that it has support for the scalable mode translation. With this option set, scalable mode - will not be used even on hardware which claims to support - it. + will be used on hardware which claims to support it. tboot_noforce [Default Off] Do not force the Intel IOMMU enabled under tboot. By default, tboot will force Intel IOMMU on, which @@@ -1831,11 -1836,6 +1836,11 @@@ to let secondary kernels in charge of setting up LPIs.
+ irqchip.gicv3_pseudo_nmi= [ARM64] + Enables support for pseudo-NMIs in the kernel. This + requires the kernel to be built with + CONFIG_ARM64_PSEUDO_NMI. + irqfixup [HW] When an interrupt is not handled search all handlers for it. Intended to get systems with badly broken @@@ -1987,12 -1987,6 +1992,12 @@@ Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y, the default is off.
+ kpti= [ARM64] Control page table isolation of user + and kernel address spaces. + Default: enabled on cores which need mitigation. + 0: force disabled + 1: force enabled + kvm.ignore_msrs=[KVM] Ignore guest accesses to unhandled MSRs. Default is 0 (don't ignore, but inject #GP)
diff --combined Documentation/networking/index.rst index d6f9537afb27,9a32451cd201..4ef24c6a638a --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@@ -24,17 -24,16 +24,19 @@@ Contents device_drivers/intel/i40e device_drivers/intel/iavf device_drivers/intel/ice + devlink-info-versions kapi z8530book msg_zerocopy failover net_failover + phy alias bridge snmp_counter + checksum-offloads + segmentation-offloads + scaling
.. only:: subproject
diff --combined MAINTAINERS index e0506e37b793,d7da0618d6b3..979d15824776 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -331,7 -331,6 +331,7 @@@ ACPI APE M: "Rafael J. Wysocki" rjw@rjwysocki.net M: Len Brown lenb@kernel.org L: linux-acpi@vger.kernel.org +R: James Morse james.morse@arm.com R: Tony Luck tony.luck@intel.com R: Borislav Petkov bp@alien8.de F: drivers/acpi/apei/ @@@ -366,7 -365,6 +366,7 @@@ M: Lorenzo Pieralisi <lorenzo.pieralisi M: Hanjun Guo hanjun.guo@linaro.org M: Sudeep Holla sudeep.holla@arm.com L: linux-acpi@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/acpi/arm64
@@@ -411,9 -409,10 +411,9 @@@ F: drivers/platform/x86/wmi. F: include/uapi/linux/wmi.h
AD1889 ALSA SOUND DRIVER -M: Thibaut Varene T-Bone@parisc-linux.org -W: http://wiki.parisc-linux.org/AD1889 +W: https://parisc.wiki.kernel.org/index.php/AD1889 L: linux-parisc@vger.kernel.org -S: Maintained +S: Orphan F: sound/pci/ad1889.*
AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER @@@ -1160,7 -1159,7 +1160,7 @@@ F: arch/arm*/include/asm/hw_breakpoint. F: arch/arm*/include/asm/perf_event.h F: drivers/perf/* F: include/linux/perf/arm_pmu.h -F: Documentation/devicetree/bindings/arm/pmu.txt +F: Documentation/devicetree/bindings/arm/pmu.yaml F: Documentation/devicetree/bindings/perf/
ARM PORT @@@ -1532,14 -1531,21 +1532,14 @@@ ARM/FREESCALE IMX / MXC ARM ARCHITECTUR M: Shawn Guo shawnguo@kernel.org M: Sascha Hauer s.hauer@pengutronix.de R: Pengutronix Kernel Team kernel@pengutronix.de -R: Fabio Estevam fabio.estevam@nxp.com +R: Fabio Estevam festevam@gmail.com R: NXP Linux Team linux-imx@nxp.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git -F: arch/arm/mach-imx/ -F: arch/arm/mach-mxs/ -F: arch/arm/boot/dts/imx* -F: arch/arm/configs/imx*_defconfig -F: arch/arm64/boot/dts/freescale/imx* -F: drivers/clk/imx/ -F: drivers/firmware/imx/ -F: drivers/soc/imx/ -F: include/linux/firmware/imx/ -F: include/soc/imx/ +N: imx +N: mxs +X: drivers/media/i2c/
ARM/FREESCALE VYBRID ARM ARCHITECTURE M: Shawn Guo shawnguo@kernel.org @@@ -1731,7 -1737,6 +1731,7 @@@ F: arch/arm/configs/mvebu_*_defconfi F: arch/arm/mach-mvebu/ F: arch/arm64/boot/dts/marvell/armada* F: drivers/cpufreq/armada-37xx-cpufreq.c +F: drivers/cpufreq/armada-8k-cpufreq.c F: drivers/cpufreq/mvebu-cpufreq.c F: drivers/irqchip/irq-armada-370-xp.c F: drivers/irqchip/irq-mvebu-* @@@ -1943,37 -1948,19 +1943,37 @@@ M: David Brown <david.brown@linaro.org L: linux-arm-msm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/soc/qcom/ +F: Documentation/devicetree/bindings/*/qcom* F: arch/arm/boot/dts/qcom-*.dts F: arch/arm/boot/dts/qcom-*.dtsi F: arch/arm/mach-qcom/ -F: arch/arm64/boot/dts/qcom/* +F: arch/arm64/boot/dts/qcom/ +F: drivers/*/qcom/ +F: drivers/*/qcom* +F: drivers/*/*/qcom/ +F: drivers/*/*/qcom* +F: drivers/*/pm8???-* +F: drivers/bluetooth/btqcomsmd.c +F: drivers/clocksource/timer-qcom.c +F: drivers/extcon/extcon-qcom* +F: drivers/iommu/msm* F: drivers/i2c/busses/i2c-qup.c -F: drivers/clk/qcom/ -F: drivers/dma/qcom/ -F: drivers/soc/qcom/ +F: drivers/i2c/busses/i2c-qcom-geni.c +F: drivers/mfd/ssbi.c +F: drivers/mmc/host/mmci_qcom* +F: drivers/mmc/host/sdhci_msm.c +F: drivers/pci/controller/dwc/pcie-qcom.c +F: drivers/phy/qualcomm/ +F: drivers/power/*/msm* +F: drivers/reset/reset-qcom-* +F: drivers/scsi/ufs/ufs-qcom.* F: drivers/spi/spi-qup.c +F: drivers/spi/spi-geni-qcom.c +F: drivers/spi/spi-qcom-qspi.c F: drivers/tty/serial/msm_serial.c -F: drivers/*/pm8???-* -F: drivers/mfd/ssbi.c -F: drivers/firmware/qcom_scm* +F: drivers/usb/dwc3/dwc3-qcom.c +F: include/dt-bindings/*/qcom* +F: include/linux/*/qcom* T: git git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git
ARM/RADISYS ENP2611 MACHINE SUPPORT @@@ -2010,7 -1997,7 +2010,7 @@@ Q: http://patchwork.kernel.org/project/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next S: Supported F: arch/arm64/boot/dts/renesas/ -F: Documentation/devicetree/bindings/arm/shmobile.txt +F: Documentation/devicetree/bindings/arm/renesas.yaml F: drivers/soc/renesas/ F: include/linux/soc/renesas/
@@@ -2097,9 -2084,8 +2097,9 @@@ F: drivers/media/platform/s5p-cec F: Documentation/devicetree/bindings/media/s5p-cec.txt
ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT -M: Andrzej Pietrasiewicz andrzej.p@samsung.com +M: Andrzej Pietrasiewicz andrzejtp2010@gmail.com M: Jacek Anaszewski jacek.anaszewski@gmail.com +M: Sylwester Nawrocki s.nawrocki@samsung.com L: linux-arm-kernel@lists.infradead.org L: linux-media@vger.kernel.org S: Maintained @@@ -2123,8 -2109,6 +2123,8 @@@ Q: http://patchwork.kernel.org/project/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next S: Supported F: arch/arm/boot/dts/emev2* +F: arch/arm/boot/dts/gr-peach* +F: arch/arm/boot/dts/iwg20d-q7* F: arch/arm/boot/dts/r7s* F: arch/arm/boot/dts/r8a* F: arch/arm/boot/dts/r9a* @@@ -2132,7 -2116,7 +2132,7 @@@ F: arch/arm/boot/dts/sh F: arch/arm/configs/shmobile_defconfig F: arch/arm/include/debug/renesas-scif.S F: arch/arm/mach-shmobile/ -F: Documentation/devicetree/bindings/arm/shmobile.txt +F: Documentation/devicetree/bindings/arm/renesas.yaml F: drivers/soc/renesas/ F: include/linux/soc/renesas/
@@@ -2928,6 -2912,12 +2928,12 @@@ L: netdev@vger.kernel.or S: Maintained F: arch/powerpc/net/
+ BPF JIT for RISC-V (RV64G) + M: Björn Töpel bjorn.topel@gmail.com + L: netdev@vger.kernel.org + S: Maintained + F: arch/riscv/net/ + BPF JIT for S390 M: Martin Schwidefsky schwidefsky@de.ibm.com M: Heiko Carstens heiko.carstens@de.ibm.com @@@ -3977,7 -3967,7 +3983,7 @@@ M: Viresh Kumar <viresh.kumar@linaro.or L: linux-pm@vger.kernel.org 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) +T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git (For ARM Updates) B: https://bugzilla.kernel.org F: Documentation/admin-guide/pm/cpufreq.rst F: Documentation/admin-guide/pm/intel_pstate.rst @@@ -4037,7 -4027,6 +4043,7 @@@ S: Maintaine T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git B: https://bugzilla.kernel.org F: Documentation/admin-guide/pm/cpuidle.rst +F: Documentation/driver-api/pm/cpuidle.rst F: drivers/cpuidle/* F: include/linux/cpuidle.h
@@@ -4145,7 -4134,7 +4151,7 @@@ S: Maintaine F: drivers/media/dvb-frontends/cxd2820r*
CXGB3 ETHERNET DRIVER (CXGB3) - M: Arjun Vynipadath arjun@chelsio.com + M: Vishal Kulkarni vishal@chelsio.com L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported @@@ -4174,7 -4163,7 +4180,7 @@@ S: Supporte F: drivers/crypto/chelsio
CXGB4 ETHERNET DRIVER (CXGB4) - M: Arjun Vynipadath arjun@chelsio.com + M: Vishal Kulkarni vishal@chelsio.com L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported @@@ -5203,7 -5192,7 +5209,7 @@@ DRM DRIVERS FOR XE M: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com T: git git://anongit.freedesktop.org/drm/drm-misc L: dri-devel@lists.freedesktop.org -L: xen-devel@lists.xen.org +L: xen-devel@lists.xenproject.org (moderated for non-subscribers) S: Supported F: drivers/gpu/drm/xen/ F: Documentation/gpu/xen-front.rst @@@ -5904,7 -5893,6 +5910,7 @@@ L: linux-fsdevel@vger.kernel.or S: Maintained F: fs/* F: include/linux/fs.h +F: include/linux/fs_types.h F: include/uapi/linux/fs.h
FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER @@@ -6047,6 -6035,12 +6053,12 @@@ L: linuxppc-dev@lists.ozlabs.or S: Maintained F: drivers/dma/fsldma.*
+ FREESCALE ENETC ETHERNET DRIVERS + M: Claudiu Manoil claudiu.manoil@nxp.com + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/freescale/enetc/ + FREESCALE eTSEC ETHERNET DRIVER (GIANFAR) M: Claudiu Manoil claudiu.manoil@nxp.com L: netdev@vger.kernel.org @@@ -6110,7 -6104,9 +6122,9 @@@ FREESCALE QORIQ PTP CLOCK DRIVE M: Yangbo Lu yangbo.lu@nxp.com L: netdev@vger.kernel.org S: Maintained + F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c F: drivers/ptp/ptp_qoriq.c + F: drivers/ptp/ptp_qoriq_debugfs.c F: include/linux/fsl/ptp_qoriq.h F: Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
@@@ -6169,7 -6165,7 +6183,7 @@@ FREESCALE SOC SOUND DRIVER M: Timur Tabi timur@kernel.org M: Nicolin Chen nicoleotsuka@gmail.com M: Xiubo Li Xiubo.Lee@gmail.com -R: Fabio Estevam fabio.estevam@nxp.com +R: Fabio Estevam festevam@gmail.com L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: linuxppc-dev@lists.ozlabs.org S: Maintained @@@ -7721,6 -7717,7 +7735,6 @@@ M: Yong Zhi <yong.zhi@intel.com M: Sakari Ailus sakari.ailus@linux.intel.com M: Bingbu Cao bingbu.cao@intel.com R: Tian Shu Qiu tian.shu.qiu@intel.com -R: Jian Xu Zheng jian.xu.zheng@intel.com L: linux-media@vger.kernel.org S: Maintained F: drivers/media/pci/intel/ipu3/ @@@ -10599,6 -10596,7 +10613,7 @@@ F: Documentation/devicetree/bindings/ne F: net/dsa/ F: include/net/dsa.h F: include/linux/dsa/ + F: include/linux/platform_data/dsa.h F: drivers/net/dsa/
NETWORKING [GENERAL] @@@ -10915,7 -10913,7 +10930,7 @@@ F: include/linux/nvmem-consumer. F: include/linux/nvmem-provider.h
NXP SGTL5000 DRIVER -M: Fabio Estevam fabio.estevam@nxp.com +M: Fabio Estevam festevam@gmail.com L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/sgtl5000.txt @@@ -11254,19 -11252,6 +11269,19 @@@ S: Maintaine F: drivers/media/i2c/ov7740.c F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
+OMNIVISION OV9640 SENSOR DRIVER +M: Petr Cvek petrcvekcz@gmail.com +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/ov9640.* + +OMNIVISION OV8856 SENSOR DRIVER +M: Ben Kao ben.kao@intel.com +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/ov8856.c + OMNIVISION OV9650 SENSOR DRIVER M: Sakari Ailus sakari.ailus@linux.intel.com R: Akinobu Mita akinobu.mita@gmail.com @@@ -11342,12 -11327,10 +11357,12 @@@ F: include/dt-bindings
OPENCORES I2C BUS DRIVER M: Peter Korsgaard peter@korsgaard.com +M: Andrew Lunn andrew@lunn.ch L: linux-i2c@vger.kernel.org S: Maintained F: Documentation/i2c/busses/i2c-ocores F: drivers/i2c/busses/i2c-ocores.c +F: include/linux/platform_data/i2c-ocores.h
OPENRISC ARCHITECTURE M: Jonas Bonn jonas@southpole.se @@@ -11518,7 -11501,7 +11533,7 @@@ F: Documentation/blockdev/paride.tx F: drivers/block/paride/
PARISC ARCHITECTURE -M: "James E.J. Bottomley" jejb@parisc-linux.org +M: "James E.J. Bottomley" James.Bottomley@HansenPartnership.com M: Helge Deller deller@gmx.de L: linux-parisc@vger.kernel.org W: http://www.parisc-linux.org/ @@@ -12409,7 -12392,6 +12424,7 @@@ L: linux-media@vger.kernel.or T: git git://linuxtv.org/media_tree.git S: Odd Fixes F: drivers/media/usb/pwc/* +F: include/trace/events/pwc.h
PWM FAN DRIVER M: Kamil Debski kamil@wypas.org @@@ -12635,11 -12617,11 +12650,11 @@@ F: Documentation/media/v4l-drivers/qcom F: drivers/media/platform/qcom/camss/
QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096 -M: Ilia Lin ilia.lin@gmail.com -L: linux-pm@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt -F: drivers/cpufreq/qcom-cpufreq-kryo.c +M: Ilia Lin ilia.lin@kernel.org +L: linux-pm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/opp/kryo-cpufreq.txt +F: drivers/cpufreq/qcom-cpufreq-kryo.c
QUALCOMM EMAC GIGABIT ETHERNET DRIVER M: Timur Tabi timur@kernel.org @@@ -12647,6 -12629,14 +12662,14 @@@ L: netdev@vger.kernel.or S: Maintained F: drivers/net/ethernet/qualcomm/emac/
+ QUALCOMM ETHQOS ETHERNET DRIVER + M: Vinod Koul vkoul@kernel.org + M: Niklas Cassel niklas.cassel@linaro.org + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c + F: Documentation/devicetree/bindings/net/qcom,dwmac.txt + QUALCOMM GENERIC INTERFACE I2C DRIVER M: Alok Chauhan alokc@codeaurora.org M: Karthikeyan Ramasubramanian kramasub@codeaurora.org @@@ -13003,7 -12993,6 +13026,7 @@@ F: drivers/reset F: Documentation/devicetree/bindings/reset/ F: include/dt-bindings/reset/ F: include/linux/reset.h +F: include/linux/reset/ F: include/linux/reset-controller.h
RESTARTABLE SEQUENCES SUPPORT @@@ -13772,6 -13761,7 +13795,7 @@@ F: drivers/misc/sgi-xp
SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS M: Ursula Braun ubraun@linux.ibm.com + M: Karsten Graul kgraul@linux.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported diff --combined arch/arm/boot/dts/armada-38x.dtsi index 746887f7be5a,7b2e2bd6479b..96c18703e471 --- a/arch/arm/boot/dts/armada-38x.dtsi +++ b/arch/arm/boot/dts/armada-38x.dtsi @@@ -9,15 -9,13 +9,15 @@@ * Thomas Petazzoni thomas.petazzoni@free-electrons.com */
-#include "skeleton.dtsi" #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/irq.h>
#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16))
/ { + #address-cells = <1>; + #size-cells = <1>; + model = "Marvell Armada 38x family SoC"; compatible = "marvell,armada380";
@@@ -337,6 -335,43 +337,43 @@@ #clock-cells = <1>; };
+ comphy: phy@18300 { + compatible = "marvell,armada-380-comphy"; + reg = <0x18300 0x100>; + #address-cells = <1>; + #size-cells = <0>; + + comphy0: phy@0 { + reg = <0>; + #phy-cells = <1>; + }; + + comphy1: phy@1 { + reg = <1>; + #phy-cells = <1>; + }; + + comphy2: phy@2 { + reg = <2>; + #phy-cells = <1>; + }; + + comphy3: phy@3 { + reg = <3>; + #phy-cells = <1>; + }; + + comphy4: phy@4 { + reg = <4>; + #phy-cells = <1>; + }; + + comphy5: phy@5 { + reg = <5>; + #phy-cells = <1>; + }; + }; + coreclk: mvebu-sar@18600 { compatible = "marvell,armada-380-core-clock"; reg = <0x18600 0x04>; diff --combined arch/arm/boot/dts/ls1021a.dtsi index 114e41e290e9,ad75959b99c1..b4f2723ecd86 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@@ -45,12 -45,11 +45,12 @@@ * OTHER DEALINGS IN THE SOFTWARE. */
-#include "skeleton64.dtsi" #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/thermal/thermal.h>
/ { + #address-cells = <2>; + #size-cells = <2>; compatible = "fsl,ls1021a"; interrupt-parent = <&gic>;
@@@ -89,11 -88,6 +89,11 @@@ }; };
+ memory { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x0>; + }; + sysclk: sysclk { compatible = "fixed-clock"; #clock-cells = <0>; @@@ -131,13 -125,6 +131,13 @@@ interrupt-parent = <&gic>; ranges;
+ ddr: memory-controller@1080000 { + compatible = "fsl,qoriq-memory-controller"; + reg = <0x0 0x1080000 0x0 0x1000>; + interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; + big-endian; + }; + gic: interrupt-controller@1400000 { compatible = "arm,gic-400", "arm,cortex-a7-gic"; #interrupt-cells = <3>; @@@ -719,6 -706,7 +719,7 @@@ fsl,tmr-fiper1 = <999999995>; fsl,tmr-fiper2 = <99990>; fsl,max-adj = <499999999>; + fsl,extts-fifo; };
enet0: ethernet@2d10000 { @@@ -824,7 -812,6 +825,7 @@@ dr_mode = "host"; snps,quirk-frame-length-adjustment = <0x20>; snps,dis_rxdet_inp3_quirk; + snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; };
pcie@3400000 { @@@ -838,7 -825,6 +839,7 @@@ #size-cells = <2>; device_type = "pci"; num-lanes = <4>; + num-viewport = <6>; bus-range = <0x0 0xff>; ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ @@@ -863,7 -849,6 +864,7 @@@ #size-cells = <2>; device_type = "pci"; num-lanes = <4>; + num-viewport = <6>; bus-range = <0x0 0xff>; ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */ 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ diff --combined arch/xtensa/include/asm/Kbuild index 27bd3d33b010,809f39ce08c0..d939e13e8d84 --- a/arch/xtensa/include/asm/Kbuild +++ b/arch/xtensa/include/asm/Kbuild @@@ -23,10 -23,9 +23,11 @@@ generic-y += mm-arch-hooks. generic-y += param.h generic-y += percpu.h generic-y += preempt.h +generic-y += qrwlock.h +generic-y += qspinlock.h generic-y += rwsem.h generic-y += sections.h + generic-y += socket.h generic-y += topology.h generic-y += trace_clock.h generic-y += vga.h diff --combined drivers/net/Kconfig index 21bf8ac78380,7f9727f64f55..af0be8447ef5 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@@ -145,13 -145,15 +145,15 @@@ config MACVTA To compile this driver as a module, choose M here: the module will be called macvtap.
+ config IPVLAN_L3S + depends on NETFILTER + def_bool y + select NET_L3_MASTER_DEV
config IPVLAN tristate "IP-VLAN support" depends on INET depends on IPV6 || !IPV6 - depends on NETFILTER - select NET_L3_MASTER_DEV ---help--- This allows one to create virtual devices off of a main interface and packets will be delivered based on the dest L3 (IPv6/IPv4 addr) @@@ -197,9 -199,9 +199,9 @@@ config VXLA
config GENEVE tristate "Generic Network Virtualization Encapsulation" - depends on INET && NET_UDP_TUNNEL + depends on INET depends on IPV6 || !IPV6 - select NET_IP_TUNNEL + select NET_UDP_TUNNEL select GRO_CELLS ---help--- This allows one to create geneve virtual interfaces that provide diff --combined drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index c500ea77aaa0,87777b09f5e0..967ea5ee5102 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@@ -86,16 -86,16 +86,16 @@@ static void free_rx_fd(struct dpaa2_eth for (i = 1; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) { addr = dpaa2_sg_get_addr(&sgt[i]); sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, addr); - dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL);
- skb_free_frag(sg_vaddr); + free_pages((unsigned long)sg_vaddr, 0); if (dpaa2_sg_is_final(&sgt[i])) break; }
free_buf: - skb_free_frag(vaddr); + free_pages((unsigned long)vaddr, 0); }
/* Build a linear skb based on a single-buffer frame descriptor */ @@@ -109,7 -109,7 +109,7 @@@ static struct sk_buff *build_linear_skb
ch->buf_count--;
- skb = build_skb(fd_vaddr, DPAA2_ETH_SKB_SIZE); + skb = build_skb(fd_vaddr, DPAA2_ETH_RX_BUF_RAW_SIZE); if (unlikely(!skb)) return NULL;
@@@ -144,19 -144,19 +144,19 @@@ static struct sk_buff *build_frag_skb(s /* Get the address and length from the S/G entry */ sg_addr = dpaa2_sg_get_addr(sge); sg_vaddr = dpaa2_iova_to_virt(priv->iommu_domain, sg_addr); - dma_unmap_single(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL);
sg_length = dpaa2_sg_get_len(sge);
if (i == 0) { /* We build the skb around the first data buffer */ - skb = build_skb(sg_vaddr, DPAA2_ETH_SKB_SIZE); + skb = build_skb(sg_vaddr, DPAA2_ETH_RX_BUF_RAW_SIZE); if (unlikely(!skb)) { /* Free the first SG entry now, since we already * unmapped it and obtained the virtual address */ - skb_free_frag(sg_vaddr); + free_pages((unsigned long)sg_vaddr, 0);
/* We still need to subtract the buffers used * by this FD from our software counter @@@ -211,9 -211,9 +211,9 @@@ static void free_bufs(struct dpaa2_eth_
for (i = 0; i < count; i++) { vaddr = dpaa2_iova_to_virt(priv->iommu_domain, buf_array[i]); - dma_unmap_single(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); - skb_free_frag(vaddr); + dma_unmap_page(dev, buf_array[i], DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL); + free_pages((unsigned long)vaddr, 0); } }
@@@ -264,9 -264,7 +264,7 @@@ static int xdp_enqueue(struct dpaa2_eth
fq = &priv->fq[queue_id]; for (i = 0; i < DPAA2_ETH_ENQUEUE_RETRIES; i++) { - err = dpaa2_io_service_enqueue_qd(fq->channel->dpio, - priv->tx_qdid, 0, - fq->tx_qdbin, fd); + err = priv->enqueue(priv, fq, fd, 0); if (err != -EBUSY) break; } @@@ -378,16 -376,16 +376,16 @@@ static void dpaa2_eth_rx(struct dpaa2_e return; }
- dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL); skb = build_linear_skb(ch, fd, vaddr); } else if (fd_format == dpaa2_fd_sg) { WARN_ON(priv->xdp_prog);
- dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page(dev, addr, DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL); skb = build_frag_skb(priv, ch, buf_data); - skb_free_frag(vaddr); + free_pages((unsigned long)vaddr, 0); percpu_extras->rx_sg_frames++; percpu_extras->rx_sg_bytes += dpaa2_fd_get_len(fd); } else { @@@ -657,7 -655,7 +655,7 @@@ static int build_single_fd(struct dpaa2 * dpaa2_eth_tx(). */ static void free_tx_fd(const struct dpaa2_eth_priv *priv, - const struct dpaa2_fd *fd) + const struct dpaa2_fd *fd, bool in_napi) { struct device *dev = priv->net_dev->dev.parent; dma_addr_t fd_addr; @@@ -712,7 -710,7 +710,7 @@@ skb_free_frag(skbh);
/* Move on with skb release */ - dev_kfree_skb(skb); + napi_consume_skb(skb, in_napi); }
static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) @@@ -785,9 -783,7 +783,7 @@@ queue_mapping = skb_get_queue_mapping(skb); fq = &priv->fq[queue_mapping]; for (i = 0; i < DPAA2_ETH_ENQUEUE_RETRIES; i++) { - err = dpaa2_io_service_enqueue_qd(fq->channel->dpio, - priv->tx_qdid, 0, - fq->tx_qdbin, &fd); + err = priv->enqueue(priv, fq, &fd, 0); if (err != -EBUSY) break; } @@@ -795,7 -791,7 +791,7 @@@ if (unlikely(err < 0)) { percpu_stats->tx_errors++; /* Clean up everything, including freeing the skb */ - free_tx_fd(priv, &fd); + free_tx_fd(priv, &fd, false); } else { fd_len = dpaa2_fd_get_len(&fd); percpu_stats->tx_packets++; @@@ -837,7 -833,7 +833,7 @@@ static void dpaa2_eth_tx_conf(struct dp
/* Check frame errors in the FD field */ fd_errors = dpaa2_fd_get_ctrl(fd) & DPAA2_FD_TX_ERR_MASK; - free_tx_fd(priv, fd); + free_tx_fd(priv, fd, true);
if (likely(!fd_errors)) return; @@@ -903,7 -899,7 +899,7 @@@ static int add_bufs(struct dpaa2_eth_pr { struct device *dev = priv->net_dev->dev.parent; u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; - void *buf; + struct page *page; dma_addr_t addr; int i, err;
@@@ -911,14 -907,16 +907,16 @@@ /* Allocate buffer visible to WRIOP + skb shared info + * alignment padding */ - buf = napi_alloc_frag(dpaa2_eth_buf_raw_size(priv)); - if (unlikely(!buf)) + /* allocate one page for each Rx buffer. WRIOP sees + * the entire page except for a tailroom reserved for + * skb shared info + */ + page = dev_alloc_pages(0); + if (!page) goto err_alloc;
- buf = PTR_ALIGN(buf, priv->rx_buf_align); - - addr = dma_map_single(dev, buf, DPAA2_ETH_RX_BUF_SIZE, - DMA_BIDIRECTIONAL); + addr = dma_map_page(dev, page, 0, DPAA2_ETH_RX_BUF_SIZE, + DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(dev, addr))) goto err_map;
@@@ -926,7 -924,7 +924,7 @@@
/* tracing point */ trace_dpaa2_eth_buf_seed(priv->net_dev, - buf, dpaa2_eth_buf_raw_size(priv), + page, DPAA2_ETH_RX_BUF_RAW_SIZE, addr, DPAA2_ETH_RX_BUF_SIZE, bpid); } @@@ -948,7 -946,7 +946,7 @@@ release_bufs return i;
err_map: - skb_free_frag(buf); + __free_pages(page, 0); err_alloc: /* If we managed to allocate at least some buffers, * release them to hardware @@@ -1243,34 -1241,36 +1241,36 @@@ enable_err return err; }
- /* The DPIO store must be empty when we call this, - * at the end of every NAPI cycle. - */ - static u32 drain_channel(struct dpaa2_eth_channel *ch) + /* Total number of in-flight frames on ingress queues */ + static u32 ingress_fq_count(struct dpaa2_eth_priv *priv) { - u32 drained = 0, total = 0; + struct dpaa2_eth_fq *fq; + u32 fcnt = 0, bcnt = 0, total = 0; + int i, err;
- do { - pull_channel(ch); - drained = consume_frames(ch, NULL); - total += drained; - } while (drained); + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + err = dpaa2_io_query_fq_count(NULL, fq->fqid, &fcnt, &bcnt); + if (err) { + netdev_warn(priv->net_dev, "query_fq_count failed"); + break; + } + total += fcnt; + }
return total; }
- static u32 drain_ingress_frames(struct dpaa2_eth_priv *priv) + static void wait_for_fq_empty(struct dpaa2_eth_priv *priv) { - struct dpaa2_eth_channel *ch; - int i; - u32 drained = 0; - - for (i = 0; i < priv->num_channels; i++) { - ch = priv->channel[i]; - drained += drain_channel(ch); - } + int retries = 10; + u32 pending;
- return drained; + do { + pending = ingress_fq_count(priv); + if (pending) + msleep(100); + } while (pending && --retries); }
static int dpaa2_eth_stop(struct net_device *net_dev) @@@ -1278,14 -1278,22 +1278,22 @@@ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); int dpni_enabled = 0; int retries = 10; - u32 drained;
netif_tx_stop_all_queues(net_dev); netif_carrier_off(net_dev);
- /* Loop while dpni_disable() attempts to drain the egress FQs - * and confirm them back to us. + /* On dpni_disable(), the MC firmware will: + * - stop MAC Rx and wait for all Rx frames to be enqueued to software + * - cut off WRIOP dequeues from egress FQs and wait until transmission + * of all in flight Tx frames is finished (and corresponding Tx conf + * frames are enqueued back to software) + * + * Before calling dpni_disable(), we wait for all Tx frames to arrive + * on WRIOP. After it finishes, wait until all remaining frames on Rx + * and Tx conf queues are consumed on NAPI poll. */ + msleep(500); + do { dpni_disable(priv->mc_io, 0, priv->mc_token); dpni_is_enabled(priv->mc_io, 0, priv->mc_token, &dpni_enabled); @@@ -1300,19 -1308,9 +1308,9 @@@ */ }
- /* Wait for NAPI to complete on every core and disable it. - * In particular, this will also prevent NAPI from being rescheduled if - * a new CDAN is serviced, effectively discarding the CDAN. We therefore - * don't even need to disarm the channels, except perhaps for the case - * of a huge coalescing value. - */ + wait_for_fq_empty(priv); disable_ch_napi(priv);
- /* Manually drain the Rx and TxConf queues */ - drained = drain_ingress_frames(priv); - if (drained) - netdev_dbg(net_dev, "Drained %d frames.\n", drained); - /* Empty the buffer pool */ drain_pool(priv);
@@@ -1902,7 -1900,7 +1900,7 @@@ static int setup_dpio(struct dpaa2_eth_
/* Register the new context */ channel->dpio = dpaa2_io_service_select(i); - err = dpaa2_io_service_register(channel->dpio, nctx); + err = dpaa2_io_service_register(channel->dpio, nctx, dev); if (err) { dev_dbg(dev, "No affine DPIO for cpu %d\n", i); /* If no affine DPIO for this core, there's probably @@@ -1942,7 -1940,7 +1940,7 @@@ return 0;
err_set_cdan: - dpaa2_io_service_deregister(channel->dpio, nctx); + dpaa2_io_service_deregister(channel->dpio, nctx, dev); err_service_reg: free_channel(priv, channel); err_alloc_ch: @@@ -1962,14 -1960,13 +1960,14 @@@
static void free_dpio(struct dpaa2_eth_priv *priv) { - int i; + struct device *dev = priv->net_dev->dev.parent; struct dpaa2_eth_channel *ch; + int i;
/* deregister CDAN notifications and free channels */ for (i = 0; i < priv->num_channels; i++) { ch = priv->channel[i]; - dpaa2_io_service_deregister(ch->dpio, &ch->nctx); + dpaa2_io_service_deregister(ch->dpio, &ch->nctx, dev); free_channel(priv, ch); } } @@@ -2135,6 -2132,7 +2133,7 @@@ static int set_buffer_layout(struct dpa { struct device *dev = priv->net_dev->dev.parent; struct dpni_buffer_layout buf_layout = {0}; + u16 rx_buf_align; int err;
/* We need to check for WRIOP version 1.0.0, but depending on the MC @@@ -2143,9 -2141,9 +2142,9 @@@ */ if (priv->dpni_attrs.wriop_version == DPAA2_WRIOP_VERSION(0, 0, 0) || priv->dpni_attrs.wriop_version == DPAA2_WRIOP_VERSION(1, 0, 0)) - priv->rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN_REV1; + rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN_REV1; else - priv->rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN; + rx_buf_align = DPAA2_ETH_RX_BUF_ALIGN;
/* tx buffer */ buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE; @@@ -2185,7 -2183,7 +2184,7 @@@ /* rx buffer */ buf_layout.pass_frame_status = true; buf_layout.pass_parser_result = true; - buf_layout.data_align = priv->rx_buf_align; + buf_layout.data_align = rx_buf_align; buf_layout.data_head_room = dpaa2_eth_rx_head_room(priv); buf_layout.private_data_size = 0; buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | @@@ -2203,6 -2201,36 +2202,36 @@@ return 0; }
+ #define DPNI_ENQUEUE_FQID_VER_MAJOR 7 + #define DPNI_ENQUEUE_FQID_VER_MINOR 9 + + static inline int dpaa2_eth_enqueue_qd(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq, + struct dpaa2_fd *fd, u8 prio) + { + return dpaa2_io_service_enqueue_qd(fq->channel->dpio, + priv->tx_qdid, prio, + fq->tx_qdbin, fd); + } + + static inline int dpaa2_eth_enqueue_fq(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq, + struct dpaa2_fd *fd, + u8 prio __always_unused) + { + return dpaa2_io_service_enqueue_fq(fq->channel->dpio, + fq->tx_fqid, fd); + } + + static void set_enqueue_mode(struct dpaa2_eth_priv *priv) + { + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_ENQUEUE_FQID_VER_MAJOR, + DPNI_ENQUEUE_FQID_VER_MINOR) < 0) + priv->enqueue = dpaa2_eth_enqueue_qd; + else + priv->enqueue = dpaa2_eth_enqueue_fq; + } + /* Configure the DPNI object this interface is associated with */ static int setup_dpni(struct fsl_mc_device *ls_dev) { @@@ -2256,6 -2284,8 +2285,8 @@@ if (err) goto close;
+ set_enqueue_mode(priv); + priv->cls_rules = devm_kzalloc(dev, sizeof(struct dpaa2_eth_cls_rule) * dpaa2_eth_fs_count(priv), GFP_KERNEL); if (!priv->cls_rules) @@@ -2340,6 -2370,7 +2371,7 @@@ static int setup_tx_flow(struct dpaa2_e }
fq->tx_qdbin = qid.qdbin; + fq->tx_fqid = qid.fqid;
err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid, @@@ -3084,6 -3115,10 +3116,10 @@@ static int dpaa2_eth_probe(struct fsl_m goto err_netdev_reg; }
+ #ifdef CONFIG_DEBUG_FS + dpaa2_dbg_add(priv); + #endif + dev_info(dev, "Probed interface %s\n", net_dev->name); return 0;
@@@ -3127,6 -3162,9 +3163,9 @@@ static int dpaa2_eth_remove(struct fsl_ net_dev = dev_get_drvdata(dev); priv = netdev_priv(net_dev);
+ #ifdef CONFIG_DEBUG_FS + dpaa2_dbg_remove(priv); + #endif unregister_netdev(net_dev);
if (priv->do_link_poll) @@@ -3171,4 -3209,25 +3210,25 @@@ static struct fsl_mc_driver dpaa2_eth_d .match_id_table = dpaa2_eth_match_id_table };
- module_fsl_mc_driver(dpaa2_eth_driver); + static int __init dpaa2_eth_driver_init(void) + { + int err; + + dpaa2_eth_dbg_init(); + err = fsl_mc_driver_register(&dpaa2_eth_driver); + if (err) { + dpaa2_eth_dbg_exit(); + return err; + } + + return 0; + } + + static void __exit dpaa2_eth_driver_exit(void) + { + dpaa2_eth_dbg_exit(); + fsl_mc_driver_unregister(&dpaa2_eth_driver); + } + + module_init(dpaa2_eth_driver_init); + module_exit(dpaa2_eth_driver_exit); diff --combined drivers/net/ethernet/mellanox/mlx5/core/Makefile index 0257731e6d42,6bb2a860b15b..789e52b759a1 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@@ -13,7 -13,7 +13,7 @@@ obj-$(CONFIG_MLX5_CORE) += mlx5_core. # mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o alloc.o qp.o port.o mr.o pd.o \ - mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ + transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \ lib/devcom.o diag/fs_tracepoint.o diag/fw_tracer.o
@@@ -22,7 -22,7 +22,7 @@@ # mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \ en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o \ - en_selftest.o en/port.o en/monitor_stats.o + en_selftest.o en/port.o en/monitor_stats.o en/reporter_tx.o
# # Netdev extra diff --combined drivers/net/ethernet/realtek/r8169.c index 6e36b88ca7c9,1dd72137fd53..10bab1f7150a --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@@ -229,7 -229,6 +229,6 @@@ static const struct pci_device_id rtl81
MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
- static int use_dac = -1; static struct { u32 msg_enable; } debug = { -1 }; @@@ -639,6 -638,7 +638,7 @@@ struct rtl8169_private void __iomem *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; struct net_device *dev; + struct phy_device *phydev; struct napi_struct napi; u32 msg_enable; u16 mac_version; @@@ -679,12 -679,12 +679,12 @@@ } wk;
unsigned supports_gmii:1; - struct mii_bus *mii_bus; dma_addr_t counters_phys_addr; struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts;
+ const char *fw_name; struct rtl_fw { const struct firmware *fw;
@@@ -697,15 -697,12 +697,12 @@@ size_t size; } phy_action; } *rtl_fw; - #define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
u32 ocp_base; };
MODULE_AUTHOR("Realtek and the Linux r8169 crew netdev@vger.kernel.org"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); - module_param(use_dac, int, 0); - MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); module_param_named(debug, debug.msg_enable, int, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); MODULE_SOFTDEP("pre: realtek"); @@@ -745,6 -742,16 +742,16 @@@ static void rtl_unlock_work(struct rtl8 mutex_unlock(&tp->wk.mutex); }
+ static void rtl_lock_config_regs(struct rtl8169_private *tp) + { + RTL_W8(tp, Cfg9346, Cfg9346_Lock); + } + + static void rtl_unlock_config_regs(struct rtl8169_private *tp) + { + RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + } + static void rtl_tx_performance_tweak(struct rtl8169_private *tp, u16 force) { pcie_capability_clear_and_set_word(tp->pci_dev, PCI_EXP_DEVCTL, @@@ -1278,21 -1285,14 +1285,16 @@@ static u8 rtl8168d_efuse_read(struct rt RTL_R32(tp, EFUSEAR) & EFUSEAR_DATA_MASK : ~0; }
- static u16 rtl_get_events(struct rtl8169_private *tp) - { - return RTL_R16(tp, IntrStatus); - } - static void rtl_ack_events(struct rtl8169_private *tp, u16 bits) { RTL_W16(tp, IntrStatus, bits); + mmiowb(); }
static void rtl_irq_disable(struct rtl8169_private *tp) { RTL_W16(tp, IntrMask, 0); + mmiowb(); }
#define RTL_EVENT_NAPI_RX (RxOK | RxErr) @@@ -1315,7 -1315,7 +1317,7 @@@ static void rtl8169_irq_mask_and_ack(st static void rtl_link_chg_patch(struct rtl8169_private *tp) { struct net_device *dev = tp->dev; - struct phy_device *phydev = dev->phydev; + struct phy_device *phydev = tp->phydev;
if (!netif_running(dev)) return; @@@ -1371,41 -1371,6 +1373,6 @@@
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
- static u32 __rtl8169_get_wol(struct rtl8169_private *tp) - { - u8 options; - u32 wolopts = 0; - - options = RTL_R8(tp, Config1); - if (!(options & PMEnable)) - return 0; - - options = RTL_R8(tp, Config3); - if (options & LinkUp) - wolopts |= WAKE_PHY; - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: - if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2) - wolopts |= WAKE_MAGIC; - break; - default: - if (options & MagicPacket) - wolopts |= WAKE_MAGIC; - break; - } - - options = RTL_R8(tp, Config5); - if (options & UWF) - wolopts |= WAKE_UCAST; - if (options & BWF) - wolopts |= WAKE_BCAST; - if (options & MWF) - wolopts |= WAKE_MCAST; - - return wolopts; - } - static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct rtl8169_private *tp = netdev_priv(dev); @@@ -1433,7 -1398,7 +1400,7 @@@ static void __rtl8169_set_wol(struct rt }; u8 options;
- RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp);
switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: @@@ -1481,7 -1446,7 +1448,7 @@@ break; }
- RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp);
device_set_wakeup_enable(tp_to_dev(tp), wolopts); } @@@ -1510,11 -1475,6 +1477,6 @@@ static int rtl8169_set_wol(struct net_d return 0; }
- static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp) - { - return rtl_chip_infos[tp->mac_version].fw_name; - } - static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@@ -1524,7 -1484,7 +1486,7 @@@ strlcpy(info->driver, MODULENAME, sizeof(info->driver)); strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info)); BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version)); - if (!IS_ERR_OR_NULL(rtl_fw)) + if (rtl_fw) strlcpy(info->fw_version, rtl_fw->version, sizeof(info->fw_version)); } @@@ -1989,6 -1949,196 +1951,196 @@@ static int rtl_set_coalesce(struct net_ return 0; }
+ static int rtl_get_eee_supp(struct rtl8169_private *tp) + { + struct phy_device *phydev = tp->phydev; + int ret; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_38: + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); + break; + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + phy_write(phydev, 0x1f, 0x0a5c); + ret = phy_read(phydev, 0x12); + phy_write(phydev, 0x1f, 0x0000); + break; + default: + ret = -EPROTONOSUPPORT; + break; + } + + return ret; + } + + static int rtl_get_eee_lpadv(struct rtl8169_private *tp) + { + struct phy_device *phydev = tp->phydev; + int ret; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_38: + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); + break; + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + phy_write(phydev, 0x1f, 0x0a5d); + ret = phy_read(phydev, 0x11); + phy_write(phydev, 0x1f, 0x0000); + break; + default: + ret = -EPROTONOSUPPORT; + break; + } + + return ret; + } + + static int rtl_get_eee_adv(struct rtl8169_private *tp) + { + struct phy_device *phydev = tp->phydev; + int ret; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_38: + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV); + break; + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + phy_write(phydev, 0x1f, 0x0a5d); + ret = phy_read(phydev, 0x10); + phy_write(phydev, 0x1f, 0x0000); + break; + default: + ret = -EPROTONOSUPPORT; + break; + } + + return ret; + } + + static int rtl_set_eee_adv(struct rtl8169_private *tp, int val) + { + struct phy_device *phydev = tp->phydev; + int ret = 0; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_38: + ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); + break; + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + phy_write(phydev, 0x1f, 0x0a5d); + phy_write(phydev, 0x10, val); + phy_write(phydev, 0x1f, 0x0000); + break; + default: + ret = -EPROTONOSUPPORT; + break; + } + + return ret; + } + + static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) + { + struct rtl8169_private *tp = netdev_priv(dev); + struct device *d = tp_to_dev(tp); + int ret; + + pm_runtime_get_noresume(d); + + if (!pm_runtime_active(d)) { + ret = -EOPNOTSUPP; + goto out; + } + + /* Get Supported EEE */ + ret = rtl_get_eee_supp(tp); + if (ret < 0) + goto out; + data->supported = mmd_eee_cap_to_ethtool_sup_t(ret); + + /* Get advertisement EEE */ + ret = rtl_get_eee_adv(tp); + if (ret < 0) + goto out; + data->advertised = mmd_eee_adv_to_ethtool_adv_t(ret); + data->eee_enabled = !!data->advertised; + + /* Get LP advertisement EEE */ + ret = rtl_get_eee_lpadv(tp); + if (ret < 0) + goto out; + data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(ret); + data->eee_active = !!(data->advertised & data->lp_advertised); + out: + pm_runtime_put_noidle(d); + return ret < 0 ? ret : 0; + } + + static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) + { + struct rtl8169_private *tp = netdev_priv(dev); + struct device *d = tp_to_dev(tp); + int old_adv, adv = 0, cap, ret; + + pm_runtime_get_noresume(d); + + if (!dev->phydev || !pm_runtime_active(d)) { + ret = -EOPNOTSUPP; + goto out; + } + + if (dev->phydev->autoneg == AUTONEG_DISABLE || + dev->phydev->duplex != DUPLEX_FULL) { + ret = -EPROTONOSUPPORT; + goto out; + } + + /* Get Supported EEE */ + ret = rtl_get_eee_supp(tp); + if (ret < 0) + goto out; + cap = ret; + + ret = rtl_get_eee_adv(tp); + if (ret < 0) + goto out; + old_adv = ret; + + if (data->eee_enabled) { + adv = !data->advertised ? cap : + ethtool_adv_to_mmd_eee_adv_t(data->advertised) & cap; + /* Mask prohibited EEE modes */ + adv &= ~dev->phydev->eee_broken_modes; + } + + if (old_adv != adv) { + ret = rtl_set_eee_adv(tp, adv); + if (ret < 0) + goto out; + + /* Restart autonegotiation so the new modes get sent to the + * link partner. + */ + ret = phy_restart_aneg(dev->phydev); + } + + out: + pm_runtime_put_noidle(d); + return ret < 0 ? ret : 0; + } + static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, @@@ -2005,10 -2155,20 +2157,20 @@@ .get_ethtool_stats = rtl8169_get_ethtool_stats, .get_ts_info = ethtool_op_get_ts_info, .nway_reset = phy_ethtool_nway_reset, + .get_eee = rtl8169_get_eee, + .set_eee = rtl8169_set_eee, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, };
+ static void rtl_enable_eee(struct rtl8169_private *tp) + { + int supported = rtl_get_eee_supp(tp); + + if (supported > 0) + rtl_set_eee_adv(tp, supported); + } + static void rtl8169_get_mac_version(struct rtl8169_private *tp) { /* @@@ -2201,7 -2361,7 +2363,7 @@@ static bool rtl_fw_format_ok(struct rtl if (fw->size % FW_OPCODE_SIZE) goto out;
- strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE); + strlcpy(version, tp->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data; pa->size = fw->size / FW_OPCODE_SIZE; @@@ -2376,20 -2536,18 +2538,18 @@@ static void rtl_phy_write_fw(struct rtl
static void rtl_release_firmware(struct rtl8169_private *tp) { - if (!IS_ERR_OR_NULL(tp->rtl_fw)) { + if (tp->rtl_fw) { release_firmware(tp->rtl_fw->fw); kfree(tp->rtl_fw); + tp->rtl_fw = NULL; } - tp->rtl_fw = RTL_FIRMWARE_UNKNOWN; }
static void rtl_apply_firmware(struct rtl8169_private *tp) { - struct rtl_fw *rtl_fw = tp->rtl_fw; - /* TODO: release firmware once rtl_phy_write_fw signals failures. */ - if (!IS_ERR_OR_NULL(rtl_fw)) - rtl_phy_write_fw(tp, rtl_fw); + if (tp->rtl_fw) + rtl_phy_write_fw(tp, tp->rtl_fw); }
static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) @@@ -2400,6 -2558,33 +2560,33 @@@ rtl_apply_firmware(tp); }
+ static void rtl8168_config_eee_mac(struct rtl8169_private *tp) + { + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0003, 0x0000, ERIAR_EXGMAC); + } + + static void rtl8168f_config_eee_phy(struct rtl8169_private *tp) + { + struct phy_device *phydev = tp->phydev; + + phy_write(phydev, 0x1f, 0x0007); + phy_write(phydev, 0x1e, 0x0020); + phy_set_bits(phydev, 0x15, BIT(8)); + + phy_write(phydev, 0x1f, 0x0005); + phy_write(phydev, 0x05, 0x8b85); + phy_set_bits(phydev, 0x06, BIT(13)); + + phy_write(phydev, 0x1f, 0x0000); + } + + static void rtl8168g_config_eee_phy(struct rtl8169_private *tp) + { + phy_write(tp->phydev, 0x1f, 0x0a43); + phy_set_bits(tp->phydev, 0x11, BIT(4)); + phy_write(tp->phydev, 0x1f, 0x0000); + } + static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@@ -3167,22 -3352,8 +3354,8 @@@ static void rtl8168e_2_hw_phy_config(st rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000);
- /* EEE setting */ - rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0003, 0x0000, ERIAR_EXGMAC); - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x2000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0004); - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x0020); - rtl_w0w1_phy(tp, 0x15, 0x0100, 0x0000); - rtl_writephy(tp, 0x1f, 0x0002); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0d, 0x0007); - rtl_writephy(tp, 0x0e, 0x003c); - rtl_writephy(tp, 0x0d, 0x4007); - rtl_writephy(tp, 0x0e, 0x0006); - rtl_writephy(tp, 0x0d, 0x0000); + rtl8168f_config_eee_phy(tp); + rtl_enable_eee(tp);
/* Green feature */ rtl_writephy(tp, 0x1f, 0x0003); @@@ -3217,6 -3388,9 +3390,9 @@@ static void rtl8168f_hw_phy_config(stru rtl_writephy(tp, 0x05, 0x8b86); rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); + + rtl8168f_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) @@@ -3350,22 -3524,6 +3526,6 @@@ static void rtl8411_hw_phy_config(struc rtl_w0w1_phy(tp, 0x06, 0x8000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000);
- /* eee setting */ - rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC); - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x2000); - rtl_writephy(tp, 0x1f, 0x0004); - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x0020); - rtl_w0w1_phy(tp, 0x15, 0x0000, 0x0100); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0d, 0x0007); - rtl_writephy(tp, 0x0e, 0x003c); - rtl_writephy(tp, 0x0d, 0x4007); - rtl_writephy(tp, 0x0e, 0x0000); - rtl_writephy(tp, 0x0d, 0x0000); - /* Green feature */ rtl_writephy(tp, 0x1f, 0x0003); rtl_w0w1_phy(tp, 0x19, 0x0000, 0x0001); @@@ -3373,6 -3531,30 +3533,30 @@@ rtl_writephy(tp, 0x1f, 0x0000); }
+ static void rtl8168g_disable_aldps(struct rtl8169_private *tp) + { + phy_write(tp->phydev, 0x1f, 0x0a43); + phy_clear_bits(tp->phydev, 0x10, BIT(2)); + } + + static void rtl8168g_phy_adjust_10m_aldps(struct rtl8169_private *tp) + { + struct phy_device *phydev = tp->phydev; + + phy_write(phydev, 0x1f, 0x0bcc); + phy_clear_bits(phydev, 0x14, BIT(8)); + + phy_write(phydev, 0x1f, 0x0a44); + phy_set_bits(phydev, 0x11, BIT(7) | BIT(6)); + + phy_write(phydev, 0x1f, 0x0a43); + phy_write(phydev, 0x13, 0x8084); + phy_clear_bits(phydev, 0x14, BIT(14) | BIT(13)); + phy_set_bits(phydev, 0x10, BIT(12) | BIT(1) | BIT(0)); + + phy_write(phydev, 0x1f, 0x0000); + } + static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) { rtl_apply_firmware(tp); @@@ -3399,14 -3581,7 +3583,7 @@@ rtl_writephy(tp, 0x1f, 0x0a44); rtl_w0w1_phy(tp, 0x11, 0x000c, 0x0000);
- rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w0w1_phy(tp, 0x14, 0x0100, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w0w1_phy(tp, 0x11, 0x00c0, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8084); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x6000); - rtl_w0w1_phy(tp, 0x10, 0x1003, 0x0000); + rtl8168g_phy_adjust_10m_aldps(tp);
/* EEE auto-fallback function */ rtl_writephy(tp, 0x1f, 0x0a4b); @@@ -3431,17 -3606,16 +3608,16 @@@ rtl_writephy(tp, 0x14, 0x9065); rtl_writephy(tp, 0x14, 0x1065);
- /* Check ALDPS bit, disable it if enabled */ - rtl_writephy(tp, 0x1f, 0x0a43); - if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); - - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_disable_aldps(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp) { rtl_apply_firmware(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) @@@ -3546,12 -3720,9 +3722,9 @@@ rtl_w0w1_phy(tp, 0x11, 0x0000, 0x0080); rtl_writephy(tp, 0x1f, 0x0000);
- /* Check ALDPS bit, disable it if enabled */ - rtl_writephy(tp, 0x1f, 0x0a43); - if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); - - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_disable_aldps(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) @@@ -3619,12 -3790,9 +3792,9 @@@ rtl_w0w1_phy(tp, 0x11, 0x0000, 0x0080); rtl_writephy(tp, 0x1f, 0x0000);
- /* Check ALDPS bit, disable it if enabled */ - rtl_writephy(tp, 0x1f, 0x0a43); - if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); - - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_disable_aldps(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp) @@@ -3634,16 -3802,7 +3804,7 @@@ rtl_w0w1_phy(tp, 0x11, 0x000c, 0x0000); rtl_writephy(tp, 0x1f, 0x0000);
- /* patch 10M & ALDPS */ - rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x0100); - rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w0w1_phy(tp, 0x11, 0x00c0, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8084); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x6000); - rtl_w0w1_phy(tp, 0x10, 0x1003, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_phy_adjust_10m_aldps(tp);
/* Enable EEE auto-fallback function */ rtl_writephy(tp, 0x1f, 0x0a4b); @@@ -3661,26 -3820,14 +3822,14 @@@ rtl_w0w1_phy(tp, 0x11, 0x4000, 0x2000); rtl_writephy(tp, 0x1f, 0x0000);
- /* Check ALDPS bit, disable it if enabled */ - rtl_writephy(tp, 0x1f, 0x0a43); - if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); - - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_disable_aldps(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8168ep_2_hw_phy_config(struct rtl8169_private *tp) { - /* patch 10M & ALDPS */ - rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x0100); - rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w0w1_phy(tp, 0x11, 0x00c0, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8084); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x6000); - rtl_w0w1_phy(tp, 0x10, 0x1003, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_phy_adjust_10m_aldps(tp);
/* Enable UC LPF tune function */ rtl_writephy(tp, 0x1f, 0x0a43); @@@ -3752,12 -3899,9 +3901,9 @@@ rtl_writephy(tp, 0x14, 0x1065); rtl_writephy(tp, 0x1f, 0x0000);
- /* Check ALDPS bit, disable it if enabled */ - rtl_writephy(tp, 0x1f, 0x0a43); - if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); - - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168g_disable_aldps(tp); + rtl8168g_config_eee_phy(tp); + rtl_enable_eee(tp); }
static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) @@@ -3996,24 -4140,24 +4142,24 @@@ static void rtl8169_init_phy(struct net }
/* We may have called phy_speed_down before */ - phy_speed_up(dev->phydev); + phy_speed_up(tp->phydev);
- genphy_soft_reset(dev->phydev); + genphy_soft_reset(tp->phydev);
/* It was reported that several chips end up with 10MBit/Half on a * 1GBit link after resuming from S3. For whatever reason the PHY on * these chips doesn't properly start a renegotiation when soft-reset. * Explicitly requesting a renegotiation fixes this. */ - if (dev->phydev->autoneg == AUTONEG_ENABLE) - phy_restart_aneg(dev->phydev); + if (tp->phydev->autoneg == AUTONEG_ENABLE) + phy_restart_aneg(tp->phydev); }
static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) { rtl_lock_work(tp);
- RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp);
RTL_W32(tp, MAC4, addr[4] | addr[5] << 8); RTL_R32(tp, MAC4); @@@ -4024,7 -4168,7 +4170,7 @@@ if (tp->mac_version == RTL_GIGA_MAC_VER_34) rtl_rar_exgmac_set(tp, addr);
- RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp);
rtl_unlock_work(tp); } @@@ -4051,10 -4195,12 +4197,12 @@@ static int rtl_set_mac_address(struct n
static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { + struct rtl8169_private *tp = netdev_priv(dev); + if (!netif_running(dev)) return -ENODEV;
- return phy_mii_ioctl(dev->phydev, ifr, cmd); + return phy_mii_ioctl(tp->phydev, ifr, cmd); }
static void rtl_init_mdio_ops(struct rtl8169_private *tp) @@@ -4101,22 -4247,6 +4249,6 @@@ static void rtl_wol_suspend_quirk(struc } }
- static bool rtl_wol_pll_power_down(struct rtl8169_private *tp) - { - struct phy_device *phydev; - - if (!__rtl8169_get_wol(tp)) - return false; - - /* phydev may not be attached to netdevice */ - phydev = mdiobus_get_phy(tp->mii_bus, 0); - - phy_speed_down(phydev, false); - rtl_wol_suspend_quirk(tp); - - return true; - } - static void r8168_pll_power_down(struct rtl8169_private *tp) { if (r8168_check_dash(tp)) @@@ -4126,8 -4256,11 +4258,11 @@@ tp->mac_version == RTL_GIGA_MAC_VER_33) rtl_ephy_write(tp, 0x19, 0xff64);
- if (rtl_wol_pll_power_down(tp)) + if (device_may_wakeup(tp_to_dev(tp))) { + phy_speed_down(tp->phydev, false); + rtl_wol_suspend_quirk(tp); return; + }
switch (tp->mac_version) { case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_33: @@@ -4180,7 -4313,7 +4315,7 @@@ static void r8168_pll_power_up(struct r break; }
- phy_resume(tp->dev->phydev); + phy_resume(tp->phydev); /* give MAC/PHY some time to resume */ msleep(20); } @@@ -4236,18 -4369,18 +4371,18 @@@ static void rtl8169_init_ring_indexes(s static void rtl_hw_jumbo_enable(struct rtl8169_private *tp) { if (tp->jumbo_ops.enable) { - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp); tp->jumbo_ops.enable(tp); - RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp); } }
static void rtl_hw_jumbo_disable(struct rtl8169_private *tp) { if (tp->jumbo_ops.disable) { - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp); tp->jumbo_ops.disable(tp); - RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp); } }
@@@ -4380,21 -4513,20 +4515,20 @@@ static void rtl_hw_reset(struct rtl8169 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); }
- static void rtl_request_uncached_firmware(struct rtl8169_private *tp) + static void rtl_request_firmware(struct rtl8169_private *tp) { struct rtl_fw *rtl_fw; - const char *name; int rc = -ENOMEM;
- name = rtl_lookup_firmware_name(tp); - if (!name) - goto out_no_firmware; + /* firmware loaded already or no firmware available */ + if (tp->rtl_fw || !tp->fw_name) + return;
rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL); if (!rtl_fw) goto err_warn;
- rc = request_firmware(&rtl_fw->fw, name, tp_to_dev(tp)); + rc = request_firmware(&rtl_fw->fw, tp->fw_name, tp_to_dev(tp)); if (rc < 0) goto err_free;
@@@ -4403,7 -4535,7 +4537,7 @@@ goto err_release_firmware;
tp->rtl_fw = rtl_fw; - out: + return;
err_release_firmware: @@@ -4412,16 -4544,7 +4546,7 @@@ err_free kfree(rtl_fw); err_warn: netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n", - name, rc); - out_no_firmware: - tp->rtl_fw = NULL; - goto out; - } - - static void rtl_request_firmware(struct rtl8169_private *tp) - { - if (IS_ERR(tp->rtl_fw)) - rtl_request_uncached_firmware(tp); + tp->fw_name, rc); }
static void rtl_rx_close(struct rtl8169_private *tp) @@@ -4568,13 -4691,13 +4693,13 @@@ static void rtl_set_rx_mode(struct net_
static void rtl_hw_start(struct rtl8169_private *tp) { - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp);
tp->hw_start(tp);
rtl_set_rx_max_size(tp); rtl_set_rx_tx_desc_registers(tp); - RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp);
/* Initially a 10 us delay. Turned it into a PCI commit. - FR */ RTL_R8(tp, IntrMask); @@@ -4698,18 -4821,10 +4823,10 @@@ static void rtl_enable_clock_request(st PCI_EXP_LNKCTL_CLKREQ_EN); }
- static void rtl_pcie_state_l2l3_enable(struct rtl8169_private *tp, bool enable) + static void rtl_pcie_state_l2l3_disable(struct rtl8169_private *tp) { - u8 data; - - data = RTL_R8(tp, Config3); - - if (enable) - data |= Rdy_to_L23; - else - data &= ~Rdy_to_L23; - - RTL_W8(tp, Config3, data); + /* work around an issue when PCI reset occurs during L2/L3 state */ + RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Rdy_to_L23); }
static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) @@@ -4967,6 -5082,8 +5084,8 @@@ static void rtl_hw_start_8168e_2(struc /* Adjust EEE LED frequency */ RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07);
+ rtl8168_config_eee_mac(tp); + RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN); RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN); RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~Spi_en); @@@ -4999,6 -5116,8 +5118,8 @@@ static void rtl_hw_start_8168f(struct r RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) | PFM_EN); RTL_W32(tp, MISC, RTL_R32(tp, MISC) | PWM_EN); RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~Spi_en); + + rtl8168_config_eee_mac(tp); }
static void rtl_hw_start_8168f_1(struct rtl8169_private *tp) @@@ -5030,7 -5149,7 +5151,7 @@@ static void rtl_hw_start_8411(struct rt };
rtl_hw_start_8168f(tp); - rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp);
rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
@@@ -5061,10 -5180,12 +5182,12 @@@ static void rtl_hw_start_8168g(struct r /* Adjust EEE LED frequency */ RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07);
+ rtl8168_config_eee_mac(tp); + rtl_w0w1_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC); rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp); }
static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) @@@ -5163,6 -5284,8 +5286,8 @@@ static void rtl_hw_start_8168h_1(struc /* Adjust EEE LED frequency */ RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07);
+ rtl8168_config_eee_mac(tp); + RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN);
@@@ -5170,7 -5293,7 +5295,7 @@@
rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp);
rtl_writephy(tp, 0x1f, 0x0c42); rg_saw_cnt = (rtl_readphy(tp, 0x13) & 0x3fff); @@@ -5243,11 -5366,13 +5368,13 @@@ static void rtl_hw_start_8168ep(struct /* Adjust EEE LED frequency */ RTL_W8(tp, EEE_LED, RTL_R8(tp, EEE_LED) & ~0x07);
+ rtl8168_config_eee_mac(tp); + rtl_w0w1_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC);
RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN);
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp); }
static void rtl_hw_start_8168ep_1(struct rtl8169_private *tp) @@@ -5518,7 -5643,7 +5645,7 @@@ static void rtl_hw_start_8105e_1(struc
rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp); }
static void rtl_hw_start_8105e_2(struct rtl8169_private *tp) @@@ -5553,7 -5678,7 +5680,7 @@@ static void rtl_hw_start_8402(struct rt rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp); }
static void rtl_hw_start_8106(struct rtl8169_private *tp) @@@ -5567,7 -5692,7 +5694,7 @@@ RTL_W8(tp, MCU, RTL_R8(tp, MCU) | EN_NDP | EN_OOB_RESET); RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN);
- rtl_pcie_state_l2l3_enable(tp, false); + rtl_pcie_state_l2l3_disable(tp); rtl_hw_aspm_clkreq_enable(tp, true); }
@@@ -5667,11 -5792,6 +5794,6 @@@ static inline void rtl8169_mark_to_asic desc->opts1 = cpu_to_le32(DescOwn | eor | R8169_RX_BUF_SIZE); }
- static inline void *rtl8169_align(void *data) - { - return (void *)ALIGN((long)data, 16); - } - static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp, struct RxDesc *desc) { @@@ -5684,15 -5804,13 +5806,13 @@@ if (!data) return NULL;
- if (rtl8169_align(data) != data) { - kfree(data); - data = kmalloc_node(R8169_RX_BUF_SIZE + 15, GFP_KERNEL, node); - if (!data) - return NULL; + /* Memory should be properly aligned, but better check. */ + if (!IS_ALIGNED((unsigned long)data, 8)) { + netdev_err_once(tp->dev, "RX buffer not 8-byte-aligned\n"); + goto err_out; }
- mapping = dma_map_single(d, rtl8169_align(data), R8169_RX_BUF_SIZE, - DMA_FROM_DEVICE); + mapping = dma_map_single(d, data, R8169_RX_BUF_SIZE, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(d, mapping))) { if (net_ratelimit()) netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n"); @@@ -6074,6 -6192,7 +6194,6 @@@ static netdev_tx_t rtl8169_start_xmit(s struct device *d = tp_to_dev(tp); dma_addr_t mapping; u32 opts[2], len; - bool stop_queue; int frags;
if (unlikely(!rtl_tx_slots_avail(tp, skb_shinfo(skb)->nr_frags))) { @@@ -6115,8 -6234,6 +6235,8 @@@
txd->opts2 = cpu_to_le32(opts[1]);
+ netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb);
/* Force memory writes to complete before releasing descriptor */ @@@ -6129,16 -6246,14 +6249,16 @@@
tp->cur_tx += frags + 1;
- stop_queue = !rtl_tx_slots_avail(tp, MAX_SKB_FRAGS); - if (unlikely(stop_queue)) - netif_stop_queue(dev); + RTL_W8(tp, TxPoll, NPQ);
- if (__netdev_sent_queue(dev, skb->len, skb->xmit_more)) - RTL_W8(tp, TxPoll, NPQ); + mmiowb();
- if (unlikely(stop_queue)) { + if (!rtl_tx_slots_avail(tp, MAX_SKB_FRAGS)) { + /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must + * not miss a ring update when it notices a stopped queue. + */ + smp_wmb(); + netif_stop_queue(dev); /* Sync with rtl_tx: * - publish queue status and cur_tx ring index (write barrier) * - refresh dirty_tx ring index (read barrier). @@@ -6198,16 -6313,6 +6318,6 @@@ static void rtl8169_pcierr_interrupt(st PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
- /* The infamous DAC f*ckup only happens at boot time */ - if ((tp->cp_cmd & PCIDAC) && !tp->cur_rx) { - netif_info(tp, intr, dev, "disabling PCI DAC\n"); - tp->cp_cmd &= ~PCIDAC; - RTL_W16(tp, CPlusCmd, tp->cp_cmd); - dev->features &= ~NETIF_F_HIGHDMA; - } - - rtl8169_hw_reset(tp); - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); }
@@@ -6303,7 -6408,6 +6413,6 @@@ static struct sk_buff *rtl8169_try_rx_c struct sk_buff *skb; struct device *d = tp_to_dev(tp);
- data = rtl8169_align(data); dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE); prefetch(data); skb = napi_alloc_skb(&tp->napi, pkt_size); @@@ -6414,7 -6518,7 +6523,7 @@@ release_descriptor static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) { struct rtl8169_private *tp = dev_instance; - u16 status = rtl_get_events(tp); + u16 status = RTL_R16(tp, IntrStatus); u16 irq_mask = RTL_R16(tp, IntrMask);
if (status == 0xffff || !(status & irq_mask)) @@@ -6425,8 -6529,8 +6534,8 @@@ goto out; }
- if (status & LinkChg && tp->dev->phydev) - phy_mac_interrupt(tp->dev->phydev); + if (status & LinkChg) + phy_mac_interrupt(tp->phydev);
if (unlikely(status & RxFIFOOver && tp->mac_version == RTL_GIGA_MAC_VER_11)) { @@@ -6488,9 -6592,7 +6597,9 @@@ static int rtl8169_poll(struct napi_str
if (work_done < budget) { napi_complete_done(napi, work_done); + rtl_irq_enable(tp); + mmiowb(); }
return work_done; @@@ -6519,12 -6621,12 +6628,12 @@@ static void r8169_phylink_handler(struc }
if (net_ratelimit()) - phy_print_status(ndev->phydev); + phy_print_status(tp->phydev); }
static int r8169_phy_connect(struct rtl8169_private *tp) { - struct phy_device *phydev = mdiobus_get_phy(tp->mii_bus, 0); + struct phy_device *phydev = tp->phydev; phy_interface_t phy_mode; int ret;
@@@ -6551,7 -6653,7 +6660,7 @@@ static void rtl8169_down(struct net_dev { struct rtl8169_private *tp = netdev_priv(dev);
- phy_stop(dev->phydev); + phy_stop(tp->phydev);
napi_disable(&tp->napi); netif_stop_queue(dev); @@@ -6593,7 -6695,7 +6702,7 @@@ static int rtl8169_close(struct net_dev
cancel_work_sync(&tp->wk.work);
- phy_disconnect(dev->phydev); + phy_disconnect(tp->phydev);
pci_free_irq(pdev, 0, tp);
@@@ -6644,10 -6746,6 +6753,6 @@@ static int rtl_open(struct net_device * if (retval < 0) goto err_free_rx_1;
- INIT_WORK(&tp->wk.work, rtl_task); - - smp_mb(); - rtl_request_firmware(tp);
retval = pci_request_irq(pdev, 0, rtl8169_interrupt, NULL, tp, @@@ -6674,7 -6772,7 +6779,7 @@@ if (!rtl8169_init_counter_offsets(tp)) netif_warn(tp, hw, dev, "counter reset/update failed\n");
- phy_start(dev->phydev); + phy_start(tp->phydev); netif_start_queue(dev);
rtl_unlock_work(tp); @@@ -6763,7 -6861,7 +6868,7 @@@ static void rtl8169_net_suspend(struct if (!netif_running(dev)) return;
- phy_stop(dev->phydev); + phy_stop(tp->phydev); netif_device_detach(dev);
rtl_lock_work(tp); @@@ -6798,14 -6896,13 +6903,13 @@@ static void __rtl8169_resume(struct net rtl_pll_power_up(tp); rtl8169_init_phy(dev, tp);
- phy_start(tp->dev->phydev); + phy_start(tp->phydev);
rtl_lock_work(tp); napi_enable(&tp->napi); set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + rtl_reset_work(tp); rtl_unlock_work(tp); - - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); }
static int rtl8169_resume(struct device *device) @@@ -6942,7 -7039,7 +7046,7 @@@ static void rtl_remove_one(struct pci_d netif_napi_del(&tp->napi);
unregister_netdev(dev); - mdiobus_unregister(tp->mii_bus); + mdiobus_unregister(tp->phydev->mdio.bus);
rtl_release_firmware(tp);
@@@ -7002,9 -7099,9 +7106,9 @@@ static int rtl_alloc_irq(struct rtl8169 unsigned int flags;
if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); + rtl_unlock_config_regs(tp); RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable); - RTL_W8(tp, Cfg9346, Cfg9346_Lock); + rtl_lock_config_regs(tp); flags = PCI_IRQ_LEGACY; } else { flags = PCI_IRQ_ALL_TYPES; @@@ -7013,6 -7110,30 +7117,30 @@@ return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags); }
+ static void rtl_read_mac_address(struct rtl8169_private *tp, + u8 mac_addr[ETH_ALEN]) + { + u32 value; + + /* Get MAC address */ + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + value = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); + mac_addr[0] = (value >> 0) & 0xff; + mac_addr[1] = (value >> 8) & 0xff; + mac_addr[2] = (value >> 16) & 0xff; + mac_addr[3] = (value >> 24) & 0xff; + + value = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); + mac_addr[4] = (value >> 0) & 0xff; + mac_addr[5] = (value >> 8) & 0xff; + break; + default: + break; + } + } + DECLARE_RTL_COND(rtl_link_list_ready_cond) { return RTL_R8(tp, MCU) & LINK_LIST_RDY; @@@ -7049,7 -7170,6 +7177,6 @@@ static int r8169_mdio_write_reg(struct static int r8169_mdio_register(struct rtl8169_private *tp) { struct pci_dev *pdev = tp->pci_dev; - struct phy_device *phydev; struct mii_bus *new_bus; int ret;
@@@ -7071,16 -7191,14 +7198,14 @@@ if (ret) return ret;
- phydev = mdiobus_get_phy(new_bus, 0); - if (!phydev) { + tp->phydev = mdiobus_get_phy(new_bus, 0); + if (!tp->phydev) { mdiobus_unregister(new_bus); return -ENODEV; }
/* PHY will be woken up in rtl_open() */ - phy_suspend(phydev); - - tp->mii_bus = new_bus; + phy_suspend(tp->phydev);
return 0; } @@@ -7178,9 -7296,37 +7303,37 @@@ static void rtl_disable_clk(void *data clk_disable_unprepare(data); }
+ static int rtl_get_ether_clk(struct rtl8169_private *tp) + { + struct device *d = tp_to_dev(tp); + struct clk *clk; + int rc; + + clk = devm_clk_get(d, "ether_clk"); + if (IS_ERR(clk)) { + rc = PTR_ERR(clk); + if (rc == -ENOENT) + /* clk-core allows NULL (for suspend / resume) */ + rc = 0; + else if (rc != -EPROBE_DEFER) + dev_err(d, "failed to get clk: %d\n", rc); + } else { + tp->clk = clk; + rc = clk_prepare_enable(clk); + if (rc) + dev_err(d, "failed to enable clk: %d\n", rc); + else + rc = devm_add_action_or_reset(d, rtl_disable_clk, clk); + } + + return rc; + } + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; + /* align to u16 for is_valid_ether_addr() */ + u8 mac_addr[ETH_ALEN] __aligned(2) = {}; struct rtl8169_private *tp; struct net_device *dev; int chipset, region, i; @@@ -7199,30 -7345,9 +7352,9 @@@ tp->supports_gmii = cfg->has_gmii;
/* Get the *optional* external "ether_clk" used on some boards */ - tp->clk = devm_clk_get(&pdev->dev, "ether_clk"); - if (IS_ERR(tp->clk)) { - rc = PTR_ERR(tp->clk); - if (rc == -ENOENT) { - /* clk-core allows NULL (for suspend / resume) */ - tp->clk = NULL; - } else if (rc == -EPROBE_DEFER) { - return rc; - } else { - dev_err(&pdev->dev, "failed to get clk: %d\n", rc); - return rc; - } - } else { - rc = clk_prepare_enable(tp->clk); - if (rc) { - dev_err(&pdev->dev, "failed to enable clk: %d\n", rc); - return rc; - } - - rc = devm_add_action_or_reset(&pdev->dev, rtl_disable_clk, - tp->clk); - if (rc) - return rc; - } + rc = rtl_get_ether_clk(tp); + if (rc) + return rc;
/* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pcim_enable_device(pdev); @@@ -7267,13 -7392,8 +7399,8 @@@
tp->cp_cmd = RTL_R16(tp, CPlusCmd);
- if (sizeof(dma_addr_t) > 4 && (use_dac == 1 || (use_dac == -1 && - tp->mac_version >= RTL_GIGA_MAC_VER_18)) && + if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 && !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { - - /* CPlusCmd Dual Access Cycle is only needed for non-PCIe */ - if (!pci_is_pcie(pdev)) - tp->cp_cmd |= PCIDAC; dev->features |= NETIF_F_HIGHDMA; } else { rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); @@@ -7304,26 -7424,19 +7431,19 @@@ return rc; }
- tp->saved_wolopts = __rtl8169_get_wol(tp); - mutex_init(&tp->wk.mutex); + INIT_WORK(&tp->wk.work, rtl_task); u64_stats_init(&tp->rx_stats.syncp); u64_stats_init(&tp->tx_stats.syncp);
- /* Get MAC address */ - switch (tp->mac_version) { - u8 mac_addr[ETH_ALEN] __aligned(4); - case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38: - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: - *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); - *(u16 *)&mac_addr[4] = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); + /* get MAC address */ + rc = eth_platform_get_mac_address(&pdev->dev, mac_addr); + if (rc) + rtl_read_mac_address(tp, mac_addr); + + if (is_valid_ether_addr(mac_addr)) + rtl_rar_set(tp, mac_addr);
- if (is_valid_ether_addr(mac_addr)) - rtl_rar_set(tp, mac_addr); - break; - default: - break; - } for (i = 0; i < ETH_ALEN; i++) dev->dev_addr[i] = RTL_R8(tp, MAC0 + i);
@@@ -7372,7 -7485,7 +7492,7 @@@ tp->irq_mask = RTL_EVENT_NAPI | cfg->irq_mask; tp->coalesce_info = cfg->coalesce_info;
- tp->rtl_fw = RTL_FIRMWARE_UNKNOWN; + tp->fw_name = rtl_chip_infos[chipset].fw_name;
tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), &tp->counters_phys_addr, @@@ -7413,7 -7526,7 +7533,7 @@@ return 0;
err_mdio_unregister: - mdiobus_unregister(tp->mii_bus); + mdiobus_unregister(tp->phydev->mdio.bus); return rc; }
diff --combined drivers/net/ethernet/sfc/ef10.c index c08034154a9a,bc92d73047c6..e888b479c596 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@@ -6041,10 -6041,13 +6041,13 @@@ static const struct efx_ef10_nvram_type { NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 0, 3, "sfc_exp_rom_cfg" }, { NVRAM_PARTITION_TYPE_LICENSE, 0, 0, "sfc_license" }, { NVRAM_PARTITION_TYPE_PHY_MIN, 0xff, 0, "sfc_phy_fw" }, - /* MUM and SUC firmware share the same partition type */ { NVRAM_PARTITION_TYPE_MUM_FIRMWARE, 0, 0, "sfc_mumfw" }, { NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 0, 0, "sfc_uefi" }, - { NVRAM_PARTITION_TYPE_STATUS, 0, 0, "sfc_status" } + { NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS, 0, 0, "sfc_dynamic_cfg_dflt" }, + { NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS, 0, 0, "sfc_exp_rom_cfg_dflt" }, + { NVRAM_PARTITION_TYPE_STATUS, 0, 0, "sfc_status" }, + { NVRAM_PARTITION_TYPE_BUNDLE, 0, 0, "sfc_bundle" }, + { NVRAM_PARTITION_TYPE_BUNDLE_METADATA, 0, 0, "sfc_bundle_metadata" }, }; #define EF10_NVRAM_PARTITION_COUNT ARRAY_SIZE(efx_ef10_nvram_types)
@@@ -6074,8 -6077,15 +6077,15 @@@ static int efx_ef10_mtd_probe_partition rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); if (rc) return rc; + if (protected && + (type != NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS && + type != NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS)) + /* Hide protected partitions that don't provide defaults. */ + return -ENODEV; + if (protected) - return -ENODEV; /* hide it */ + /* Protected partitions are read only. */ + erase_size = 0;
/* If we've already exposed a partition of this type, hide this * duplicate. All operations on MTDs are keyed by the type anyway, @@@ -6115,7 -6125,7 +6125,7 @@@ static int efx_ef10_mtd_probe(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX); - DECLARE_BITMAP(found, EF10_NVRAM_PARTITION_COUNT); + DECLARE_BITMAP(found, EF10_NVRAM_PARTITION_COUNT) = { 0 }; struct efx_mcdi_mtd_partition *parts; size_t outlen, n_parts_total, i, n_parts; unsigned int type; diff --combined drivers/net/phy/phylink.c index 938803237d7f,33f66dcd369a..59d175a5ba54 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@@ -1,12 -1,9 +1,9 @@@ + // SPDX-License-Identifier: GPL-2.0 /* * phylink models the MAC to optional PHY connection, supporting * technologies such as SFP cages where the PHY is hot-pluggable. * * Copyright (C) 2015 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/ethtool.h> #include <linux/export.h> @@@ -305,6 -302,13 +302,13 @@@ static void phylink_mac_config(struct p pl->ops->mac_config(pl->netdev, pl->link_an_mode, state); }
+ static void phylink_mac_config_up(struct phylink *pl, + const struct phylink_link_state *state) + { + if (state->link) + phylink_mac_config(pl, state); + } + static void phylink_mac_an_restart(struct phylink *pl) { if (pl->link_config.an_enabled && @@@ -404,12 -408,12 +408,12 @@@ static void phylink_resolve(struct work case MLO_AN_PHY: link_state = pl->phy_state; phylink_resolve_flow(pl, &link_state); - phylink_mac_config(pl, &link_state); + phylink_mac_config_up(pl, &link_state); break;
case MLO_AN_FIXED: phylink_get_fixed_state(pl, &link_state); - phylink_mac_config(pl, &link_state); + phylink_mac_config_up(pl, &link_state); break;
case MLO_AN_INBAND: @@@ -474,17 -478,6 +478,17 @@@ static void phylink_run_resolve(struct queue_work(system_power_efficient_wq, &pl->resolve); }
+static void phylink_run_resolve_and_disable(struct phylink *pl, int bit) +{ + unsigned long state = pl->phylink_disable_state; + + set_bit(bit, &pl->phylink_disable_state); + if (state == 0) { + queue_work(system_power_efficient_wq, &pl->resolve); + flush_work(&pl->resolve); + } +} + static void phylink_fixed_poll(struct timer_list *t) { struct phylink *pl = container_of(t, struct phylink, link_poll); @@@ -690,9 -683,8 +694,8 @@@ static int phylink_bringup_phy(struct p __ETHTOOL_LINK_MODE_MASK_NBITS, pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS, phy->advertising);
- phy_start_machine(phy); - if (phy->irq > 0) - phy_start_interrupts(phy); + if (phy_interrupt_is_valid(phy)) + phy_request_interrupt(phy);
return 0; } @@@ -935,7 -927,9 +938,7 @@@ void phylink_stop(struct phylink *pl if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio)) del_timer_sync(&pl->link_poll);
- set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); - queue_work(system_power_efficient_wq, &pl->resolve); - flush_work(&pl->resolve); + phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED); } EXPORT_SYMBOL_GPL(phylink_stop);
@@@ -1278,6 -1272,24 +1281,24 @@@ int phylink_get_eee_err(struct phylink EXPORT_SYMBOL_GPL(phylink_get_eee_err);
/** + * phylink_init_eee() - init and check the EEE features + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @clk_stop_enable: allow PHY to stop receive clock + * + * Must be called either with RTNL held or within mac_link_up() + */ + int phylink_init_eee(struct phylink *pl, bool clk_stop_enable) + { + int ret = -EOPNOTSUPP; + + if (pl->phydev) + ret = phy_init_eee(pl->phydev, clk_stop_enable); + + return ret; + } + EXPORT_SYMBOL_GPL(phylink_init_eee); + + /** * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters * @pl: a pointer to a &struct phylink returned from phylink_create() * @eee: a pointer to a &struct ethtool_eee for the read parameters @@@ -1641,7 -1653,9 +1662,7 @@@ static void phylink_sfp_link_down(void
ASSERT_RTNL();
- set_bit(PHYLINK_DISABLE_LINK, &pl->phylink_disable_state); - queue_work(system_power_efficient_wq, &pl->resolve); - flush_work(&pl->resolve); + phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_LINK); }
static void phylink_sfp_link_up(void *upstream) @@@ -1704,4 -1718,4 +1725,4 @@@ void phylink_helper_basex_speed(struct } EXPORT_SYMBOL_GPL(phylink_helper_basex_speed);
- MODULE_LICENSE("GPL"); + MODULE_LICENSE("GPL v2"); diff --combined drivers/net/phy/sfp.c index 68c8fbf099f8,298ab7546929..d4635c2178d1 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@@ -1,3 -1,4 +1,4 @@@ + // SPDX-License-Identifier: GPL-2.0 #include <linux/ctype.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> @@@ -184,7 -185,6 +185,7 @@@ struct sfp
struct gpio_desc *gpio[GPIO_MAX];
+ bool attached; unsigned int state; struct delayed_work poll; struct delayed_work timeout; @@@ -1476,7 -1476,7 +1477,7 @@@ static void sfp_sm_event(struct sfp *sf */ switch (sfp->sm_mod_state) { default: - if (event == SFP_E_INSERT) { + if (event == SFP_E_INSERT && sfp->attached) { sfp_module_tx_disable(sfp); sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT); } @@@ -1608,19 -1608,6 +1609,19 @@@ mutex_unlock(&sfp->sm_mutex); }
+static void sfp_attach(struct sfp *sfp) +{ + sfp->attached = true; + if (sfp->state & SFP_F_PRESENT) + sfp_sm_event(sfp, SFP_E_INSERT); +} + +static void sfp_detach(struct sfp *sfp) +{ + sfp->attached = false; + sfp_sm_event(sfp, SFP_E_REMOVE); +} + static void sfp_start(struct sfp *sfp) { sfp_sm_event(sfp, SFP_E_DEV_UP); @@@ -1681,8 -1668,6 +1682,8 @@@ static int sfp_module_eeprom(struct sf }
static const struct sfp_socket_ops sfp_module_ops = { + .attach = sfp_attach, + .detach = sfp_detach, .start = sfp_start, .stop = sfp_stop, .module_info = sfp_module_info, @@@ -1850,6 -1835,10 +1851,6 @@@ static int sfp_probe(struct platform_de dev_info(sfp->dev, "Host maximum power %u.%uW\n", sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
- sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); - if (!sfp->sfp_bus) - return -ENOMEM; - /* Get the initial state, and always signal TX disable, * since the network interface will not be up. */ @@@ -1860,6 -1849,10 +1861,6 @@@ sfp->state |= SFP_F_RATE_SELECT; sfp_set_state(sfp, sfp->state); sfp_module_tx_disable(sfp); - rtnl_lock(); - if (sfp->state & SFP_F_PRESENT) - sfp_sm_event(sfp, SFP_E_INSERT); - rtnl_unlock();
for (i = 0; i < GPIO_MAX; i++) { if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) @@@ -1892,10 -1885,6 +1893,10 @@@ dev_warn(sfp->dev, "No tx_disable pin: SFP modules will always be emitting.\n");
+ sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); + if (!sfp->sfp_bus) + return -ENOMEM; + return 0; }
diff --combined drivers/net/vxlan.c index 2aae11feff0c,c0cd1c022e77..33edc78e818d --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@@ -361,10 -361,11 +361,11 @@@ errout static void vxlan_fdb_switchdev_notifier_info(const struct vxlan_dev *vxlan, const struct vxlan_fdb *fdb, const struct vxlan_rdst *rd, + struct netlink_ext_ack *extack, struct switchdev_notifier_vxlan_fdb_info *fdb_info) { fdb_info->info.dev = vxlan->dev; - fdb_info->info.extack = NULL; + fdb_info->info.extack = extack; fdb_info->remote_ip = rd->remote_ip; fdb_info->remote_port = rd->remote_port; fdb_info->remote_vni = rd->remote_vni; @@@ -375,41 -376,50 +376,50 @@@ fdb_info->added_by_user = fdb->flags & NTF_VXLAN_ADDED_BY_USER; }
- static void vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, - struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, - bool adding) + static int vxlan_fdb_switchdev_call_notifiers(struct vxlan_dev *vxlan, + struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, + bool adding, + struct netlink_ext_ack *extack) { struct switchdev_notifier_vxlan_fdb_info info; enum switchdev_notifier_type notifier_type; + int ret;
if (WARN_ON(!rd)) - return; + return 0;
notifier_type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE : SWITCHDEV_VXLAN_FDB_DEL_TO_DEVICE; - vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, &info); - call_switchdev_notifiers(notifier_type, vxlan->dev, - &info.info); + vxlan_fdb_switchdev_notifier_info(vxlan, fdb, rd, NULL, &info); + ret = call_switchdev_notifiers(notifier_type, vxlan->dev, + &info.info, extack); + return notifier_to_errno(ret); }
- static void vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, - struct vxlan_rdst *rd, int type, bool swdev_notify) + static int vxlan_fdb_notify(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb, + struct vxlan_rdst *rd, int type, bool swdev_notify, + struct netlink_ext_ack *extack) { + int err; + if (swdev_notify) { switch (type) { case RTM_NEWNEIGH: - vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, - true); + err = vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, + true, extack); + if (err) + return err; break; case RTM_DELNEIGH: vxlan_fdb_switchdev_call_notifiers(vxlan, fdb, rd, - false); + false, extack); break; } }
__vxlan_fdb_notify(vxlan, fdb, rd, type); + return 0; }
static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa) @@@ -423,7 -433,7 +433,7 @@@ .remote_vni = cpu_to_be32(VXLAN_N_VID), };
- vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true); + vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true, NULL); }
static void vxlan_fdb_miss(struct vxlan_dev *vxlan, const u8 eth_addr[ETH_ALEN]) @@@ -435,7 -445,7 +445,7 @@@
memcpy(f.eth_addr, eth_addr, ETH_ALEN);
- vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true); + vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH, true, NULL); }
/* Hash Ethernet address */ @@@ -545,7 -555,7 +555,7 @@@ int vxlan_fdb_find_uc(struct net_devic }
rdst = first_remote_rcu(f); - vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, fdb_info); + vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, NULL, fdb_info);
out: rcu_read_unlock(); @@@ -556,19 -566,21 +566,21 @@@ EXPORT_SYMBOL_GPL(vxlan_fdb_find_uc) static int vxlan_fdb_notify_one(struct notifier_block *nb, const struct vxlan_dev *vxlan, const struct vxlan_fdb *f, - const struct vxlan_rdst *rdst) + const struct vxlan_rdst *rdst, + struct netlink_ext_ack *extack) { struct switchdev_notifier_vxlan_fdb_info fdb_info; int rc;
- vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, &fdb_info); + vxlan_fdb_switchdev_notifier_info(vxlan, f, rdst, extack, &fdb_info); rc = nb->notifier_call(nb, SWITCHDEV_VXLAN_FDB_ADD_TO_DEVICE, &fdb_info); return notifier_to_errno(rc); }
int vxlan_fdb_replay(const struct net_device *dev, __be32 vni, - struct notifier_block *nb) + struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan; struct vxlan_rdst *rdst; @@@ -586,7 -598,8 +598,8 @@@ if (f->vni == vni) { list_for_each_entry(rdst, &f->remotes, list) { rc = vxlan_fdb_notify_one(nb, vxlan, - f, rdst); + f, rdst, + extack); if (rc) goto out; } @@@ -625,7 -638,7 +638,7 @@@ EXPORT_SYMBOL_GPL(vxlan_fdb_clear_offlo /* Replace destination of unicast mac */ static int vxlan_fdb_replace(struct vxlan_fdb *f, union vxlan_addr *ip, __be16 port, __be32 vni, - __u32 ifindex) + __u32 ifindex, struct vxlan_rdst *oldrd) { struct vxlan_rdst *rd;
@@@ -637,6 -650,7 +650,7 @@@ if (!rd) return 0;
+ *oldrd = *rd; dst_cache_reset(&rd->dst_cache); rd->remote_ip = *ip; rd->remote_port = port; @@@ -826,92 -840,6 +840,6 @@@ static int vxlan_fdb_create(struct vxla return 0; }
- /* Add new entry to forwarding table -- assumes lock held */ - static int vxlan_fdb_update(struct vxlan_dev *vxlan, - const u8 *mac, union vxlan_addr *ip, - __u16 state, __u16 flags, - __be16 port, __be32 src_vni, __be32 vni, - __u32 ifindex, __u16 ndm_flags, - bool swdev_notify) - { - __u16 fdb_flags = (ndm_flags & ~NTF_USE); - struct vxlan_rdst *rd = NULL; - struct vxlan_fdb *f; - int notify = 0; - int rc; - - f = __vxlan_find_mac(vxlan, mac, src_vni); - if (f) { - if (flags & NLM_F_EXCL) { - netdev_dbg(vxlan->dev, - "lost race to create %pM\n", mac); - return -EEXIST; - } - - /* Do not allow an externally learned entry to take over an - * entry added by the user. - */ - if (!(fdb_flags & NTF_EXT_LEARNED) || - !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { - if (f->state != state) { - f->state = state; - f->updated = jiffies; - notify = 1; - } - if (f->flags != fdb_flags) { - f->flags = fdb_flags; - f->updated = jiffies; - notify = 1; - } - } - - if ((flags & NLM_F_REPLACE)) { - /* Only change unicasts */ - if (!(is_multicast_ether_addr(f->eth_addr) || - is_zero_ether_addr(f->eth_addr))) { - notify |= vxlan_fdb_replace(f, ip, port, vni, - ifindex); - } else - return -EOPNOTSUPP; - } - if ((flags & NLM_F_APPEND) && - (is_multicast_ether_addr(f->eth_addr) || - is_zero_ether_addr(f->eth_addr))) { - rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); - - if (rc < 0) - return rc; - notify |= rc; - } - - if (ndm_flags & NTF_USE) - f->used = jiffies; - } else { - if (!(flags & NLM_F_CREATE)) - return -ENOENT; - - /* Disallow replace to add a multicast entry */ - if ((flags & NLM_F_REPLACE) && - (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) - return -EOPNOTSUPP; - - netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); - rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, - vni, ifindex, fdb_flags, &f); - if (rc < 0) - return rc; - notify = 1; - } - - if (notify) { - if (rd == NULL) - rd = first_remote_rtnl(f); - vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, swdev_notify); - } - - return 0; - } - static void vxlan_fdb_free(struct rcu_head *head) { struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu); @@@ -929,14 -857,13 +857,13 @@@ static void vxlan_fdb_destroy(struct vx { struct vxlan_rdst *rd;
- netdev_dbg(vxlan->dev, - "delete %pM\n", f->eth_addr); + netdev_dbg(vxlan->dev, "delete %pM\n", f->eth_addr);
--vxlan->addrcnt; if (do_notify) list_for_each_entry(rd, &f->remotes, list) vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, - swdev_notify); + swdev_notify, NULL);
hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, vxlan_fdb_free); @@@ -950,11 -877,157 +877,157 @@@ static void vxlan_dst_free(struct rcu_h kfree(rd); }
+ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan, + union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + struct vxlan_fdb *f, + bool swdev_notify, + struct netlink_ext_ack *extack) + { + __u16 fdb_flags = (ndm_flags & ~NTF_USE); + struct vxlan_rdst *rd = NULL; + struct vxlan_rdst oldrd; + int notify = 0; + int rc = 0; + int err; + + /* Do not allow an externally learned entry to take over an entry added + * by the user. + */ + if (!(fdb_flags & NTF_EXT_LEARNED) || + !(f->flags & NTF_VXLAN_ADDED_BY_USER)) { + if (f->state != state) { + f->state = state; + f->updated = jiffies; + notify = 1; + } + if (f->flags != fdb_flags) { + f->flags = fdb_flags; + f->updated = jiffies; + notify = 1; + } + } + + if ((flags & NLM_F_REPLACE)) { + /* Only change unicasts */ + if (!(is_multicast_ether_addr(f->eth_addr) || + is_zero_ether_addr(f->eth_addr))) { + rc = vxlan_fdb_replace(f, ip, port, vni, + ifindex, &oldrd); + notify |= rc; + } else { + return -EOPNOTSUPP; + } + } + if ((flags & NLM_F_APPEND) && + (is_multicast_ether_addr(f->eth_addr) || + is_zero_ether_addr(f->eth_addr))) { + rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd); + + if (rc < 0) + return rc; + notify |= rc; + } + + if (ndm_flags & NTF_USE) + f->used = jiffies; + + if (notify) { + if (rd == NULL) + rd = first_remote_rtnl(f); + + err = vxlan_fdb_notify(vxlan, f, rd, RTM_NEWNEIGH, + swdev_notify, extack); + if (err) + goto err_notify; + } + + return 0; + + err_notify: + if ((flags & NLM_F_REPLACE) && rc) + *rd = oldrd; + else if ((flags & NLM_F_APPEND) && rc) { + list_del_rcu(&rd->list); + call_rcu(&rd->rcu, vxlan_dst_free); + } + return err; + } + + static int vxlan_fdb_update_create(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 src_vni, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + bool swdev_notify, + struct netlink_ext_ack *extack) + { + __u16 fdb_flags = (ndm_flags & ~NTF_USE); + struct vxlan_fdb *f; + int rc; + + /* Disallow replace to add a multicast entry */ + if ((flags & NLM_F_REPLACE) && + (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac))) + return -EOPNOTSUPP; + + netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); + rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, + vni, ifindex, fdb_flags, &f); + if (rc < 0) + return rc; + + rc = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, + swdev_notify, extack); + if (rc) + goto err_notify; + + return 0; + + err_notify: + vxlan_fdb_destroy(vxlan, f, false, false); + return rc; + } + + /* Add new entry to forwarding table -- assumes lock held */ + static int vxlan_fdb_update(struct vxlan_dev *vxlan, + const u8 *mac, union vxlan_addr *ip, + __u16 state, __u16 flags, + __be16 port, __be32 src_vni, __be32 vni, + __u32 ifindex, __u16 ndm_flags, + bool swdev_notify, + struct netlink_ext_ack *extack) + { + struct vxlan_fdb *f; + + f = __vxlan_find_mac(vxlan, mac, src_vni); + if (f) { + if (flags & NLM_F_EXCL) { + netdev_dbg(vxlan->dev, + "lost race to create %pM\n", mac); + return -EEXIST; + } + + return vxlan_fdb_update_existing(vxlan, ip, state, flags, port, + vni, ifindex, ndm_flags, f, + swdev_notify, extack); + } else { + if (!(flags & NLM_F_CREATE)) + return -ENOENT; + + return vxlan_fdb_update_create(vxlan, mac, ip, state, flags, + port, src_vni, vni, ifindex, + ndm_flags, swdev_notify, extack); + } + } + static void vxlan_fdb_dst_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f, struct vxlan_rdst *rd, bool swdev_notify) { list_del_rcu(&rd->list); - vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, swdev_notify); + vxlan_fdb_notify(vxlan, f, rd, RTM_DELNEIGH, swdev_notify, NULL); call_rcu(&rd->rcu, vxlan_dst_free); }
@@@ -1025,7 -1098,8 +1098,8 @@@ static int vxlan_fdb_parse(struct nlatt /* Add static entry (via netlink) */ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 vid, u16 flags) + const unsigned char *addr, u16 vid, u16 flags, + struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); /* struct net *net = dev_net(vxlan->dev); */ @@@ -1055,7 -1129,7 +1129,7 @@@ err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags, port, src_vni, vni, ifindex, ndm->ndm_flags | NTF_VXLAN_ADDED_BY_USER, - true); + true, extack); spin_unlock_bh(&vxlan->hash_lock);
return err; @@@ -1223,7 -1297,7 +1297,7 @@@ static bool vxlan_snoop(struct net_devi
rdst->remote_ip = *src_ip; f->updated = jiffies; - vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true); + vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL); } else { /* learned new entry */ spin_lock(&vxlan->hash_lock); @@@ -1236,7 -1310,7 +1310,7 @@@ vxlan->cfg.dst_port, vni, vxlan->default_dst.remote_vni, - ifindex, NTF_SELF, true); + ifindex, NTF_SELF, true, NULL); spin_unlock(&vxlan->hash_lock); }
@@@ -2219,7 -2293,7 +2293,7 @@@ static void vxlan_encap_bypass(struct s struct pcpu_sw_netstats *tx_stats, *rx_stats; union vxlan_addr loopback; union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip; - struct net_device *dev = skb->dev; + struct net_device *dev; int len = skb->len;
tx_stats = this_cpu_ptr(src_vxlan->dev->tstats); @@@ -2239,15 -2313,9 +2313,15 @@@ #endif }
+ rcu_read_lock(); + dev = skb->dev; + if (unlikely(!(dev->flags & IFF_UP))) { + kfree_skb(skb); + goto drop; + } + if (dst_vxlan->cfg.flags & VXLAN_F_LEARN) - vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, 0, - vni); + vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
u64_stats_update_begin(&tx_stats->syncp); tx_stats->tx_packets++; @@@ -2260,10 -2328,8 +2334,10 @@@ rx_stats->rx_bytes += len; u64_stats_update_end(&rx_stats->syncp); } else { +drop: dev->stats.rx_dropped++; } + rcu_read_unlock(); }
static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, @@@ -3486,9 -3552,12 +3560,12 @@@ static int __vxlan_dev_create(struct ne goto errout;
/* notify default fdb entry */ - if (f) - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH, - true); + if (f) { + err = vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), + RTM_NEWNEIGH, true, extack); + if (err) + goto errout; + }
list_add(&vxlan->next, &vn->vxlan_list); return 0; @@@ -3735,8 -3804,7 +3812,7 @@@ static int vxlan_changelink(struct net_ { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; - unsigned long old_age_interval; - struct vxlan_rdst old_dst; + struct net_device *lowerdev; struct vxlan_config conf; int err;
@@@ -3745,46 -3813,43 +3821,43 @@@ if (err) return err;
- old_age_interval = vxlan->cfg.age_interval; - memcpy(&old_dst, dst, sizeof(struct vxlan_rdst)); - - err = vxlan_dev_configure(vxlan->net, dev, &conf, true, extack); + err = vxlan_config_validate(vxlan->net, &conf, &lowerdev, + vxlan, extack); if (err) return err;
- if (old_age_interval != vxlan->cfg.age_interval) - mod_timer(&vxlan->age_timer, jiffies); - /* handle default dst entry */ - if (!vxlan_addr_equal(&dst->remote_ip, &old_dst.remote_ip)) { + if (!vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip)) { spin_lock_bh(&vxlan->hash_lock); - if (!vxlan_addr_any(&old_dst.remote_ip)) - __vxlan_fdb_delete(vxlan, all_zeros_mac, - old_dst.remote_ip, - vxlan->cfg.dst_port, - old_dst.remote_vni, - old_dst.remote_vni, - old_dst.remote_ifindex, - true); - - if (!vxlan_addr_any(&dst->remote_ip)) { + if (!vxlan_addr_any(&conf.remote_ip)) { err = vxlan_fdb_update(vxlan, all_zeros_mac, - &dst->remote_ip, + &conf.remote_ip, NUD_REACHABLE | NUD_PERMANENT, NLM_F_APPEND | NLM_F_CREATE, vxlan->cfg.dst_port, - dst->remote_vni, - dst->remote_vni, - dst->remote_ifindex, - NTF_SELF, true); + conf.vni, conf.vni, + conf.remote_ifindex, + NTF_SELF, true, extack); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; } } + if (!vxlan_addr_any(&dst->remote_ip)) + __vxlan_fdb_delete(vxlan, all_zeros_mac, + dst->remote_ip, + vxlan->cfg.dst_port, + dst->remote_vni, + dst->remote_vni, + dst->remote_ifindex, + true); spin_unlock_bh(&vxlan->hash_lock); }
+ if (conf.age_interval != vxlan->cfg.age_interval) + mod_timer(&vxlan->age_timer, jiffies); + + vxlan_config_apply(dev, &conf, lowerdev, vxlan->net, true); return 0; }
@@@ -4059,8 -4124,11 +4132,11 @@@ vxlan_fdb_external_learn_add(struct net struct switchdev_notifier_vxlan_fdb_info *fdb_info) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct netlink_ext_ack *extack; int err;
+ extack = switchdev_notifier_info_to_extack(&fdb_info->info); + spin_lock_bh(&vxlan->hash_lock); err = vxlan_fdb_update(vxlan, fdb_info->eth_addr, &fdb_info->remote_ip, NUD_REACHABLE, @@@ -4070,7 -4138,7 +4146,7 @@@ fdb_info->remote_vni, fdb_info->remote_ifindex, NTF_USE | NTF_SELF | NTF_EXT_LEARNED, - false); + false, extack); spin_unlock_bh(&vxlan->hash_lock);
return err; diff --combined drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a5ea3ba495a4,f66e1b2f0980..3987adaaf2bd --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@@ -155,52 -155,42 +155,52 @@@ static const struct ieee80211_ops mt76x .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .set_rts_threshold = mt76x02_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, - .get_txpower = mt76x02_get_txpower, + .get_txpower = mt76_get_txpower, };
-static int mt76x0u_register_device(struct mt76x02_dev *dev) +static int mt76x0u_init_hardware(struct mt76x02_dev *dev) { - struct ieee80211_hw *hw = dev->mt76.hw; int err;
- err = mt76u_alloc_queues(&dev->mt76); - if (err < 0) - goto out_err; - - err = mt76u_mcu_init_rx(&dev->mt76); - if (err < 0) - goto out_err; - mt76x0_chip_onoff(dev, true, true); - if (!mt76x02_wait_for_mac(&dev->mt76)) { - err = -ETIMEDOUT; - goto out_err; - } + + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT;
err = mt76x0u_mcu_init(dev); if (err < 0) - goto out_err; + return err;
mt76x0_init_usb_dma(dev); err = mt76x0_init_hardware(dev); if (err < 0) - goto out_err; + return err;
mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); mt76_wr(dev, MT_TXOP_CTRL_CFG, FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
+ return 0; +} + +static int mt76x0u_register_device(struct mt76x02_dev *dev) +{ + struct ieee80211_hw *hw = dev->mt76.hw; + int err; + + err = mt76u_alloc_queues(&dev->mt76); + if (err < 0) + goto out_err; + + err = mt76u_mcu_init_rx(&dev->mt76); + if (err < 0) + goto out_err; + + err = mt76x0u_init_hardware(dev); + if (err < 0) + goto out_err; + err = mt76x0_register_device(dev); if (err < 0) goto out_err; @@@ -311,8 -301,6 +311,8 @@@ static int __maybe_unused mt76x0_suspen
mt76u_stop_queues(&dev->mt76); mt76x0u_mac_stop(dev); + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state); + mt76x0_chip_onoff(dev, false, false); usb_kill_urb(usb->mcu.res.urb);
return 0; @@@ -340,7 -328,7 +340,7 @@@ static int __maybe_unused mt76x0_resume tasklet_enable(&usb->rx_tasklet); tasklet_enable(&usb->tx_tasklet);
- ret = mt76x0_init_hardware(dev); + ret = mt76x0u_init_hardware(dev); if (ret) goto err;
diff --combined drivers/s390/net/qeth_core_main.c index e7f4652941cd,5ca934775c42..a8cdc0d73bae --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@@ -192,23 -192,6 +192,6 @@@ const char *qeth_get_cardname_short(str return "n/a"; }
- void qeth_set_recovery_task(struct qeth_card *card) - { - card->recovery_task = current; - } - EXPORT_SYMBOL_GPL(qeth_set_recovery_task); - - void qeth_clear_recovery_task(struct qeth_card *card) - { - card->recovery_task = NULL; - } - EXPORT_SYMBOL_GPL(qeth_clear_recovery_task); - - static bool qeth_is_recovery_task(const struct qeth_card *card) - { - return card->recovery_task == current; - } - void qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads, int clear_start_mask) { @@@ -235,15 -218,6 +218,6 @@@ int qeth_threads_running(struct qeth_ca } EXPORT_SYMBOL_GPL(qeth_threads_running);
- int qeth_wait_for_threads(struct qeth_card *card, unsigned long threads) - { - if (qeth_is_recovery_task(card)) - return 0; - return wait_event_interruptible(card->wait_q, - qeth_threads_running(card, threads) == 0); - } - EXPORT_SYMBOL_GPL(qeth_wait_for_threads); - void qeth_clear_working_pool_list(struct qeth_card *card) { struct qeth_buffer_pool_entry *pool_entry, *tmp; @@@ -592,6 -566,7 +566,7 @@@ static struct qeth_reply *qeth_alloc_re if (reply) { refcount_set(&reply->refcnt, 1); atomic_set(&reply->received, 0); + init_waitqueue_head(&reply->wait_q); } return reply; } @@@ -607,6 -582,26 +582,26 @@@ static void qeth_put_reply(struct qeth_ kfree(reply); }
+ static void qeth_enqueue_reply(struct qeth_card *card, struct qeth_reply *reply) + { + spin_lock_irq(&card->lock); + list_add_tail(&reply->list, &card->cmd_waiter_list); + spin_unlock_irq(&card->lock); + } + + static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply) + { + spin_lock_irq(&card->lock); + list_del(&reply->list); + spin_unlock_irq(&card->lock); + } + + static void qeth_notify_reply(struct qeth_reply *reply) + { + atomic_inc(&reply->received); + wake_up(&reply->wait_q); + } + static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, struct qeth_card *card) { @@@ -683,19 -678,15 +678,15 @@@ static struct qeth_ipa_cmd *qeth_check_
void qeth_clear_ipacmd_list(struct qeth_card *card) { - struct qeth_reply *reply, *r; + struct qeth_reply *reply; unsigned long flags;
QETH_CARD_TEXT(card, 4, "clipalst");
spin_lock_irqsave(&card->lock, flags); - list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { - qeth_get_reply(reply); + list_for_each_entry(reply, &card->cmd_waiter_list, list) { reply->rc = -EIO; - atomic_inc(&reply->received); - list_del_init(&reply->list); - wake_up(&reply->wait_q); - qeth_put_reply(reply); + qeth_notify_reply(reply); } spin_unlock_irqrestore(&card->lock, flags); } @@@ -752,7 -743,10 +743,10 @@@ void qeth_release_buffer(struct qeth_ch spin_lock_irqsave(&channel->iob_lock, flags); iob->state = BUF_STATE_FREE; iob->callback = qeth_send_control_data_cb; - iob->rc = 0; + if (iob->reply) { + qeth_put_reply(iob->reply); + iob->reply = NULL; + } spin_unlock_irqrestore(&channel->iob_lock, flags); wake_up(&channel->wait_q); } @@@ -765,6 -759,17 +759,17 @@@ static void qeth_release_buffer_cb(stru qeth_release_buffer(channel, iob); }
+ static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc) + { + struct qeth_reply *reply = iob->reply; + + if (reply) { + reply->rc = rc; + qeth_notify_reply(reply); + } + qeth_release_buffer(iob->channel, iob); + } + static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel) { struct qeth_cmd_buffer *buffer = NULL; @@@ -800,9 -805,9 +805,9 @@@ static void qeth_send_control_data_cb(s struct qeth_cmd_buffer *iob) { struct qeth_ipa_cmd *cmd = NULL; - struct qeth_reply *reply, *r; + struct qeth_reply *reply = NULL; + struct qeth_reply *r; unsigned long flags; - int keep_reply; int rc = 0;
QETH_CARD_TEXT(card, 4, "sndctlcb"); @@@ -834,44 -839,40 +839,40 @@@ goto out; }
+ /* match against pending cmd requests */ spin_lock_irqsave(&card->lock, flags); - list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { - if ((reply->seqno == QETH_IDX_COMMAND_SEQNO) || - ((cmd) && (reply->seqno == cmd->hdr.seqno))) { + list_for_each_entry(r, &card->cmd_waiter_list, list) { + if ((r->seqno == QETH_IDX_COMMAND_SEQNO) || + (cmd && (r->seqno == cmd->hdr.seqno))) { + reply = r; + /* take the object outside the lock */ qeth_get_reply(reply); - list_del_init(&reply->list); - spin_unlock_irqrestore(&card->lock, flags); - keep_reply = 0; - if (reply->callback != NULL) { - if (cmd) { - reply->offset = (__u16)((char *)cmd - - (char *)iob->data); - keep_reply = reply->callback(card, - reply, - (unsigned long)cmd); - } else - keep_reply = reply->callback(card, - reply, - (unsigned long)iob); - } - if (cmd) - reply->rc = (u16) cmd->hdr.return_code; - else if (iob->rc) - reply->rc = iob->rc; - if (keep_reply) { - spin_lock_irqsave(&card->lock, flags); - list_add_tail(&reply->list, - &card->cmd_waiter_list); - spin_unlock_irqrestore(&card->lock, flags); - } else { - atomic_inc(&reply->received); - wake_up(&reply->wait_q); - } - qeth_put_reply(reply); - goto out; + break; } } spin_unlock_irqrestore(&card->lock, flags); + + if (!reply) + goto out; + + if (!reply->callback) { + rc = 0; + } else { + if (cmd) { + reply->offset = (u16)((char *)cmd - (char *)iob->data); + rc = reply->callback(card, reply, (unsigned long)cmd); + } else { + rc = reply->callback(card, reply, (unsigned long)iob); + } + } + + if (rc <= 0) { + reply->rc = rc; + qeth_notify_reply(reply); + } + + qeth_put_reply(reply); + out: memcpy(&card->seqno.pdu_hdr_ack, QETH_PDU_HEADER_SEQ_NO(iob->data), @@@ -1002,9 -1003,8 +1003,8 @@@ static int qeth_get_problem(struct qeth return 0; }
- static long qeth_check_irb_error(struct qeth_card *card, - struct ccw_device *cdev, unsigned long intparm, - struct irb *irb) + static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev, + unsigned long intparm, struct irb *irb) { if (!IS_ERR(irb)) return 0; @@@ -1015,7 -1015,7 +1015,7 @@@ CCW_DEVID(cdev)); QETH_CARD_TEXT(card, 2, "ckirberr"); QETH_CARD_TEXT_(card, 2, " rc%d", -EIO); - break; + return -EIO; case -ETIMEDOUT: dev_warn(&cdev->dev, "A hardware operation timed out" " on the device\n"); @@@ -1027,14 -1027,14 +1027,14 @@@ wake_up(&card->wait_q); } } - break; + return -ETIMEDOUT; default: QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n", PTR_ERR(irb), CCW_DEVID(cdev)); QETH_CARD_TEXT(card, 2, "ckirberr"); QETH_CARD_TEXT(card, 2, " rc???"); + return PTR_ERR(irb); } - return PTR_ERR(irb); }
static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, @@@ -1069,10 -1069,11 +1069,11 @@@ if (qeth_intparm_is_iob(intparm)) iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
- if (qeth_check_irb_error(card, cdev, intparm, irb)) { + rc = qeth_check_irb_error(card, cdev, intparm, irb); + if (rc) { /* IO was terminated, free its resources. */ if (iob) - qeth_release_buffer(iob->channel, iob); + qeth_cancel_cmd(iob, rc); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); return; @@@ -1128,7 -1129,7 +1129,7 @@@ if (rc) { card->read_or_write_problem = 1; if (iob) - qeth_release_buffer(iob->channel, iob); + qeth_cancel_cmd(iob, rc); qeth_clear_ipacmd_list(card); qeth_schedule_recovery(card); goto out; @@@ -1290,7 -1291,6 +1291,6 @@@ static int qeth_setup_channel(struct qe channel->iob[cnt].state = BUF_STATE_FREE; channel->iob[cnt].channel = channel; channel->iob[cnt].callback = qeth_send_control_data_cb; - channel->iob[cnt].rc = 0; } if (cnt < QETH_CMD_BUFFER_NO) { qeth_clean_channel(channel); @@@ -1432,7 -1432,6 +1432,6 @@@ static void qeth_setup_card(struct qeth spin_lock_init(&card->thread_mask_lock); mutex_init(&card->conf_mutex); mutex_init(&card->discipline_mutex); - mutex_init(&card->vid_list_mutex); INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); INIT_LIST_HEAD(&card->cmd_waiter_list); init_waitqueue_head(&card->wait_q); @@@ -2018,7 -2017,7 +2017,7 @@@ void qeth_prepare_control_data(struct q card->seqno.pdu_hdr++; memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); - QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN); + QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN)); } EXPORT_SYMBOL_GPL(qeth_prepare_control_data);
@@@ -2035,24 -2034,22 +2034,22 @@@ * for the IPA commands. * @reply_param: private pointer passed to the callback * - * Returns the value of the `return_code' field of the response - * block returned from the hardware, or other error indication. - * Value of zero indicates successful execution of the command. - * * Callback function gets called one or more times, with cb_cmd * pointing to the response returned by the hardware. Callback - * function must return non-zero if more reply blocks are expected, - * and zero if the last or only reply block is received. Callback - * function can get the value of the reply_param pointer from the + * function must return + * > 0 if more reply blocks are expected, + * 0 if the last or only reply block is received, and + * < 0 on error. + * Callback function can get the value of the reply_param pointer from the * field 'param' of the structure qeth_reply. */
- int qeth_send_control_data(struct qeth_card *card, int len, - struct qeth_cmd_buffer *iob, - int (*reply_cb)(struct qeth_card *cb_card, - struct qeth_reply *cb_reply, - unsigned long cb_cmd), - void *reply_param) + static int qeth_send_control_data(struct qeth_card *card, int len, + struct qeth_cmd_buffer *iob, + int (*reply_cb)(struct qeth_card *cb_card, + struct qeth_reply *cb_reply, + unsigned long cb_cmd), + void *reply_param) { struct qeth_channel *channel = iob->channel; int rc; @@@ -2074,7 -2071,9 +2071,9 @@@ reply->callback = reply_cb; reply->param = reply_param;
- init_waitqueue_head(&reply->wait_q); + /* pairs with qeth_release_buffer(): */ + qeth_get_reply(reply); + iob->reply = reply;
while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ;
@@@ -2089,9 -2088,7 +2088,7 @@@ } qeth_prepare_control_data(card, len, iob);
- spin_lock_irq(&card->lock); - list_add_tail(&reply->list, &card->cmd_waiter_list); - spin_unlock_irq(&card->lock); + qeth_enqueue_reply(card, reply);
timeout = jiffies + event_timeout;
@@@ -2104,10 -2101,8 +2101,8 @@@ QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", CARD_DEVID(card), rc); QETH_CARD_TEXT_(card, 2, " err%d", rc); - spin_lock_irq(&card->lock); - list_del_init(&reply->list); + qeth_dequeue_reply(card, reply); qeth_put_reply(reply); - spin_unlock_irq(&card->lock); qeth_release_buffer(channel, iob); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); @@@ -2129,21 -2124,16 +2124,16 @@@ } }
+ qeth_dequeue_reply(card, reply); rc = reply->rc; qeth_put_reply(reply); return rc;
time_err: - reply->rc = -ETIME; - spin_lock_irq(&card->lock); - list_del_init(&reply->list); - spin_unlock_irq(&card->lock); - atomic_inc(&reply->received); - rc = reply->rc; + qeth_dequeue_reply(card, reply); qeth_put_reply(reply); - return rc; + return -ETIME; } - EXPORT_SYMBOL_GPL(qeth_send_control_data);
static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) @@@ -2348,9 -2338,8 +2338,8 @@@ static int qeth_ulp_setup_cb(struct qet QETH_DBF_TEXT(SETUP, 2, "olmlimit"); dev_err(&card->gdev->dev, "A connection could not be " "established because of an OLM limit\n"); - iob->rc = -EMLINK; + return -EMLINK; } - QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc); return 0; }
@@@ -2843,14 -2832,20 +2832,20 @@@ static void qeth_fill_ipacmd_header(str cmd->hdr.prot_version = prot; }
- void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob) + void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, + u16 cmd_length) { + u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length; u8 prot_type = qeth_mpc_select_prot_type(card);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2); memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); + memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &cmd_length, 2); + memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &cmd_length, 2); memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); + memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &cmd_length, 2); } EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd);
@@@ -2861,7 -2856,7 +2856,7 @@@ struct qeth_cmd_buffer *qeth_get_ipacmd
iob = qeth_get_buffer(&card->write); if (iob) { - qeth_prepare_ipa_cmd(card, iob); + qeth_prepare_ipa_cmd(card, iob, sizeof(struct qeth_ipa_cmd)); qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot); } else { dev_warn(&card->gdev->dev, @@@ -2874,6 -2869,14 +2869,14 @@@ } EXPORT_SYMBOL_GPL(qeth_get_ipacmd_buffer);
+ static int qeth_send_ipa_cmd_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) + { + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + + return (cmd->hdr.return_code) ? -EIO : 0; + } + /** * qeth_send_ipa_cmd() - send an IPA command * @@@ -2885,11 -2888,15 +2888,15 @@@ int qeth_send_ipa_cmd(struct qeth_card unsigned long), void *reply_param) { + u16 length; int rc;
QETH_CARD_TEXT(card, 4, "sendipa"); - rc = qeth_send_control_data(card, IPA_CMD_LENGTH, - iob, reply_cb, reply_param); + + if (reply_cb == NULL) + reply_cb = qeth_send_ipa_cmd_cb; + memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2); + rc = qeth_send_control_data(card, length, iob, reply_cb, reply_param); if (rc == -ETIME) { qeth_clear_ipacmd_list(card); qeth_schedule_recovery(card); @@@ -2898,9 -2905,19 +2905,19 @@@ } EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd);
+ static int qeth_send_startlan_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) + { + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + + if (cmd->hdr.return_code == IPA_RC_LAN_OFFLINE) + return -ENETDOWN; + + return (cmd->hdr.return_code) ? -EIO : 0; + } + static int qeth_send_startlan(struct qeth_card *card) { - int rc; struct qeth_cmd_buffer *iob;
QETH_DBF_TEXT(SETUP, 2, "strtlan"); @@@ -2908,8 -2925,7 +2925,7 @@@ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0); if (!iob) return -ENOMEM; - rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); - return rc; + return qeth_send_ipa_cmd(card, iob, qeth_send_startlan_cb, NULL); }
static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd) @@@ -2927,7 -2943,7 +2943,7 @@@ static int qeth_query_setadapterparms_c
QETH_CARD_TEXT(card, 3, "quyadpcb"); if (qeth_setadpparms_inspect_rc(cmd)) - return 0; + return -EIO;
if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) { card->info.link_type = @@@ -2982,19 -2998,18 +2998,18 @@@ static int qeth_query_ipassists_cb(stru cmd = (struct qeth_ipa_cmd *) data;
switch (cmd->hdr.return_code) { + case IPA_RC_SUCCESS: + break; case IPA_RC_NOTSUPP: case IPA_RC_L2_UNSUPPORTED_CMD: QETH_DBF_TEXT(SETUP, 2, "ipaunsup"); card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS; card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS; - return 0; + return -EOPNOTSUPP; default: - if (cmd->hdr.return_code) { - QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n", - CARD_DEVID(card), - cmd->hdr.return_code); - return 0; - } + QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n", + CARD_DEVID(card), cmd->hdr.return_code); + return -EIO; }
if (cmd->hdr.prot_version == QETH_PROT_IPV4) { @@@ -3032,7 -3047,7 +3047,7 @@@ static int qeth_query_switch_attributes
QETH_CARD_TEXT(card, 2, "qswiatcb"); if (qeth_setadpparms_inspect_rc(cmd)) - return 0; + return -EIO;
sw_info = (struct qeth_switch_info *)reply->param; attrs = &cmd->data.setadapterparms.data.query_switch_attributes; @@@ -3064,15 -3079,15 +3079,15 @@@ int qeth_query_switch_attributes(struc static int qeth_query_setdiagass_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct qeth_ipa_cmd *cmd; - __u16 rc; + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + u16 rc = cmd->hdr.return_code;
- cmd = (struct qeth_ipa_cmd *)data; - rc = cmd->hdr.return_code; - if (rc) + if (rc) { QETH_CARD_TEXT_(card, 2, "diagq:%x", rc); - else - card->info.diagass_support = cmd->data.diagass.ext; + return -EIO; + } + + card->info.diagass_support = cmd->data.diagass.ext; return 0; }
@@@ -3119,13 -3134,13 +3134,13 @@@ static void qeth_get_trap_id(struct qet static int qeth_hw_trap_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct qeth_ipa_cmd *cmd; - __u16 rc; + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + u16 rc = cmd->hdr.return_code;
- cmd = (struct qeth_ipa_cmd *)data; - rc = cmd->hdr.return_code; - if (rc) + if (rc) { QETH_CARD_TEXT_(card, 2, "trapc:%x", rc); + return -EIO; + } return 0; }
@@@ -3566,8 -3581,6 +3581,6 @@@ static void qeth_qdio_cq_handler(struc card->qdio.c_q->next_buf_to_init = (card->qdio.c_q->next_buf_to_init + count) % QDIO_MAX_BUFFERS_PER_Q;
- netif_wake_queue(card->dev); - if (card->options.performance_stats) { int delta_t = qeth_get_micros(); delta_t -= card->perf_stats.cq_start_time; @@@ -3936,7 -3949,6 +3949,6 @@@ static int qeth_fill_buffer(struct qeth { struct qdio_buffer *buffer = buf->buffer; bool is_first_elem = true; - int flush_cnt = 0;
__skb_queue_tail(&buf->skb_list, skb);
@@@ -3957,24 -3969,22 +3969,22 @@@
if (!queue->do_pack) { QETH_CARD_TEXT(queue->card, 6, "fillbfnp"); - /* set state to PRIMED -> will be flushed */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - flush_cnt = 1; } else { QETH_CARD_TEXT(queue->card, 6, "fillbfpa"); if (queue->card->options.performance_stats) queue->card->perf_stats.skbs_sent_pack++; - if (buf->next_element_to_fill >= - QETH_MAX_BUFFER_ELEMENTS(queue->card)) { - /* - * packed buffer if full -> set state PRIMED - * -> will be flushed - */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - flush_cnt = 1; - } + + /* If the buffer still has free elements, keep using it. */ + if (buf->next_element_to_fill < + QETH_MAX_BUFFER_ELEMENTS(queue->card)) + return 0; } - return flush_cnt; + + /* flush out the buffer */ + atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); + queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % + QDIO_MAX_BUFFERS_PER_Q; + return 1; }
static int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, @@@ -3990,7 -4000,6 +4000,6 @@@ */ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) return -EBUSY; - queue->next_buf_to_fill = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); qeth_flush_buffers(queue, index, 1); return 0; @@@ -4048,10 -4057,9 +4057,9 @@@ int qeth_do_send_packet(struct qeth_car } } } - tmp = qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); - queue->next_buf_to_fill = (queue->next_buf_to_fill + tmp) % - QDIO_MAX_BUFFERS_PER_Q; - flush_count += tmp; + + flush_count += qeth_fill_buffer(queue, buffer, skb, hdr, offset, + hd_len); if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); else if (!atomic_read(&queue->set_pci_flags_count)) @@@ -4191,7 -4199,7 +4199,7 @@@ static int qeth_setadp_promisc_mode_cb( setparms->data.mode = SET_PROMISC_MODE_OFF; } card->info.promisc_mode = setparms->data.mode; - return 0; + return (cmd->hdr.return_code) ? -EIO : 0; }
void qeth_setadp_promisc_mode(struct qeth_card *card) @@@ -4243,12 -4251,15 +4251,15 @@@ static int qeth_setadpparms_change_maca
QETH_CARD_TEXT(card, 4, "chgmaccb"); if (qeth_setadpparms_inspect_rc(cmd)) - return 0; + return -EIO;
adp_cmd = &cmd->data.setadapterparms; + if (!is_valid_ether_addr(adp_cmd->data.change_addr.addr)) + return -EADDRNOTAVAIL; + if (IS_LAYER2(card) && IS_OSD(card) && !IS_VM_NIC(card) && !(adp_cmd->hdr.flags & QETH_SETADP_FLAGS_VIRTUAL_MAC)) - return 0; + return -EADDRNOTAVAIL;
ether_addr_copy(card->dev->dev_addr, adp_cmd->data.change_addr.addr); return 0; @@@ -4287,7 -4298,7 +4298,7 @@@ static int qeth_setadpparms_set_access_
QETH_CARD_TEXT(card, 4, "setaccb"); if (cmd->hdr.return_code) - return 0; + return -EIO; qeth_setadpparms_inspect_rc(cmd);
access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; @@@ -4361,7 -4372,7 +4372,7 @@@ card->options.isolation = card->options.prev_isolation; break; } - return 0; + return (cmd->hdr.return_code) ? -EIO : 0; }
static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, @@@ -4495,27 -4506,6 +4506,6 @@@ static int qeth_mdio_read(struct net_de return rc; }
- static int qeth_send_ipa_snmp_cmd(struct qeth_card *card, - struct qeth_cmd_buffer *iob, int len, - int (*reply_cb)(struct qeth_card *, struct qeth_reply *, - unsigned long), - void *reply_param) - { - u16 s1, s2; - - QETH_CARD_TEXT(card, 4, "sendsnmp"); - - /* adjust PDU length fields in IPA_PDU_HEADER */ - s1 = (u32) IPA_PDU_HEADER_SIZE + len; - s2 = (u32) len; - memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); - memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); - memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); - memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); - return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob, - reply_cb, reply_param); - } - static int qeth_snmp_command_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long sdata) { @@@ -4533,13 -4523,13 +4523,13 @@@
if (cmd->hdr.return_code) { QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code); - return 0; + return -EIO; } if (cmd->data.setadapterparms.hdr.return_code) { cmd->hdr.return_code = cmd->data.setadapterparms.hdr.return_code; QETH_CARD_TEXT_(card, 4, "scer2%x", cmd->hdr.return_code); - return 0; + return -EIO; } data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data)); if (cmd->data.setadapterparms.hdr.seq_no == 1) { @@@ -4554,9 -4544,8 +4544,8 @@@
/* check if there is enough room in userspace */ if ((qinfo->udata_len - qinfo->udata_offset) < data_len) { - QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM); - cmd->hdr.return_code = IPA_RC_ENOMEM; - return 0; + QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOSPC); + return -ENOSPC; } QETH_CARD_TEXT_(card, 4, "snore%i", cmd->data.setadapterparms.hdr.used_total); @@@ -4621,10 -4610,13 +4610,13 @@@ static int qeth_snmp_command(struct qet rc = -ENOMEM; goto out; } + + /* for large requests, fix-up the length fields: */ + qeth_prepare_ipa_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len); + cmd = __ipa_cmd(iob); memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len); - rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, - qeth_snmp_command_cb, (void *)&qinfo); + rc = qeth_send_ipa_cmd(card, iob, qeth_snmp_command_cb, &qinfo); if (rc) QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n", CARD_DEVID(card), rc); @@@ -4648,16 -4640,14 +4640,14 @@@ static int qeth_setadpparms_query_oat_c
QETH_CARD_TEXT(card, 3, "qoatcb"); if (qeth_setadpparms_inspect_rc(cmd)) - return 0; + return -EIO;
priv = (struct qeth_qoat_priv *)reply->param; resdatalen = cmd->data.setadapterparms.hdr.cmdlength; resdata = (char *)data + 28;
- if (resdatalen > (priv->buffer_len - priv->response_len)) { - cmd->hdr.return_code = IPA_RC_FFFF; - return 0; - } + if (resdatalen > (priv->buffer_len - priv->response_len)) + return -ENOSPC;
memcpy((priv->buffer + priv->response_len), resdata, resdatalen); @@@ -4730,9 -4720,7 +4720,7 @@@ static int qeth_query_oat_command(struc if (copy_to_user(udata, &oat_data, sizeof(struct qeth_query_oat_data))) rc = -EFAULT; - } else - if (rc == IPA_RC_FFFF) - rc = -EFAULT; + }
out_free: vfree(priv.buffer); @@@ -4749,7 -4737,7 +4737,7 @@@ static int qeth_query_card_info_cb(stru
QETH_CARD_TEXT(card, 2, "qcrdincb"); if (qeth_setadpparms_inspect_rc(cmd)) - return 0; + return -EIO;
card_info = &cmd->data.setadapterparms.data.card_info; carrier_info->card_type = card_info->card_type; @@@ -4987,8 -4975,8 +4975,8 @@@ static int qeth_qdio_establish(struct q init_data.output_handler = qeth_qdio_output_handler; init_data.queue_start_poll_array = queue_start_poll; init_data.int_parm = (unsigned long) card; - init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; - init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; + init_data.input_sbal_addr_array = in_sbal_ptrs; + init_data.output_sbal_addr_array = out_sbal_ptrs; init_data.output_sbal_state_array = card->qdio.out_bufstates; init_data.scan_threshold = (card->info.type == QETH_CARD_TYPE_IQD) ? 1 : 32; @@@ -5151,25 -5139,16 +5139,16 @@@ retriable rc = qeth_send_startlan(card); if (rc) { QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); - if (rc == IPA_RC_LAN_OFFLINE) { - dev_warn(&card->gdev->dev, - "The LAN is offline\n"); + if (rc == -ENETDOWN) { + dev_warn(&card->gdev->dev, "The LAN is offline\n"); *carrier_ok = false; } else { - rc = -ENODEV; goto out; } } else { *carrier_ok = true; }
- if (qeth_netdev_is_registered(card->dev)) { - if (*carrier_ok) - netif_carrier_on(card->dev); - else - netif_carrier_off(card->dev); - } - card->options.ipa4.supported_funcs = 0; card->options.ipa6.supported_funcs = 0; card->options.adp.supported_funcs = 0; @@@ -5433,7 -5412,7 +5412,7 @@@ static int qeth_setassparms_get_caps_cb struct qeth_ipa_caps *caps = reply->param;
if (qeth_setassparms_inspect_rc(cmd)) - return 0; + return -EIO;
caps->supported = cmd->data.setassparms.data.caps.supported; caps->enabled = cmd->data.setassparms.data.caps.enabled; @@@ -5443,18 -5422,18 +5422,18 @@@ int qeth_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct qeth_ipa_cmd *cmd; + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
QETH_CARD_TEXT(card, 4, "defadpcb");
- cmd = (struct qeth_ipa_cmd *) data; - if (cmd->hdr.return_code == 0) { - cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; - if (cmd->hdr.prot_version == QETH_PROT_IPV4) - card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; - if (cmd->hdr.prot_version == QETH_PROT_IPV6) - card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; - } + if (cmd->hdr.return_code) + return -EIO; + + cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; + if (cmd->hdr.prot_version == QETH_PROT_IPV4) + card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; + if (cmd->hdr.prot_version == QETH_PROT_IPV6) + card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; return 0; } EXPORT_SYMBOL_GPL(qeth_setassparms_cb); @@@ -5946,9 -5925,6 +5925,6 @@@ int qeth_do_ioctl(struct net_device *de if (!card) return -ENODEV;
- if (!qeth_card_hw_is_reachable(card)) - return -ENODEV; - if (card->info.type == QETH_CARD_TYPE_OSN) return -EPERM;
@@@ -6259,8 -6235,6 +6235,6 @@@ int qeth_core_ethtool_get_link_ksetting /* Check if we can obtain more accurate information. */ /* If QUERY_CARD_INFO command is not supported or fails, */ /* just return the heuristics that was filled above. */ - if (!qeth_card_hw_is_reachable(card)) - return -ENODEV; rc = qeth_query_card_info(card, &carrier_info); if (rc == -EOPNOTSUPP) /* for old hardware, return heuristic */ return 0; @@@ -6325,120 -6299,91 +6299,91 @@@ } EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_link_ksettings);
- /* Callback to handle checksum offload command reply from OSA card. - * Verify that required features have been enabled on the card. - * Return error in hdr->return_code as this value is checked by caller. - * - * Always returns zero to indicate no further messages from the OSA card. - */ - static int qeth_ipa_checksum_run_cmd_cb(struct qeth_card *card, - struct qeth_reply *reply, - unsigned long data) + static int qeth_start_csum_cb(struct qeth_card *card, struct qeth_reply *reply, + unsigned long data) { struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; - struct qeth_checksum_cmd *chksum_cb = - (struct qeth_checksum_cmd *)reply->param; + u32 *features = reply->param;
- QETH_CARD_TEXT(card, 4, "chkdoccb"); if (qeth_setassparms_inspect_rc(cmd)) - return 0; + return -EIO;
- memset(chksum_cb, 0, sizeof(*chksum_cb)); - if (cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) { - chksum_cb->supported = - cmd->data.setassparms.data.chksum.supported; - QETH_CARD_TEXT_(card, 3, "strt:%x", chksum_cb->supported); - } - if (cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_ENABLE) { - chksum_cb->supported = - cmd->data.setassparms.data.chksum.supported; - chksum_cb->enabled = - cmd->data.setassparms.data.chksum.enabled; - QETH_CARD_TEXT_(card, 3, "supp:%x", chksum_cb->supported); - QETH_CARD_TEXT_(card, 3, "enab:%x", chksum_cb->enabled); - } + *features = cmd->data.setassparms.data.flags_32bit; return 0; }
- /* Send command to OSA card and check results. */ - static int qeth_ipa_checksum_run_cmd(struct qeth_card *card, - enum qeth_ipa_funcs ipa_func, - __u16 cmd_code, long data, - struct qeth_checksum_cmd *chksum_cb, - enum qeth_prot_versions prot) + static int qeth_set_csum_off(struct qeth_card *card, enum qeth_ipa_funcs cstype, + enum qeth_prot_versions prot) { - struct qeth_cmd_buffer *iob; - - QETH_CARD_TEXT(card, 4, "chkdocmd"); - iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code, - sizeof(__u32), prot); - if (!iob) - return -ENOMEM; - - __ipa_cmd(iob)->data.setassparms.data.flags_32bit = (__u32) data; - return qeth_send_ipa_cmd(card, iob, qeth_ipa_checksum_run_cmd_cb, - chksum_cb); + return qeth_send_simple_setassparms_prot(card, cstype, + IPA_CMD_ASS_STOP, 0, prot); }
- static int qeth_send_checksum_on(struct qeth_card *card, int cstype, - enum qeth_prot_versions prot) + static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype, + enum qeth_prot_versions prot) { u32 required_features = QETH_IPA_CHECKSUM_UDP | QETH_IPA_CHECKSUM_TCP; - struct qeth_checksum_cmd chksum_cb; + struct qeth_cmd_buffer *iob; + struct qeth_ipa_caps caps; + u32 features; int rc;
- if (prot == QETH_PROT_IPV4) + /* some L3 HW requires combined L3+L4 csum offload: */ + if (IS_LAYER3(card) && prot == QETH_PROT_IPV4 && + cstype == IPA_OUTBOUND_CHECKSUM) required_features |= QETH_IPA_CHECKSUM_IP_HDR; - rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_START, 0, - &chksum_cb, prot); - if (!rc) { - if ((required_features & chksum_cb.supported) != - required_features) - rc = -EIO; - else if (!(QETH_IPA_CHECKSUM_LP2LP & chksum_cb.supported) && - cstype == IPA_INBOUND_CHECKSUM) - dev_warn(&card->gdev->dev, - "Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n", - QETH_CARD_IFNAME(card)); - } - if (rc) { - qeth_send_simple_setassparms_prot(card, cstype, - IPA_CMD_ASS_STOP, 0, prot); - dev_warn(&card->gdev->dev, - "Starting HW IPv%d checksumming for %s failed, using SW checksumming\n", - prot, QETH_CARD_IFNAME(card)); + + iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_START, 0, + prot); + if (!iob) + return -ENOMEM; + + rc = qeth_send_ipa_cmd(card, iob, qeth_start_csum_cb, &features); + if (rc) return rc; + + if ((required_features & features) != required_features) { + qeth_set_csum_off(card, cstype, prot); + return -EOPNOTSUPP; } - rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_ENABLE, - chksum_cb.supported, &chksum_cb, + + iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_ENABLE, 4, prot); - if (!rc) { - if ((required_features & chksum_cb.enabled) != - required_features) - rc = -EIO; + if (!iob) { + qeth_set_csum_off(card, cstype, prot); + return -ENOMEM; } + + if (features & QETH_IPA_CHECKSUM_LP2LP) + required_features |= QETH_IPA_CHECKSUM_LP2LP; + __ipa_cmd(iob)->data.setassparms.data.flags_32bit = required_features; + rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_get_caps_cb, &caps); if (rc) { - qeth_send_simple_setassparms_prot(card, cstype, - IPA_CMD_ASS_STOP, 0, prot); - dev_warn(&card->gdev->dev, - "Enabling HW IPv%d checksumming for %s failed, using SW checksumming\n", - prot, QETH_CARD_IFNAME(card)); + qeth_set_csum_off(card, cstype, prot); return rc; }
+ if (!qeth_ipa_caps_supported(&caps, required_features) || + !qeth_ipa_caps_enabled(&caps, required_features)) { + qeth_set_csum_off(card, cstype, prot); + return -EOPNOTSUPP; + } + dev_info(&card->gdev->dev, "HW Checksumming (%sbound IPv%d) enabled\n", cstype == IPA_INBOUND_CHECKSUM ? "in" : "out", prot); + if (!qeth_ipa_caps_enabled(&caps, QETH_IPA_CHECKSUM_LP2LP) && + cstype == IPA_OUTBOUND_CHECKSUM) + dev_warn(&card->gdev->dev, + "Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n", + QETH_CARD_IFNAME(card)); return 0; }
static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype, enum qeth_prot_versions prot) { - int rc = (on) ? qeth_send_checksum_on(card, cstype, prot) - : qeth_send_simple_setassparms_prot(card, cstype, - IPA_CMD_ASS_STOP, 0, - prot); - return rc ? -EIO : 0; + return on ? qeth_set_csum_on(card, cstype, prot) : + qeth_set_csum_off(card, cstype, prot); }
static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply, @@@ -6448,7 -6393,7 +6393,7 @@@ struct qeth_tso_start_data *tso_data = reply->param;
if (qeth_setassparms_inspect_rc(cmd)) - return 0; + return -EIO;
tso_data->mss = cmd->data.setassparms.data.tso.mss; tso_data->supported = cmd->data.setassparms.data.tso.supported; @@@ -6514,10 -6459,7 +6459,7 @@@ static int qeth_set_tso_on(struct qeth_ static int qeth_set_ipa_tso(struct qeth_card *card, bool on, enum qeth_prot_versions prot) { - int rc = on ? qeth_set_tso_on(card, prot) : - qeth_set_tso_off(card, prot); - - return rc ? -EIO : 0; + return on ? qeth_set_tso_on(card, prot) : qeth_set_tso_off(card, prot); }
static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on) @@@ -6543,8 -6485,6 +6485,6 @@@ return (rc_ipv6) ? rc_ipv6 : rc_ipv4; }
- #define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO | \ - NETIF_F_IPV6_CSUM | NETIF_F_TSO6) /** * qeth_enable_hw_features() - (Re-)Enable HW functions for device features * @dev: a net_device @@@ -6554,17 -6494,20 +6494,20 @@@ void qeth_enable_hw_features(struct net struct qeth_card *card = dev->ml_priv; netdev_features_t features;
- rtnl_lock(); features = dev->features; - /* force-off any feature that needs an IPA sequence. + /* force-off any feature that might need an IPA sequence. * netdev_update_features() will restart them. */ - dev->features &= ~QETH_HW_FEATURES; + dev->features &= ~dev->hw_features; + /* toggle VLAN filter, so that VIDs are re-programmed: */ + if (IS_LAYER2(card) && IS_VM_NIC(card)) { + dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; + dev->wanted_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + } netdev_update_features(dev); if (features != dev->features) dev_warn(&card->gdev->dev, "Device recovery failed to restore all offload features\n"); - rtnl_unlock(); } EXPORT_SYMBOL_GPL(qeth_enable_hw_features);
@@@ -6633,10 -6576,7 +6576,7 @@@ netdev_features_t qeth_fix_features(str features &= ~NETIF_F_TSO; if (!qeth_is_supported6(card, IPA_OUTBOUND_TSO)) features &= ~NETIF_F_TSO6; - /* if the card isn't up, remove features that require hw changes */ - if (card->state == CARD_STATE_DOWN || - card->state == CARD_STATE_RECOVER) - features &= ~QETH_HW_FEATURES; + QETH_DBF_HEX(SETUP, 2, &features, sizeof(features)); return features; } @@@ -6668,6 -6608,46 +6608,46 @@@ netdev_features_t qeth_features_check(s } EXPORT_SYMBOL_GPL(qeth_features_check);
+ int qeth_open(struct net_device *dev) + { + struct qeth_card *card = dev->ml_priv; + + QETH_CARD_TEXT(card, 4, "qethopen"); + if (card->state == CARD_STATE_UP) + return 0; + if (card->state != CARD_STATE_SOFTSETUP) + return -ENODEV; + + if (qdio_stop_irq(CARD_DDEV(card), 0) < 0) + return -EIO; + + card->data.state = CH_STATE_UP; + card->state = CARD_STATE_UP; + netif_start_queue(dev); + + napi_enable(&card->napi); + local_bh_disable(); + napi_schedule(&card->napi); + /* kick-start the NAPI softirq: */ + local_bh_enable(); + return 0; + } + EXPORT_SYMBOL_GPL(qeth_open); + + int qeth_stop(struct net_device *dev) + { + struct qeth_card *card = dev->ml_priv; + + QETH_CARD_TEXT(card, 4, "qethstop"); + netif_tx_disable(dev); + if (card->state == CARD_STATE_UP) { + card->state = CARD_STATE_SOFTSETUP; + napi_disable(&card->napi); + } + return 0; + } + EXPORT_SYMBOL_GPL(qeth_stop); + static int __init qeth_core_init(void) { int rc; diff --combined include/linux/skbuff.h index 1debbcd22955,a41e84f7730c..0ff662bca6b4 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@@ -1221,6 -1221,11 +1221,11 @@@ static inline int skb_flow_dissector_bp } #endif
+ struct bpf_flow_keys; + bool __skb_flow_bpf_dissect(struct bpf_prog *prog, + const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + struct bpf_flow_keys *flow_keys); bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, @@@ -1884,12 -1889,12 +1889,12 @@@ static inline void __skb_queue_before(s * * A buffer cannot be placed on two lists at the same time. */ - void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); static inline void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk) { __skb_queue_after(list, (struct sk_buff *)list, newsk); } + void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk);
/** * __skb_queue_tail - queue a buffer at the list tail @@@ -1901,12 -1906,12 +1906,12 @@@ * * A buffer cannot be placed on two lists at the same time. */ - void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk); static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) { __skb_queue_before(list, (struct sk_buff *)list, newsk); } + void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk);
/* * remove sk_buff from list. _Must_ be called atomically, and with @@@ -1933,7 -1938,6 +1938,6 @@@ static inline void __skb_unlink(struct * so must be used with appropriate locks held only. The head item is * returned or %NULL if the list is empty. */ - struct sk_buff *skb_dequeue(struct sk_buff_head *list); static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list) { struct sk_buff *skb = skb_peek(list); @@@ -1941,6 -1945,7 +1945,7 @@@ __skb_unlink(skb, list); return skb; } + struct sk_buff *skb_dequeue(struct sk_buff_head *list);
/** * __skb_dequeue_tail - remove from the tail of the queue @@@ -1950,7 -1955,6 +1955,6 @@@ * so must be used with appropriate locks held only. The tail item is * returned or %NULL if the list is empty. */ - struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list); static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list) { struct sk_buff *skb = skb_peek_tail(list); @@@ -1958,6 -1962,7 +1962,7 @@@ __skb_unlink(skb, list); return skb; } + struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list);
static inline bool skb_is_nonlinear(const struct sk_buff *skb) @@@ -2648,13 -2653,13 +2653,13 @@@ static inline int skb_orphan_frags_rx(s * the list and one reference dropped. This function does not take the * list lock and the caller must hold the relevant locks to use it. */ - void skb_queue_purge(struct sk_buff_head *list); static inline void __skb_queue_purge(struct sk_buff_head *list) { struct sk_buff *skb; while ((skb = __skb_dequeue(list)) != NULL) kfree_skb(skb); } + void skb_queue_purge(struct sk_buff_head *list);
unsigned int skb_rbtree_purge(struct rb_root *root);
@@@ -3023,7 -3028,7 +3028,7 @@@ static inline int skb_padto(struct sk_b }
/** - * skb_put_padto - increase size and pad an skbuff up to a minimal size + * __skb_put_padto - increase size and pad an skbuff up to a minimal size * @skb: buffer to pad * @len: minimal length * @free_on_error: free buffer on error @@@ -3481,16 -3486,25 +3486,25 @@@ static inline ktime_t skb_get_ktime(con /** * skb_get_timestamp - get timestamp from a skb * @skb: skb to get stamp from - * @stamp: pointer to struct timeval to store stamp in + * @stamp: pointer to struct __kernel_old_timeval to store stamp in * * Timestamps are stored in the skb as offsets to a base timestamp. * This function converts the offset back to a struct timeval and stores * it in stamp. */ static inline void skb_get_timestamp(const struct sk_buff *skb, - struct timeval *stamp) + struct __kernel_old_timeval *stamp) { - *stamp = ktime_to_timeval(skb->tstamp); + *stamp = ns_to_kernel_old_timeval(skb->tstamp); + } + + static inline void skb_get_new_timestamp(const struct sk_buff *skb, + struct __kernel_sock_timeval *stamp) + { + struct timespec64 ts = ktime_to_timespec64(skb->tstamp); + + stamp->tv_sec = ts.tv_sec; + stamp->tv_usec = ts.tv_nsec / 1000; }
static inline void skb_get_timestampns(const struct sk_buff *skb, @@@ -3499,6 -3513,15 +3513,15 @@@ *stamp = ktime_to_timespec(skb->tstamp); }
+ static inline void skb_get_new_timestampns(const struct sk_buff *skb, + struct __kernel_timespec *stamp) + { + struct timespec64 ts = ktime_to_timespec64(skb->tstamp); + + stamp->tv_sec = ts.tv_sec; + stamp->tv_nsec = ts.tv_nsec; + } + static inline void __net_timestamp(struct sk_buff *skb) { skb->tstamp = ktime_get_real(); @@@ -4212,12 -4235,6 +4235,12 @@@ static inline bool skb_is_gso_sctp(cons return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP; }
+static inline bool skb_is_gso_tcp(const struct sk_buff *skb) +{ + return skb_is_gso(skb) && + skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6); +} + static inline void skb_gso_reset(struct sk_buff *skb) { skb_shinfo(skb)->gso_size = 0; @@@ -4303,7 -4320,7 +4326,7 @@@ static inline bool skb_head_is_locked(c /* Local Checksum Offload. * Compute outer checksum based on the assumption that the * inner checksum will be offloaded later. - * See Documentation/networking/checksum-offloads.txt for + * See Documentation/networking/checksum-offloads.rst for * explanation of how this works. * Fill in outer checksum adjustment (e.g. with sum of outer * pseudo-header) before calling. diff --combined kernel/bpf/verifier.c index 8f295b790297,b63bc77af2d1..516dfc6d78de --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@@ -213,6 -213,7 +213,7 @@@ struct bpf_call_arg_meta s64 msize_smax_value; u64 msize_umax_value; int ptr_id; + int func_id; };
static DEFINE_MUTEX(bpf_verifier_lock); @@@ -351,6 -352,12 +352,12 @@@ static bool reg_is_refcounted(const str return type_is_refcounted(reg->type); }
+ static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) + { + return reg->type == PTR_TO_MAP_VALUE && + map_value_has_spin_lock(reg->map_ptr); + } + static bool reg_is_refcounted_or_null(const struct bpf_reg_state *reg) { return type_is_refcounted_or_null(reg->type); @@@ -712,6 -719,7 +719,7 @@@ static int copy_verifier_state(struct b } dst_state->speculative = src->speculative; dst_state->curframe = src->curframe; + dst_state->active_spin_lock = src->active_spin_lock; for (i = 0; i <= src->curframe; i++) { dst = dst_state->frame[i]; if (!dst) { @@@ -1095,7 -1103,7 +1103,7 @@@ static int check_subprogs(struct bpf_ve for (i = 0; i < insn_cnt; i++) { u8 code = insn[i].code;
- if (BPF_CLASS(code) != BPF_JMP) + if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) goto next; if (BPF_OP(code) == BPF_EXIT || BPF_OP(code) == BPF_CALL) goto next; @@@ -1483,6 -1491,21 +1491,21 @@@ static int check_map_access(struct bpf_ if (err) verbose(env, "R%d max value is outside of the array range\n", regno); + + if (map_value_has_spin_lock(reg->map_ptr)) { + u32 lock = reg->map_ptr->spin_lock_off; + + /* if any part of struct bpf_spin_lock can be touched by + * load/store reject this program. + * To check that [x1, x2) overlaps with [y1, y2) + * it is sufficient to check x1 < y2 && y1 < x2. + */ + if (reg->smin_value + off < lock + sizeof(struct bpf_spin_lock) && + lock < reg->umax_value + off + size) { + verbose(env, "bpf_spin_lock cannot be accessed directly by load/store\n"); + return -EACCES; + } + } return err; }
@@@ -1617,13 -1640,12 +1640,13 @@@ static int check_flow_keys_access(struc return 0; }
-static int check_sock_access(struct bpf_verifier_env *env, u32 regno, int off, - int size, enum bpf_access_type t) +static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, + u32 regno, int off, int size, + enum bpf_access_type t) { struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = ®s[regno]; - struct bpf_insn_access_aux info; + struct bpf_insn_access_aux info = {};
if (reg->smin_value < 0) { verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", @@@ -1637,8 -1659,6 +1660,8 @@@ return -EACCES; }
+ env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size; + return 0; }
@@@ -2035,7 -2055,7 +2058,7 @@@ static int check_mem_access(struct bpf_ verbose(env, "cannot write into socket\n"); return -EACCES; } - err = check_sock_access(env, regno, off, size, t); + err = check_sock_access(env, insn_idx, regno, off, size, t); if (!err && value_regno >= 0) mark_reg_unknown(env, regs, value_regno); } else { @@@ -2195,6 -2215,91 +2218,91 @@@ static int check_helper_mem_access(stru } }
+ /* Implementation details: + * bpf_map_lookup returns PTR_TO_MAP_VALUE_OR_NULL + * Two bpf_map_lookups (even with the same key) will have different reg->id. + * For traditional PTR_TO_MAP_VALUE the verifier clears reg->id after + * value_or_null->value transition, since the verifier only cares about + * the range of access to valid map value pointer and doesn't care about actual + * address of the map element. + * For maps with 'struct bpf_spin_lock' inside map value the verifier keeps + * reg->id > 0 after value_or_null->value transition. By doing so + * two bpf_map_lookups will be considered two different pointers that + * point to different bpf_spin_locks. + * The verifier allows taking only one bpf_spin_lock at a time to avoid + * dead-locks. + * Since only one bpf_spin_lock is allowed the checks are simpler than + * reg_is_refcounted() logic. The verifier needs to remember only + * one spin_lock instead of array of acquired_refs. + * cur_state->active_spin_lock remembers which map value element got locked + * and clears it after bpf_spin_unlock. + */ + static int process_spin_lock(struct bpf_verifier_env *env, int regno, + bool is_lock) + { + struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; + struct bpf_verifier_state *cur = env->cur_state; + bool is_const = tnum_is_const(reg->var_off); + struct bpf_map *map = reg->map_ptr; + u64 val = reg->var_off.value; + + if (reg->type != PTR_TO_MAP_VALUE) { + verbose(env, "R%d is not a pointer to map_value\n", regno); + return -EINVAL; + } + if (!is_const) { + verbose(env, + "R%d doesn't have constant offset. bpf_spin_lock has to be at the constant offset\n", + regno); + return -EINVAL; + } + if (!map->btf) { + verbose(env, + "map '%s' has to have BTF in order to use bpf_spin_lock\n", + map->name); + return -EINVAL; + } + if (!map_value_has_spin_lock(map)) { + if (map->spin_lock_off == -E2BIG) + verbose(env, + "map '%s' has more than one 'struct bpf_spin_lock'\n", + map->name); + else if (map->spin_lock_off == -ENOENT) + verbose(env, + "map '%s' doesn't have 'struct bpf_spin_lock'\n", + map->name); + else + verbose(env, + "map '%s' is not a struct type or bpf_spin_lock is mangled\n", + map->name); + return -EINVAL; + } + if (map->spin_lock_off != val + reg->off) { + verbose(env, "off %lld doesn't point to 'struct bpf_spin_lock'\n", + val + reg->off); + return -EINVAL; + } + if (is_lock) { + if (cur->active_spin_lock) { + verbose(env, + "Locking two bpf_spin_locks are not allowed\n"); + return -EINVAL; + } + cur->active_spin_lock = reg->id; + } else { + if (!cur->active_spin_lock) { + verbose(env, "bpf_spin_unlock without taking a lock\n"); + return -EINVAL; + } + if (cur->active_spin_lock != reg->id) { + verbose(env, "bpf_spin_unlock of different lock\n"); + return -EINVAL; + } + cur->active_spin_lock = 0; + } + return 0; + } + static bool arg_type_is_mem_ptr(enum bpf_arg_type type) { return type == ARG_PTR_TO_MEM || @@@ -2271,6 -2376,17 +2379,17 @@@ static int check_func_arg(struct bpf_ve return -EFAULT; } meta->ptr_id = reg->id; + } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) { + if (meta->func_id == BPF_FUNC_spin_lock) { + if (process_spin_lock(env, regno, true)) + return -EACCES; + } else if (meta->func_id == BPF_FUNC_spin_unlock) { + if (process_spin_lock(env, regno, false)) + return -EACCES; + } else { + verbose(env, "verifier internal error\n"); + return -EFAULT; + } } else if (arg_type_is_mem_ptr(arg_type)) { expected_type = PTR_TO_STACK; /* One exception here. In case function allows for NULL to be @@@ -2890,6 -3006,7 +3009,7 @@@ static int check_helper_call(struct bpf return err; }
+ meta.func_id = func_id; /* check args */ err = check_func_arg(env, BPF_REG_1, fn->arg1_type, &meta); if (err) @@@ -2972,6 -3089,8 +3092,8 @@@ regs[BPF_REG_0].map_ptr = meta.map_ptr; if (fn->ret_type == RET_PTR_TO_MAP_VALUE) { regs[BPF_REG_0].type = PTR_TO_MAP_VALUE; + if (map_value_has_spin_lock(meta.map_ptr)) + regs[BPF_REG_0].id = ++env->id_gen; } else { regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL; regs[BPF_REG_0].id = ++env->id_gen; @@@ -4034,11 -4153,50 +4156,50 @@@ static void find_good_pkt_pointers(stru * 0 - branch will not be taken and fall-through to next insn * -1 - unknown. Example: "if (reg < 5)" is unknown when register value range [0,10] */ - static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) + static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode, + bool is_jmp32) { + struct bpf_reg_state reg_lo; + s64 sval; + if (__is_pointer_value(false, reg)) return -1;
+ if (is_jmp32) { + reg_lo = *reg; + reg = ®_lo; + /* For JMP32, only low 32 bits are compared, coerce_reg_to_size + * could truncate high bits and update umin/umax according to + * information of low bits. + */ + coerce_reg_to_size(reg, 4); + /* smin/smax need special handling. For example, after coerce, + * if smin_value is 0x00000000ffffffffLL, the value is -1 when + * used as operand to JMP32. It is a negative number from s32's + * point of view, while it is a positive number when seen as + * s64. The smin/smax are kept as s64, therefore, when used with + * JMP32, they need to be transformed into s32, then sign + * extended back to s64. + * + * Also, smin/smax were copied from umin/umax. If umin/umax has + * different sign bit, then min/max relationship doesn't + * maintain after casting into s32, for this case, set smin/smax + * to safest range. + */ + if ((reg->umax_value ^ reg->umin_value) & + (1ULL << 31)) { + reg->smin_value = S32_MIN; + reg->smax_value = S32_MAX; + } + reg->smin_value = (s64)(s32)reg->smin_value; + reg->smax_value = (s64)(s32)reg->smax_value; + + val = (u32)val; + sval = (s64)(s32)val; + } else { + sval = (s64)val; + } + switch (opcode) { case BPF_JEQ: if (tnum_is_const(reg->var_off)) @@@ -4061,9 -4219,9 +4222,9 @@@ return 0; break; case BPF_JSGT: - if (reg->smin_value > (s64)val) + if (reg->smin_value > sval) return 1; - else if (reg->smax_value < (s64)val) + else if (reg->smax_value < sval) return 0; break; case BPF_JLT: @@@ -4073,9 -4231,9 +4234,9 @@@ return 0; break; case BPF_JSLT: - if (reg->smax_value < (s64)val) + if (reg->smax_value < sval) return 1; - else if (reg->smin_value >= (s64)val) + else if (reg->smin_value >= sval) return 0; break; case BPF_JGE: @@@ -4085,9 -4243,9 +4246,9 @@@ return 0; break; case BPF_JSGE: - if (reg->smin_value >= (s64)val) + if (reg->smin_value >= sval) return 1; - else if (reg->smax_value < (s64)val) + else if (reg->smax_value < sval) return 0; break; case BPF_JLE: @@@ -4097,9 -4255,9 +4258,9 @@@ return 0; break; case BPF_JSLE: - if (reg->smax_value <= (s64)val) + if (reg->smax_value <= sval) return 1; - else if (reg->smin_value > (s64)val) + else if (reg->smin_value > sval) return 0; break; } @@@ -4107,6 -4265,29 +4268,29 @@@ return -1; }
+ /* Generate min value of the high 32-bit from TNUM info. */ + static u64 gen_hi_min(struct tnum var) + { + return var.value & ~0xffffffffULL; + } + + /* Generate max value of the high 32-bit from TNUM info. */ + static u64 gen_hi_max(struct tnum var) + { + return (var.value | var.mask) & ~0xffffffffULL; + } + + /* Return true if VAL is compared with a s64 sign extended from s32, and they + * are with the same signedness. + */ + static bool cmp_val_with_extended_s64(s64 sval, struct bpf_reg_state *reg) + { + return ((s32)sval >= 0 && + reg->smin_value >= 0 && reg->smax_value <= S32_MAX) || + ((s32)sval < 0 && + reg->smax_value <= 0 && reg->smin_value >= S32_MIN); + } + /* Adjusts the register min/max values in the case that the dst_reg is the * variable register that we are working on, and src_reg is a constant or we're * simply doing a BPF_K check. @@@ -4114,8 -4295,10 +4298,10 @@@ */ static void reg_set_min_max(struct bpf_reg_state *true_reg, struct bpf_reg_state *false_reg, u64 val, - u8 opcode) + u8 opcode, bool is_jmp32) { + s64 sval; + /* If the dst_reg is a pointer, we can't learn anything about its * variable offset from the compare (unless src_reg were a pointer into * the same object, but we don't bother with that. @@@ -4125,19 -4308,31 +4311,31 @@@ if (__is_pointer_value(false, false_reg)) return;
+ val = is_jmp32 ? (u32)val : val; + sval = is_jmp32 ? (s64)(s32)val : (s64)val; + switch (opcode) { case BPF_JEQ: - /* If this is false then we know nothing Jon Snow, but if it is - * true then we know for sure. - */ - __mark_reg_known(true_reg, val); - break; case BPF_JNE: - /* If this is true we know nothing Jon Snow, but if it is false - * we know the value for sure; + { + struct bpf_reg_state *reg = + opcode == BPF_JEQ ? true_reg : false_reg; + + /* For BPF_JEQ, if this is false we know nothing Jon Snow, but + * if it is true we know the value for sure. Likewise for + * BPF_JNE. */ - __mark_reg_known(false_reg, val); + if (is_jmp32) { + u64 old_v = reg->var_off.value; + u64 hi_mask = ~0xffffffffULL; + + reg->var_off.value = (old_v & hi_mask) | val; + reg->var_off.mask &= hi_mask; + } else { + __mark_reg_known(reg, val); + } break; + } case BPF_JSET: false_reg->var_off = tnum_and(false_reg->var_off, tnum_const(~val)); @@@ -4145,38 -4340,61 +4343,61 @@@ true_reg->var_off = tnum_or(true_reg->var_off, tnum_const(val)); break; - case BPF_JGT: - false_reg->umax_value = min(false_reg->umax_value, val); - true_reg->umin_value = max(true_reg->umin_value, val + 1); - break; - case BPF_JSGT: - false_reg->smax_value = min_t(s64, false_reg->smax_value, val); - true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1); - break; - case BPF_JLT: - false_reg->umin_value = max(false_reg->umin_value, val); - true_reg->umax_value = min(true_reg->umax_value, val - 1); - break; - case BPF_JSLT: - false_reg->smin_value = max_t(s64, false_reg->smin_value, val); - true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1); - break; case BPF_JGE: - false_reg->umax_value = min(false_reg->umax_value, val - 1); - true_reg->umin_value = max(true_reg->umin_value, val); + case BPF_JGT: + { + u64 false_umax = opcode == BPF_JGT ? val : val - 1; + u64 true_umin = opcode == BPF_JGT ? val + 1 : val; + + if (is_jmp32) { + false_umax += gen_hi_max(false_reg->var_off); + true_umin += gen_hi_min(true_reg->var_off); + } + false_reg->umax_value = min(false_reg->umax_value, false_umax); + true_reg->umin_value = max(true_reg->umin_value, true_umin); break; + } case BPF_JSGE: - false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); - true_reg->smin_value = max_t(s64, true_reg->smin_value, val); + case BPF_JSGT: + { + s64 false_smax = opcode == BPF_JSGT ? sval : sval - 1; + s64 true_smin = opcode == BPF_JSGT ? sval + 1 : sval; + + /* If the full s64 was not sign-extended from s32 then don't + * deduct further info. + */ + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) + break; + false_reg->smax_value = min(false_reg->smax_value, false_smax); + true_reg->smin_value = max(true_reg->smin_value, true_smin); break; + } case BPF_JLE: - false_reg->umin_value = max(false_reg->umin_value, val + 1); - true_reg->umax_value = min(true_reg->umax_value, val); + case BPF_JLT: + { + u64 false_umin = opcode == BPF_JLT ? val : val + 1; + u64 true_umax = opcode == BPF_JLT ? val - 1 : val; + + if (is_jmp32) { + false_umin += gen_hi_min(false_reg->var_off); + true_umax += gen_hi_max(true_reg->var_off); + } + false_reg->umin_value = max(false_reg->umin_value, false_umin); + true_reg->umax_value = min(true_reg->umax_value, true_umax); break; + } case BPF_JSLE: - false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); - true_reg->smax_value = min_t(s64, true_reg->smax_value, val); + case BPF_JSLT: + { + s64 false_smin = opcode == BPF_JSLT ? sval : sval + 1; + s64 true_smax = opcode == BPF_JSLT ? sval - 1 : sval; + + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) + break; + false_reg->smin_value = max(false_reg->smin_value, false_smin); + true_reg->smax_value = min(true_reg->smax_value, true_smax); break; + } default: break; } @@@ -4199,24 -4417,34 +4420,34 @@@ */ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, struct bpf_reg_state *false_reg, u64 val, - u8 opcode) + u8 opcode, bool is_jmp32) { + s64 sval; + if (__is_pointer_value(false, false_reg)) return;
+ val = is_jmp32 ? (u32)val : val; + sval = is_jmp32 ? (s64)(s32)val : (s64)val; + switch (opcode) { case BPF_JEQ: - /* If this is false then we know nothing Jon Snow, but if it is - * true then we know for sure. - */ - __mark_reg_known(true_reg, val); - break; case BPF_JNE: - /* If this is true we know nothing Jon Snow, but if it is false - * we know the value for sure; - */ - __mark_reg_known(false_reg, val); + { + struct bpf_reg_state *reg = + opcode == BPF_JEQ ? true_reg : false_reg; + + if (is_jmp32) { + u64 old_v = reg->var_off.value; + u64 hi_mask = ~0xffffffffULL; + + reg->var_off.value = (old_v & hi_mask) | val; + reg->var_off.mask &= hi_mask; + } else { + __mark_reg_known(reg, val); + } break; + } case BPF_JSET: false_reg->var_off = tnum_and(false_reg->var_off, tnum_const(~val)); @@@ -4224,38 -4452,58 +4455,58 @@@ true_reg->var_off = tnum_or(true_reg->var_off, tnum_const(val)); break; - case BPF_JGT: - true_reg->umax_value = min(true_reg->umax_value, val - 1); - false_reg->umin_value = max(false_reg->umin_value, val); - break; - case BPF_JSGT: - true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1); - false_reg->smin_value = max_t(s64, false_reg->smin_value, val); - break; - case BPF_JLT: - true_reg->umin_value = max(true_reg->umin_value, val + 1); - false_reg->umax_value = min(false_reg->umax_value, val); - break; - case BPF_JSLT: - true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1); - false_reg->smax_value = min_t(s64, false_reg->smax_value, val); - break; case BPF_JGE: - true_reg->umax_value = min(true_reg->umax_value, val); - false_reg->umin_value = max(false_reg->umin_value, val + 1); + case BPF_JGT: + { + u64 false_umin = opcode == BPF_JGT ? val : val + 1; + u64 true_umax = opcode == BPF_JGT ? val - 1 : val; + + if (is_jmp32) { + false_umin += gen_hi_min(false_reg->var_off); + true_umax += gen_hi_max(true_reg->var_off); + } + false_reg->umin_value = max(false_reg->umin_value, false_umin); + true_reg->umax_value = min(true_reg->umax_value, true_umax); break; + } case BPF_JSGE: - true_reg->smax_value = min_t(s64, true_reg->smax_value, val); - false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); + case BPF_JSGT: + { + s64 false_smin = opcode == BPF_JSGT ? sval : sval + 1; + s64 true_smax = opcode == BPF_JSGT ? sval - 1 : sval; + + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) + break; + false_reg->smin_value = max(false_reg->smin_value, false_smin); + true_reg->smax_value = min(true_reg->smax_value, true_smax); break; + } case BPF_JLE: - true_reg->umin_value = max(true_reg->umin_value, val); - false_reg->umax_value = min(false_reg->umax_value, val - 1); + case BPF_JLT: + { + u64 false_umax = opcode == BPF_JLT ? val : val - 1; + u64 true_umin = opcode == BPF_JLT ? val + 1 : val; + + if (is_jmp32) { + false_umax += gen_hi_max(false_reg->var_off); + true_umin += gen_hi_min(true_reg->var_off); + } + false_reg->umax_value = min(false_reg->umax_value, false_umax); + true_reg->umin_value = max(true_reg->umin_value, true_umin); break; + } case BPF_JSLE: - true_reg->smin_value = max_t(s64, true_reg->smin_value, val); - false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); + case BPF_JSLT: + { + s64 false_smax = opcode == BPF_JSLT ? sval : sval - 1; + s64 true_smin = opcode == BPF_JSLT ? sval + 1 : sval; + + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) + break; + false_reg->smax_value = min(false_reg->smax_value, false_smax); + true_reg->smin_value = max(true_reg->smin_value, true_smin); break; + } default: break; } @@@ -4347,7 -4595,8 +4598,8 @@@ static void mark_ptr_or_null_reg(struc } else if (reg->type == PTR_TO_SOCKET_OR_NULL) { reg->type = PTR_TO_SOCKET; } - if (is_null || !reg_is_refcounted(reg)) { + if (is_null || !(reg_is_refcounted(reg) || + reg_may_point_to_spin_lock(reg))) { /* We don't need id from this point onwards anymore, * thus we should better reset it, so that state * pruning has chances to take effect. @@@ -4393,6 -4642,10 +4645,10 @@@ static bool try_match_pkt_pointers(cons if (BPF_SRC(insn->code) != BPF_X) return false;
+ /* Pointers are always 64-bit. */ + if (BPF_CLASS(insn->code) == BPF_JMP32) + return false; + switch (BPF_OP(insn->code)) { case BPF_JGT: if ((dst_reg->type == PTR_TO_PACKET && @@@ -4485,16 -4738,18 +4741,18 @@@ static int check_cond_jmp_op(struct bpf struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs; struct bpf_reg_state *dst_reg, *other_branch_regs; u8 opcode = BPF_OP(insn->code); + bool is_jmp32; int err;
- if (opcode > BPF_JSLE) { - verbose(env, "invalid BPF_JMP opcode %x\n", opcode); + /* Only conditional jumps are expected to reach here. */ + if (opcode == BPF_JA || opcode > BPF_JSLE) { + verbose(env, "invalid BPF_JMP/JMP32 opcode %x\n", opcode); return -EINVAL; }
if (BPF_SRC(insn->code) == BPF_X) { if (insn->imm != 0) { - verbose(env, "BPF_JMP uses reserved fields\n"); + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); return -EINVAL; }
@@@ -4510,7 -4765,7 +4768,7 @@@ } } else { if (insn->src_reg != BPF_REG_0) { - verbose(env, "BPF_JMP uses reserved fields\n"); + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); return -EINVAL; } } @@@ -4521,9 -4776,11 +4779,11 @@@ return err;
dst_reg = ®s[insn->dst_reg]; + is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
if (BPF_SRC(insn->code) == BPF_K) { - int pred = is_branch_taken(dst_reg, insn->imm, opcode); + int pred = is_branch_taken(dst_reg, insn->imm, opcode, + is_jmp32);
if (pred == 1) { /* only follow the goto, ignore fall-through */ @@@ -4551,30 -4808,51 +4811,51 @@@ * comparable. */ if (BPF_SRC(insn->code) == BPF_X) { + struct bpf_reg_state *src_reg = ®s[insn->src_reg]; + struct bpf_reg_state lo_reg0 = *dst_reg; + struct bpf_reg_state lo_reg1 = *src_reg; + struct bpf_reg_state *src_lo, *dst_lo; + + dst_lo = &lo_reg0; + src_lo = &lo_reg1; + coerce_reg_to_size(dst_lo, 4); + coerce_reg_to_size(src_lo, 4); + if (dst_reg->type == SCALAR_VALUE && - regs[insn->src_reg].type == SCALAR_VALUE) { - if (tnum_is_const(regs[insn->src_reg].var_off)) + src_reg->type == SCALAR_VALUE) { + if (tnum_is_const(src_reg->var_off) || + (is_jmp32 && tnum_is_const(src_lo->var_off))) reg_set_min_max(&other_branch_regs[insn->dst_reg], - dst_reg, regs[insn->src_reg].var_off.value, - opcode); - else if (tnum_is_const(dst_reg->var_off)) + dst_reg, + is_jmp32 + ? src_lo->var_off.value + : src_reg->var_off.value, + opcode, is_jmp32); + else if (tnum_is_const(dst_reg->var_off) || + (is_jmp32 && tnum_is_const(dst_lo->var_off))) reg_set_min_max_inv(&other_branch_regs[insn->src_reg], - ®s[insn->src_reg], - dst_reg->var_off.value, opcode); - else if (opcode == BPF_JEQ || opcode == BPF_JNE) + src_reg, + is_jmp32 + ? dst_lo->var_off.value + : dst_reg->var_off.value, + opcode, is_jmp32); + else if (!is_jmp32 && + (opcode == BPF_JEQ || opcode == BPF_JNE)) /* Comparing for equality, we can combine knowledge */ reg_combine_min_max(&other_branch_regs[insn->src_reg], &other_branch_regs[insn->dst_reg], - ®s[insn->src_reg], - ®s[insn->dst_reg], opcode); + src_reg, dst_reg, opcode); } } else if (dst_reg->type == SCALAR_VALUE) { reg_set_min_max(&other_branch_regs[insn->dst_reg], - dst_reg, insn->imm, opcode); + dst_reg, insn->imm, opcode, is_jmp32); }
- /* detect if R == 0 where R is returned from bpf_map_lookup_elem() */ - if (BPF_SRC(insn->code) == BPF_K && + /* detect if R == 0 where R is returned from bpf_map_lookup_elem(). + * NOTE: these optimizations below are related with pointer comparison + * which will never be JMP32. + */ + if (!is_jmp32 && BPF_SRC(insn->code) == BPF_K && insn->imm == 0 && (opcode == BPF_JEQ || opcode == BPF_JNE) && reg_type_may_be_null(dst_reg->type)) { /* Mark all identical registers in each branch as either @@@ -4716,6 -4994,11 +4997,11 @@@ static int check_ld_abs(struct bpf_veri return err; }
+ if (env->cur_state->active_spin_lock) { + verbose(env, "BPF_LD_[ABS|IND] cannot be used inside bpf_spin_lock-ed region\n"); + return -EINVAL; + } + if (regs[BPF_REG_6].type != PTR_TO_CTX) { verbose(env, "at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); @@@ -4903,7 -5186,8 +5189,8 @@@ peek_stack goto check_state; t = insn_stack[cur_stack - 1];
- if (BPF_CLASS(insns[t].code) == BPF_JMP) { + if (BPF_CLASS(insns[t].code) == BPF_JMP || + BPF_CLASS(insns[t].code) == BPF_JMP32) { u8 opcode = BPF_OP(insns[t].code);
if (opcode == BPF_EXIT) { @@@ -5000,13 -5284,14 +5287,14 @@@ static int check_btf_func(struct bpf_ve const union bpf_attr *attr, union bpf_attr __user *uattr) { - u32 i, nfuncs, urec_size, min_size, prev_offset; + u32 i, nfuncs, urec_size, min_size; u32 krec_size = sizeof(struct bpf_func_info); struct bpf_func_info *krecord; const struct btf_type *type; struct bpf_prog *prog; const struct btf *btf; void __user *urecord; + u32 prev_offset = 0; int ret = 0;
nfuncs = attr->func_info_cnt; @@@ -5450,8 -5735,11 +5738,11 @@@ static bool regsafe(struct bpf_reg_stat case PTR_TO_MAP_VALUE: /* If the new min/max/var_off satisfy the old ones and * everything else matches, we are OK. - * We don't care about the 'id' value, because nothing - * uses it for PTR_TO_MAP_VALUE (only for ..._OR_NULL) + * 'id' is not compared, since it's only used for maps with + * bpf_spin_lock inside map element and in such cases if + * the rest of the prog is valid for one map element then + * it's valid for all map elements regardless of the key + * used in bpf_map_lookup() */ return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && range_within(rold, rcur) && @@@ -5654,6 -5942,9 +5945,9 @@@ static bool states_equal(struct bpf_ver if (old->speculative && !cur->speculative) return false;
+ if (old->active_spin_lock != cur->active_spin_lock) + return false; + /* for states to be equal callsites have to be the same * and all frame states need to be equivalent */ @@@ -6058,7 -6349,7 +6352,7 @@@ static int do_check(struct bpf_verifier if (err) return err;
- } else if (class == BPF_JMP) { + } else if (class == BPF_JMP || class == BPF_JMP32) { u8 opcode = BPF_OP(insn->code);
if (opcode == BPF_CALL) { @@@ -6066,11 -6357,18 +6360,18 @@@ insn->off != 0 || (insn->src_reg != BPF_REG_0 && insn->src_reg != BPF_PSEUDO_CALL) || - insn->dst_reg != BPF_REG_0) { + insn->dst_reg != BPF_REG_0 || + class == BPF_JMP32) { verbose(env, "BPF_CALL uses reserved fields\n"); return -EINVAL; }
+ if (env->cur_state->active_spin_lock && + (insn->src_reg == BPF_PSEUDO_CALL || + insn->imm != BPF_FUNC_spin_unlock)) { + verbose(env, "function calls are not allowed while holding a lock\n"); + return -EINVAL; + } if (insn->src_reg == BPF_PSEUDO_CALL) err = check_func_call(env, insn, &env->insn_idx); else @@@ -6082,7 -6380,8 +6383,8 @@@ if (BPF_SRC(insn->code) != BPF_K || insn->imm != 0 || insn->src_reg != BPF_REG_0 || - insn->dst_reg != BPF_REG_0) { + insn->dst_reg != BPF_REG_0 || + class == BPF_JMP32) { verbose(env, "BPF_JA uses reserved fields\n"); return -EINVAL; } @@@ -6094,11 -6393,17 +6396,17 @@@ if (BPF_SRC(insn->code) != BPF_K || insn->imm != 0 || insn->src_reg != BPF_REG_0 || - insn->dst_reg != BPF_REG_0) { + insn->dst_reg != BPF_REG_0 || + class == BPF_JMP32) { verbose(env, "BPF_EXIT uses reserved fields\n"); return -EINVAL; }
+ if (env->cur_state->active_spin_lock) { + verbose(env, "bpf_spin_unlock is missing\n"); + return -EINVAL; + } + if (state->curframe) { /* exit from nested function */ env->prev_insn_idx = env->insn_idx; @@@ -6196,6 -6501,19 +6504,19 @@@ static int check_map_prealloc(struct bp !(map->map_flags & BPF_F_NO_PREALLOC); }
+ static bool is_tracing_prog_type(enum bpf_prog_type type) + { + switch (type) { + case BPF_PROG_TYPE_KPROBE: + case BPF_PROG_TYPE_TRACEPOINT: + case BPF_PROG_TYPE_PERF_EVENT: + case BPF_PROG_TYPE_RAW_TRACEPOINT: + return true; + default: + return false; + } + } + static int check_map_prog_compatibility(struct bpf_verifier_env *env, struct bpf_map *map, struct bpf_prog *prog) @@@ -6218,6 -6536,13 +6539,13 @@@ } }
+ if ((is_tracing_prog_type(prog->type) || + prog->type == BPF_PROG_TYPE_SOCKET_FILTER) && + map_value_has_spin_lock(map)) { + verbose(env, "tracing progs cannot use bpf_spin_lock yet\n"); + return -EINVAL; + } + if ((bpf_prog_is_dev_bound(prog->aux) || bpf_map_is_dev_bound(map)) && !bpf_offload_prog_map_match(prog, map)) { verbose(env, "offload device mismatch between prog and map\n"); @@@ -6434,6 -6759,153 +6762,153 @@@ static struct bpf_prog *bpf_patch_insn_ return new_prog; }
+ static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env, + u32 off, u32 cnt) + { + int i, j; + + /* find first prog starting at or after off (first to remove) */ + for (i = 0; i < env->subprog_cnt; i++) + if (env->subprog_info[i].start >= off) + break; + /* find first prog starting at or after off + cnt (first to stay) */ + for (j = i; j < env->subprog_cnt; j++) + if (env->subprog_info[j].start >= off + cnt) + break; + /* if j doesn't start exactly at off + cnt, we are just removing + * the front of previous prog + */ + if (env->subprog_info[j].start != off + cnt) + j--; + + if (j > i) { + struct bpf_prog_aux *aux = env->prog->aux; + int move; + + /* move fake 'exit' subprog as well */ + move = env->subprog_cnt + 1 - j; + + memmove(env->subprog_info + i, + env->subprog_info + j, + sizeof(*env->subprog_info) * move); + env->subprog_cnt -= j - i; + + /* remove func_info */ + if (aux->func_info) { + move = aux->func_info_cnt - j; + + memmove(aux->func_info + i, + aux->func_info + j, + sizeof(*aux->func_info) * move); + aux->func_info_cnt -= j - i; + /* func_info->insn_off is set after all code rewrites, + * in adjust_btf_func() - no need to adjust + */ + } + } else { + /* convert i from "first prog to remove" to "first to adjust" */ + if (env->subprog_info[i].start == off) + i++; + } + + /* update fake 'exit' subprog as well */ + for (; i <= env->subprog_cnt; i++) + env->subprog_info[i].start -= cnt; + + return 0; + } + + static int bpf_adj_linfo_after_remove(struct bpf_verifier_env *env, u32 off, + u32 cnt) + { + struct bpf_prog *prog = env->prog; + u32 i, l_off, l_cnt, nr_linfo; + struct bpf_line_info *linfo; + + nr_linfo = prog->aux->nr_linfo; + if (!nr_linfo) + return 0; + + linfo = prog->aux->linfo; + + /* find first line info to remove, count lines to be removed */ + for (i = 0; i < nr_linfo; i++) + if (linfo[i].insn_off >= off) + break; + + l_off = i; + l_cnt = 0; + for (; i < nr_linfo; i++) + if (linfo[i].insn_off < off + cnt) + l_cnt++; + else + break; + + /* First live insn doesn't match first live linfo, it needs to "inherit" + * last removed linfo. prog is already modified, so prog->len == off + * means no live instructions after (tail of the program was removed). + */ + if (prog->len != off && l_cnt && + (i == nr_linfo || linfo[i].insn_off != off + cnt)) { + l_cnt--; + linfo[--i].insn_off = off + cnt; + } + + /* remove the line info which refer to the removed instructions */ + if (l_cnt) { + memmove(linfo + l_off, linfo + i, + sizeof(*linfo) * (nr_linfo - i)); + + prog->aux->nr_linfo -= l_cnt; + nr_linfo = prog->aux->nr_linfo; + } + + /* pull all linfo[i].insn_off >= off + cnt in by cnt */ + for (i = l_off; i < nr_linfo; i++) + linfo[i].insn_off -= cnt; + + /* fix up all subprogs (incl. 'exit') which start >= off */ + for (i = 0; i <= env->subprog_cnt; i++) + if (env->subprog_info[i].linfo_idx > l_off) { + /* program may have started in the removed region but + * may not be fully removed + */ + if (env->subprog_info[i].linfo_idx >= l_off + l_cnt) + env->subprog_info[i].linfo_idx -= l_cnt; + else + env->subprog_info[i].linfo_idx = l_off; + } + + return 0; + } + + static int verifier_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt) + { + struct bpf_insn_aux_data *aux_data = env->insn_aux_data; + unsigned int orig_prog_len = env->prog->len; + int err; + + if (bpf_prog_is_dev_bound(env->prog->aux)) + bpf_prog_offload_remove_insns(env, off, cnt); + + err = bpf_remove_insns(env->prog, off, cnt); + if (err) + return err; + + err = adjust_subprog_starts_after_remove(env, off, cnt); + if (err) + return err; + + err = bpf_adj_linfo_after_remove(env, off, cnt); + if (err) + return err; + + memmove(aux_data + off, aux_data + off + cnt, + sizeof(*aux_data) * (orig_prog_len - off - cnt)); + + return 0; + } + /* The verifier does more data flow analysis than llvm and will not * explore branches that are dead at run time. Malicious programs can * have dead code too. Therefore replace all dead at-run-time code @@@ -6460,6 -6932,91 +6935,91 @@@ static void sanitize_dead_code(struct b } }
+ static bool insn_is_cond_jump(u8 code) + { + u8 op; + + if (BPF_CLASS(code) == BPF_JMP32) + return true; + + if (BPF_CLASS(code) != BPF_JMP) + return false; + + op = BPF_OP(code); + return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL; + } + + static void opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env) + { + struct bpf_insn_aux_data *aux_data = env->insn_aux_data; + struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0); + struct bpf_insn *insn = env->prog->insnsi; + const int insn_cnt = env->prog->len; + int i; + + for (i = 0; i < insn_cnt; i++, insn++) { + if (!insn_is_cond_jump(insn->code)) + continue; + + if (!aux_data[i + 1].seen) + ja.off = insn->off; + else if (!aux_data[i + 1 + insn->off].seen) + ja.off = 0; + else + continue; + + if (bpf_prog_is_dev_bound(env->prog->aux)) + bpf_prog_offload_replace_insn(env, i, &ja); + + memcpy(insn, &ja, sizeof(ja)); + } + } + + static int opt_remove_dead_code(struct bpf_verifier_env *env) + { + struct bpf_insn_aux_data *aux_data = env->insn_aux_data; + int insn_cnt = env->prog->len; + int i, err; + + for (i = 0; i < insn_cnt; i++) { + int j; + + j = 0; + while (i + j < insn_cnt && !aux_data[i + j].seen) + j++; + if (!j) + continue; + + err = verifier_remove_insns(env, i, j); + if (err) + return err; + insn_cnt = env->prog->len; + } + + return 0; + } + + static int opt_remove_nops(struct bpf_verifier_env *env) + { + const struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0); + struct bpf_insn *insn = env->prog->insnsi; + int insn_cnt = env->prog->len; + int i, err; + + for (i = 0; i < insn_cnt; i++) { + if (memcmp(&insn[i], &ja, sizeof(ja))) + continue; + + err = verifier_remove_insns(env, i, 1); + if (err) + return err; + insn_cnt--; + i--; + } + + return 0; + } + /* convert load instructions that access fields of a context type into a * sequence of instructions that access fields of the underlying structure: * struct __sk_buff -> struct sk_buff @@@ -7150,7 -7707,8 +7710,8 @@@ int bpf_check(struct bpf_prog **prog, u { struct bpf_verifier_env *env; struct bpf_verifier_log *log; - int ret = -EINVAL; + int i, len, ret = -EINVAL; + bool is_priv;
/* no program is valid */ if (ARRAY_SIZE(bpf_verifier_ops) == 0) @@@ -7164,12 -7722,14 +7725,14 @@@ return -ENOMEM; log = &env->log;
+ len = (*prog)->len; env->insn_aux_data = - vzalloc(array_size(sizeof(struct bpf_insn_aux_data), - (*prog)->len)); + vzalloc(array_size(sizeof(struct bpf_insn_aux_data), len)); ret = -ENOMEM; if (!env->insn_aux_data) goto err_free_env; + for (i = 0; i < len; i++) + env->insn_aux_data[i].orig_idx = i; env->prog = *prog; env->ops = bpf_verifier_ops[env->prog->type];
@@@ -7197,6 -7757,9 +7760,9 @@@ if (attr->prog_flags & BPF_F_ANY_ALIGNMENT) env->strict_alignment = false;
+ is_priv = capable(CAP_SYS_ADMIN); + env->allow_ptr_leaks = is_priv; + ret = replace_map_fd_with_map_ptr(env); if (ret < 0) goto skip_full_check; @@@ -7214,8 -7777,6 +7780,6 @@@ if (!env->explored_states) goto skip_full_check;
- env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); - ret = check_subprogs(env); if (ret < 0) goto skip_full_check; @@@ -7245,8 -7806,17 +7809,17 @@@ skip_full_check ret = check_max_stack_depth(env);
/* instruction rewrites happen after this point */ - if (ret == 0) - sanitize_dead_code(env); + if (is_priv) { + if (ret == 0) + opt_hard_wire_dead_code_branches(env); + if (ret == 0) + ret = opt_remove_dead_code(env); + if (ret == 0) + ret = opt_remove_nops(env); + } else { + if (ret == 0) + sanitize_dead_code(env); + }
if (ret == 0) /* program is valid, convert *(u32*)(ctx + off) accesses */ diff --combined kernel/cgroup/cgroup.c index 747e5b17f9da,9f617605dacb..19da0ab89a0c --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@@ -54,7 -54,6 +54,7 @@@ #include <linux/proc_ns.h> #include <linux/nsproxy.h> #include <linux/file.h> +#include <linux/fs_parser.h> #include <linux/sched/cputime.h> #include <linux/psi.h> #include <net/sock.h> @@@ -1773,37 -1772,26 +1773,37 @@@ int cgroup_show_path(struct seq_file *s return len; }
-static int parse_cgroup_root_flags(char *data, unsigned int *root_flags) -{ - char *token; +enum cgroup2_param { + Opt_nsdelegate, + nr__cgroup2_params +};
- *root_flags = 0; +static const struct fs_parameter_spec cgroup2_param_specs[] = { + fsparam_flag ("nsdelegate", Opt_nsdelegate), + {} +};
- if (!data || *data == '\0') - return 0; +static const struct fs_parameter_description cgroup2_fs_parameters = { + .name = "cgroup2", + .specs = cgroup2_param_specs, +};
- while ((token = strsep(&data, ",")) != NULL) { - if (!strcmp(token, "nsdelegate")) { - *root_flags |= CGRP_ROOT_NS_DELEGATE; - continue; - } +static int cgroup2_parse_param(struct fs_context *fc, struct fs_parameter *param) +{ + struct cgroup_fs_context *ctx = cgroup_fc2context(fc); + struct fs_parse_result result; + int opt;
- pr_err("cgroup2: unknown option "%s"\n", token); - return -EINVAL; - } + opt = fs_parse(fc, &cgroup2_fs_parameters, param, &result); + if (opt < 0) + return opt;
- return 0; + switch (opt) { + case Opt_nsdelegate: + ctx->flags |= CGRP_ROOT_NS_DELEGATE; + return 0; + } + return -EINVAL; }
static void apply_cgroup_root_flags(unsigned int root_flags) @@@ -1823,11 -1811,16 +1823,11 @@@ static int cgroup_show_options(struct s return 0; }
-static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data) +static int cgroup_reconfigure(struct fs_context *fc) { - unsigned int root_flags; - int ret; + struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
- ret = parse_cgroup_root_flags(data, &root_flags); - if (ret) - return ret; - - apply_cgroup_root_flags(root_flags); + apply_cgroup_root_flags(ctx->flags); return 0; }
@@@ -1915,9 -1908,8 +1915,9 @@@ static void init_cgroup_housekeeping(st INIT_WORK(&cgrp->release_agent_work, cgroup1_release_agent); }
-void init_cgroup_root(struct cgroup_root *root, struct cgroup_sb_opts *opts) +void init_cgroup_root(struct cgroup_fs_context *ctx) { + struct cgroup_root *root = ctx->root; struct cgroup *cgrp = &root->cgrp;
INIT_LIST_HEAD(&root->root_list); @@@ -1926,16 -1918,16 +1926,16 @@@ init_cgroup_housekeeping(cgrp); idr_init(&root->cgroup_idr);
- root->flags = opts->flags; - if (opts->release_agent) - strscpy(root->release_agent_path, opts->release_agent, PATH_MAX); - if (opts->name) - strscpy(root->name, opts->name, MAX_CGROUP_ROOT_NAMELEN); - if (opts->cpuset_clone_children) + root->flags = ctx->flags; + if (ctx->release_agent) + strscpy(root->release_agent_path, ctx->release_agent, PATH_MAX); + if (ctx->name) + strscpy(root->name, ctx->name, MAX_CGROUP_ROOT_NAMELEN); + if (ctx->cpuset_clone_children) set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags); }
-int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags) +int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) { LIST_HEAD(tmp_links); struct cgroup *root_cgrp = &root->cgrp; @@@ -1952,7 -1944,7 +1952,7 @@@ root_cgrp->ancestor_ids[0] = ret;
ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, - ref_flags, GFP_KERNEL); + 0, GFP_KERNEL); if (ret) goto out;
@@@ -2036,104 -2028,57 +2036,104 @@@ out return ret; }
-struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags, - struct cgroup_root *root, unsigned long magic, - struct cgroup_namespace *ns) +int cgroup_do_get_tree(struct fs_context *fc) { - struct dentry *dentry; - bool new_sb; + struct cgroup_fs_context *ctx = cgroup_fc2context(fc); + int ret;
- dentry = kernfs_mount(fs_type, flags, root->kf_root, magic, &new_sb); + ctx->kfc.root = ctx->root->kf_root; + if (fc->fs_type == &cgroup2_fs_type) + ctx->kfc.magic = CGROUP2_SUPER_MAGIC; + else + ctx->kfc.magic = CGROUP_SUPER_MAGIC; + ret = kernfs_get_tree(fc);
/* * In non-init cgroup namespace, instead of root cgroup's dentry, * we return the dentry corresponding to the cgroupns->root_cgrp. */ - if (!IS_ERR(dentry) && ns != &init_cgroup_ns) { + if (!ret && ctx->ns != &init_cgroup_ns) { struct dentry *nsdentry; + struct super_block *sb = fc->root->d_sb; struct cgroup *cgrp;
mutex_lock(&cgroup_mutex); spin_lock_irq(&css_set_lock);
- cgrp = cset_cgroup_from_root(ns->root_cset, root); + cgrp = cset_cgroup_from_root(ctx->ns->root_cset, ctx->root);
spin_unlock_irq(&css_set_lock); mutex_unlock(&cgroup_mutex);
- nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb); - dput(dentry); - dentry = nsdentry; + nsdentry = kernfs_node_dentry(cgrp->kn, sb); + dput(fc->root); + fc->root = nsdentry; + if (IS_ERR(nsdentry)) { + ret = PTR_ERR(nsdentry); + deactivate_locked_super(sb); + } }
- if (IS_ERR(dentry) || !new_sb) - cgroup_put(&root->cgrp); + if (!ctx->kfc.new_sb_created) + cgroup_put(&ctx->root->cgrp);
- return dentry; + return ret; }
-static struct dentry *cgroup_mount(struct file_system_type *fs_type, - int flags, const char *unused_dev_name, - void *data) +/* + * Destroy a cgroup filesystem context. + */ +static void cgroup_fs_context_free(struct fs_context *fc) { - struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; - struct dentry *dentry; + struct cgroup_fs_context *ctx = cgroup_fc2context(fc); + + kfree(ctx->name); + kfree(ctx->release_agent); + put_cgroup_ns(ctx->ns); + kernfs_free_fs_context(fc); + kfree(ctx); +} + +static int cgroup_get_tree(struct fs_context *fc) +{ + struct cgroup_fs_context *ctx = cgroup_fc2context(fc); int ret;
- get_cgroup_ns(ns); + cgrp_dfl_visible = true; + cgroup_get_live(&cgrp_dfl_root.cgrp); + ctx->root = &cgrp_dfl_root;
- /* Check if the caller has permission to mount. */ - if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) { - put_cgroup_ns(ns); - return ERR_PTR(-EPERM); - } + ret = cgroup_do_get_tree(fc); + if (!ret) + apply_cgroup_root_flags(ctx->flags); + return ret; +} + +static const struct fs_context_operations cgroup_fs_context_ops = { + .free = cgroup_fs_context_free, + .parse_param = cgroup2_parse_param, + .get_tree = cgroup_get_tree, + .reconfigure = cgroup_reconfigure, +}; + +static const struct fs_context_operations cgroup1_fs_context_ops = { + .free = cgroup_fs_context_free, + .parse_param = cgroup1_parse_param, + .get_tree = cgroup1_get_tree, + .reconfigure = cgroup1_reconfigure, +}; + +/* + * Initialise the cgroup filesystem creation/reconfiguration context. Notably, + * we select the namespace we're going to use. + */ +static int cgroup_init_fs_context(struct fs_context *fc) +{ + struct cgroup_fs_context *ctx; + + ctx = kzalloc(sizeof(struct cgroup_fs_context), GFP_KERNEL); + if (!ctx) + return -ENOMEM;
/* * The first time anyone tries to mount a cgroup, enable the list @@@ -2142,18 -2087,29 +2142,18 @@@ if (!use_task_css_set_links) cgroup_enable_task_cg_lists();
- if (fs_type == &cgroup2_fs_type) { - unsigned int root_flags; - - ret = parse_cgroup_root_flags(data, &root_flags); - if (ret) { - put_cgroup_ns(ns); - return ERR_PTR(ret); - } - - cgrp_dfl_visible = true; - cgroup_get_live(&cgrp_dfl_root.cgrp); - - dentry = cgroup_do_mount(&cgroup2_fs_type, flags, &cgrp_dfl_root, - CGROUP2_SUPER_MAGIC, ns); - if (!IS_ERR(dentry)) - apply_cgroup_root_flags(root_flags); - } else { - dentry = cgroup1_mount(&cgroup_fs_type, flags, data, - CGROUP_SUPER_MAGIC, ns); - } - - put_cgroup_ns(ns); - return dentry; + ctx->ns = current->nsproxy->cgroup_ns; + get_cgroup_ns(ctx->ns); + fc->fs_private = &ctx->kfc; + if (fc->fs_type == &cgroup2_fs_type) + fc->ops = &cgroup_fs_context_ops; + else + fc->ops = &cgroup1_fs_context_ops; + if (fc->user_ns) + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(ctx->ns->user_ns); + fc->global = true; + return 0; }
static void cgroup_kill_sb(struct super_block *sb) @@@ -2162,33 -2118,33 +2162,33 @@@ struct cgroup_root *root = cgroup_root_from_kf(kf_root);
/* - * If @root doesn't have any mounts or children, start killing it. + * If @root doesn't have any children, start killing it. * This prevents new mounts by disabling percpu_ref_tryget_live(). * cgroup_mount() may wait for @root's release. * * And don't kill the default root. */ - if (!list_empty(&root->cgrp.self.children) || - root == &cgrp_dfl_root) - cgroup_put(&root->cgrp); - else + if (list_empty(&root->cgrp.self.children) && root != &cgrp_dfl_root && + !percpu_ref_is_dying(&root->cgrp.self.refcnt)) percpu_ref_kill(&root->cgrp.self.refcnt); - + cgroup_put(&root->cgrp); kernfs_kill_sb(sb); }
struct file_system_type cgroup_fs_type = { - .name = "cgroup", - .mount = cgroup_mount, - .kill_sb = cgroup_kill_sb, - .fs_flags = FS_USERNS_MOUNT, + .name = "cgroup", + .init_fs_context = cgroup_init_fs_context, + .parameters = &cgroup1_fs_parameters, + .kill_sb = cgroup_kill_sb, + .fs_flags = FS_USERNS_MOUNT, };
static struct file_system_type cgroup2_fs_type = { - .name = "cgroup2", - .mount = cgroup_mount, - .kill_sb = cgroup_kill_sb, - .fs_flags = FS_USERNS_MOUNT, + .name = "cgroup2", + .init_fs_context = cgroup_init_fs_context, + .parameters = &cgroup2_fs_parameters, + .kill_sb = cgroup_kill_sb, + .fs_flags = FS_USERNS_MOUNT, };
int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, @@@ -5311,6 -5267,7 +5311,6 @@@ int cgroup_rmdir(struct kernfs_node *kn
static struct kernfs_syscall_ops cgroup_kf_syscall_ops = { .show_options = cgroup_show_options, - .remount_fs = cgroup_remount, .mkdir = cgroup_mkdir, .rmdir = cgroup_rmdir, .show_path = cgroup_show_path, @@@ -5377,12 -5334,11 +5377,12 @@@ static void __init cgroup_init_subsys(s */ int __init cgroup_init_early(void) { - static struct cgroup_sb_opts __initdata opts; + static struct cgroup_fs_context __initdata ctx; struct cgroup_subsys *ss; int i;
- init_cgroup_root(&cgrp_dfl_root, &opts); + ctx.root = &cgrp_dfl_root; + init_cgroup_root(&ctx); cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF;
RCU_INIT_POINTER(init_task.cgroups, &init_css_set); @@@ -5443,7 -5399,7 +5443,7 @@@ int __init cgroup_init(void hash_add(css_set_table, &init_css_set.hlist, css_set_hash(init_css_set.subsys));
- BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0, 0)); + BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0));
mutex_unlock(&cgroup_mutex);
@@@ -6040,7 -5996,7 +6040,7 @@@ int cgroup_bpf_detach(struct cgroup *cg int ret;
mutex_lock(&cgroup_mutex); - ret = __cgroup_bpf_detach(cgrp, prog, type, flags); + ret = __cgroup_bpf_detach(cgrp, prog, type); mutex_unlock(&cgroup_mutex); return ret; } diff --combined net/batman-adv/soft-interface.c index ffc83bebfe40,93a5975c21a4..8f8c2aee7dc6 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -1,5 -1,5 +1,5 @@@ // SPDX-License-Identifier: GPL-2.0 - /* Copyright (C) 2007-2018 B.A.T.M.A.N. contributors: + /* Copyright (C) 2007-2019 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * @@@ -212,6 -212,7 +212,7 @@@ static netdev_tx_t batadv_interface_tx( enum batadv_forw_mode forw_mode; struct batadv_orig_node *mcast_single_orig = NULL; int network_offset = ETH_HLEN; + __be16 proto;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped; @@@ -225,14 -226,15 +226,17 @@@ skb_reset_mac_header(skb); ethhdr = eth_hdr(skb);
- switch (ntohs(ethhdr->h_proto)) { + proto = ethhdr->h_proto; + + switch (ntohs(proto)) { case ETH_P_8021Q: + if (!pskb_may_pull(skb, sizeof(*vhdr))) + goto dropped; vhdr = vlan_eth_hdr(skb); + proto = vhdr->h_vlan_encapsulated_proto;
/* drop batman-in-batman packets to prevent loops */ - if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN)) { + if (proto != htons(ETH_P_BATMAN)) { network_offset += VLAN_HLEN; break; } @@@ -260,6 -262,9 +264,9 @@@ goto dropped; }
+ /* Snoop address candidates from DHCPACKs for early DAT filling */ + batadv_dat_snoop_outgoing_dhcp_ack(bat_priv, skb, proto, vid); + /* don't accept stp packets. STP does not help in meshes. * better use the bridge loop avoidance ... * diff --combined net/core/filter.c index f7d0004fc160,b5a002d7b263..634f8fc2ffb0 --- a/net/core/filter.c +++ b/net/core/filter.c @@@ -2789,7 -2789,8 +2789,7 @@@ static int bpf_skb_proto_4_to_6(struct u32 off = skb_mac_header_len(skb); int ret;
- /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ - if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + if (!skb_is_gso_tcp(skb)) return -ENOTSUPP;
ret = skb_cow(skb, len_diff); @@@ -2830,7 -2831,8 +2830,7 @@@ static int bpf_skb_proto_6_to_4(struct u32 off = skb_mac_header_len(skb); int ret;
- /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ - if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + if (!skb_is_gso_tcp(skb)) return -ENOTSUPP;
ret = skb_unclone(skb, GFP_ATOMIC); @@@ -2955,7 -2957,8 +2955,7 @@@ static int bpf_skb_net_grow(struct sk_b u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); int ret;
- /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ - if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + if (!skb_is_gso_tcp(skb)) return -ENOTSUPP;
ret = skb_cow(skb, len_diff); @@@ -2984,7 -2987,8 +2984,7 @@@ static int bpf_skb_net_shrink(struct sk u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb); int ret;
- /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */ - if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb))) + if (!skb_is_gso_tcp(skb)) return -ENOTSUPP;
ret = skb_unclone(skb, GFP_ATOMIC); @@@ -5312,10 -5316,20 +5312,20 @@@ bpf_base_func_proto(enum bpf_func_id fu return &bpf_tail_call_proto; case BPF_FUNC_ktime_get_ns: return &bpf_ktime_get_ns_proto; + default: + break; + } + + if (!capable(CAP_SYS_ADMIN)) + return NULL; + + switch (func_id) { + case BPF_FUNC_spin_lock: + return &bpf_spin_lock_proto; + case BPF_FUNC_spin_unlock: + return &bpf_spin_unlock_proto; case BPF_FUNC_trace_printk: - if (capable(CAP_SYS_ADMIN)) - return bpf_get_trace_printk_proto(); - /* else, fall through */ + return bpf_get_trace_printk_proto(); default: return NULL; } @@@ -6706,6 -6720,27 +6716,27 @@@ static u32 bpf_convert_ctx_access(enum target_size)); break;
+ case offsetof(struct __sk_buff, gso_segs): + /* si->dst_reg = skb_shinfo(SKB); */ + #ifdef NET_SKBUFF_DATA_USES_OFFSET + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, head), + si->dst_reg, si->src_reg, + offsetof(struct sk_buff, head)); + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end), + BPF_REG_AX, si->src_reg, + offsetof(struct sk_buff, end)); + *insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX); + #else + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end), + si->dst_reg, si->src_reg, + offsetof(struct sk_buff, end)); + #endif + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct skb_shared_info, gso_segs), + si->dst_reg, si->dst_reg, + bpf_target_off(struct skb_shared_info, + gso_segs, 2, + target_size)); + break; case offsetof(struct __sk_buff, wire_len): BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, pkt_len) != 4);
@@@ -7696,6 -7731,7 +7727,7 @@@ const struct bpf_verifier_ops flow_diss };
const struct bpf_prog_ops flow_dissector_prog_ops = { + .test_run = bpf_prog_test_run_flow_dissector, };
int sk_detach_filter(struct sock *sk) diff --combined net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index fa2ba7c500e4,e26165af45cb..4b07eb8a9b18 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c @@@ -214,8 -214,7 +214,8 @@@ int nf_nat_icmp_reply_translation(struc }
/* Change outer to look like the reply to an incoming packet */ - nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple); + target.dst.protonum = IPPROTO_ICMP; if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip)) return 0;
diff --combined net/ipv4/route.c index 5163b64f8fb3,16259ea9df54..ecc12a768191 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@@ -887,15 -887,13 +887,15 @@@ void ip_rt_send_redirect(struct sk_buf /* No redirected packets during ip_rt_redirect_silence; * reset the algorithm. */ - if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) + if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) { peer->rate_tokens = 0; + peer->n_redirects = 0; + }
/* Too many ignored redirects; do not send anything * set dst.rate_last to the last seen redirected packet. */ - if (peer->rate_tokens >= ip_rt_redirect_number) { + if (peer->n_redirects >= ip_rt_redirect_number) { peer->rate_last = jiffies; goto out_put_peer; } @@@ -912,7 -910,6 +912,7 @@@ icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); peer->rate_last = jiffies; ++peer->rate_tokens; + ++peer->n_redirects; #ifdef CONFIG_IP_ROUTE_VERBOSE if (log_martians && peer->rate_tokens == ip_rt_redirect_number) @@@ -1611,7 -1608,8 +1611,8 @@@ int ip_mc_validate_source(struct sk_buf return -EINVAL;
if (ipv4_is_zeronet(saddr)) { - if (!ipv4_is_local_multicast(daddr)) + if (!ipv4_is_local_multicast(daddr) && + ip_hdr(skb)->protocol != IPPROTO_IGMP) return -EINVAL; } else { err = fib_validate_source(skb, saddr, 0, tos, 0, dev, @@@ -2766,6 -2764,75 +2767,75 @@@ static struct sk_buff *inet_rtm_getrout return skb; }
+ static int inet_rtm_valid_getroute_req(struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { + struct rtmsg *rtm; + int i, err; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { + NL_SET_ERR_MSG(extack, + "ipv4: Invalid header for route get request"); + return -EINVAL; + } + + if (!netlink_strict_get_check(skb)) + return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, + rtm_ipv4_policy, extack); + + rtm = nlmsg_data(nlh); + if ((rtm->rtm_src_len && rtm->rtm_src_len != 32) || + (rtm->rtm_dst_len && rtm->rtm_dst_len != 32) || + rtm->rtm_table || rtm->rtm_protocol || + rtm->rtm_scope || rtm->rtm_type) { + NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for route get request"); + return -EINVAL; + } + + if (rtm->rtm_flags & ~(RTM_F_NOTIFY | + RTM_F_LOOKUP_TABLE | + RTM_F_FIB_MATCH)) { + NL_SET_ERR_MSG(extack, "ipv4: Unsupported rtm_flags for route get request"); + return -EINVAL; + } + + err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX, + rtm_ipv4_policy, extack); + if (err) + return err; + + if ((tb[RTA_SRC] && !rtm->rtm_src_len) || + (tb[RTA_DST] && !rtm->rtm_dst_len)) { + NL_SET_ERR_MSG(extack, "ipv4: rtm_src_len and rtm_dst_len must be 32 for IPv4"); + return -EINVAL; + } + + for (i = 0; i <= RTA_MAX; i++) { + if (!tb[i]) + continue; + + switch (i) { + case RTA_IIF: + case RTA_OIF: + case RTA_SRC: + case RTA_DST: + case RTA_IP_PROTO: + case RTA_SPORT: + case RTA_DPORT: + case RTA_MARK: + case RTA_UID: + break; + default: + NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in route get request"); + return -EINVAL; + } + } + + return 0; + } + static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { @@@ -2786,8 -2853,7 +2856,7 @@@ int err; int mark;
- err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy, - extack); + err = inet_rtm_valid_getroute_req(in_skb, nlh, tb, extack); if (err < 0) return err;
diff --combined net/ipv6/addrconf.c index 72ffd3d760ff,dcb1d434f7da..da5a21050ba9 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@@ -597,6 -597,43 +597,43 @@@ static const struct nla_policy devconf_ [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, };
+ static int inet6_netconf_valid_get_req(struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { + int i, err; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf get request"); + return -EINVAL; + } + + if (!netlink_strict_get_check(skb)) + return nlmsg_parse(nlh, sizeof(struct netconfmsg), tb, + NETCONFA_MAX, devconf_ipv6_policy, extack); + + err = nlmsg_parse_strict(nlh, sizeof(struct netconfmsg), tb, + NETCONFA_MAX, devconf_ipv6_policy, extack); + if (err) + return err; + + for (i = 0; i <= NETCONFA_MAX; i++) { + if (!tb[i]) + continue; + + switch (i) { + case NETCONFA_IFINDEX: + break; + default: + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request"); + return -EINVAL; + } + } + + return 0; + } + static int inet6_netconf_get_devconf(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) @@@ -605,14 -642,12 +642,12 @@@ struct nlattr *tb[NETCONFA_MAX+1]; struct inet6_dev *in6_dev = NULL; struct net_device *dev = NULL; - struct netconfmsg *ncm; struct sk_buff *skb; struct ipv6_devconf *devconf; int ifindex; int err;
- err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, - devconf_ipv6_policy, extack); + err = inet6_netconf_valid_get_req(in_skb, nlh, tb, extack); if (err < 0) return err;
@@@ -1165,8 -1200,7 +1200,8 @@@ check_cleanup_prefix_route(struct inet6 list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa == ifp) continue; - if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, + if (ifa->prefix_len != ifp->prefix_len || + !ipv6_prefix_equal(&ifa->addr, &ifp->addr, ifp->prefix_len)) continue; if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) @@@ -5182,6 -5216,52 +5217,52 @@@ static int inet6_dump_ifacaddr(struct s return inet6_dump_addr(skb, cb, type); }
+ static int inet6_rtm_valid_getaddr_req(struct sk_buff *skb, + const struct nlmsghdr *nlh, + struct nlattr **tb, + struct netlink_ext_ack *extack) + { + struct ifaddrmsg *ifm; + int i, err; + + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid header for get address request"); + return -EINVAL; + } + + ifm = nlmsg_data(nlh); + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { + NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get address request"); + return -EINVAL; + } + + if (!netlink_strict_get_check(skb)) + return nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, + ifa_ipv6_policy, extack); + + err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX, + ifa_ipv6_policy, extack); + if (err) + return err; + + for (i = 0; i <= IFA_MAX; i++) { + if (!tb[i]) + continue; + + switch (i) { + case IFA_TARGET_NETNSID: + case IFA_ADDRESS: + case IFA_LOCAL: + break; + default: + NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get address request"); + return -EINVAL; + } + } + + return 0; + } + static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { @@@ -5202,8 -5282,7 +5283,7 @@@ struct sk_buff *skb; int err;
- err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy, - extack); + err = inet6_rtm_valid_getaddr_req(in_skb, nlh, tb, extack); if (err < 0) return err;
@@@ -6825,6 -6904,11 +6905,11 @@@ static int __net_init addrconf_init_net if (!dflt) goto err_alloc_dflt;
+ if (sysctl_devconf_inherit_init_net == 1 && !net_eq(net, &init_net)) { + memcpy(all, init_net.ipv6.devconf_all, sizeof(ipv6_devconf)); + memcpy(dflt, init_net.ipv6.devconf_dflt, sizeof(ipv6_devconf_dflt)); + } + /* these will be inherited by all namespaces */ dflt->autoconf = ipv6_defaults.autoconf; dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; diff --combined net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index 7a41ee3c11b4,9c914db44bec..f0ec31933c15 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c @@@ -225,8 -225,7 +225,8 @@@ int nf_nat_icmpv6_reply_translation(str skb->len - hdrlen, 0)); }
- nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); + nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple); + target.dst.protonum = IPPROTO_ICMPV6; if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip)) return 0;
diff --combined net/mac80211/agg-tx.c index 54821fb1a960,e94b1a0407af..2c4cd4183bf9 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@@ -8,7 -8,7 +8,7 @@@ * Copyright 2007, Michael Wu flamingice@sourmilk.net * Copyright 2007-2010, Intel Corporation * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@@ -229,7 -229,7 +229,7 @@@ ieee80211_agg_start_txq(struct sta_inf clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); local_bh_disable(); rcu_read_lock(); - drv_wake_tx_queue(sta->sdata->local, txqi); + schedule_and_wake_txq(sta->sdata->local, txqi); rcu_read_unlock(); local_bh_enable(); } @@@ -366,8 -366,6 +366,8 @@@ int ___ieee80211_stop_tx_ba_session(str
set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
+ ieee80211_agg_stop_txq(sta, tid); + spin_unlock_bh(&sta->lock);
ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n", diff --combined net/rds/ib.h index 1fd1cac85da2,752f92235a38..67a715b076ca --- a/net/rds/ib.h +++ b/net/rds/ib.h @@@ -67,7 -67,9 +67,9 @@@ struct rds_ib_conn_priv_cmn u8 ricpc_protocol_major; u8 ricpc_protocol_minor; __be16 ricpc_protocol_minor_mask; /* bitmask */ - __be32 ricpc_reserved1; + u8 ricpc_dp_toss; + u8 ripc_reserved1; + __be16 ripc_reserved2; __be64 ricpc_ack_seq; __be32 ricpc_credit; /* non-zero enables flow ctl */ }; @@@ -331,8 -333,10 +333,8 @@@ static inline void rds_ib_dma_sync_sg_f unsigned int i;
for_each_sg(sglist, sg, sg_dma_len, i) { - ib_dma_sync_single_for_cpu(dev, - ib_sg_dma_address(dev, sg), - ib_sg_dma_len(dev, sg), - direction); + ib_dma_sync_single_for_cpu(dev, sg_dma_address(sg), + sg_dma_len(sg), direction); } } #define ib_dma_sync_sg_for_cpu rds_ib_dma_sync_sg_for_cpu @@@ -346,8 -350,10 +348,8 @@@ static inline void rds_ib_dma_sync_sg_f unsigned int i;
for_each_sg(sglist, sg, sg_dma_len, i) { - ib_dma_sync_single_for_device(dev, - ib_sg_dma_address(dev, sg), - ib_sg_dma_len(dev, sg), - direction); + ib_dma_sync_single_for_device(dev, sg_dma_address(sg), + sg_dma_len(sg), direction); } } #define ib_dma_sync_sg_for_device rds_ib_dma_sync_sg_for_device diff --combined net/rds/ib_recv.c index 672b91a9e207,d395eec98959..70559854837e --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@@ -346,8 -346,8 +346,8 @@@ static int rds_ib_recv_refill_one(struc sge->length = sizeof(struct rds_header);
sge = &recv->r_sge[1]; - sge->addr = ib_sg_dma_address(ic->i_cm_id->device, &recv->r_frag->f_sg); - sge->length = ib_sg_dma_len(ic->i_cm_id->device, &recv->r_frag->f_sg); + sge->addr = sg_dma_address(&recv->r_frag->f_sg); + sge->length = sg_dma_len(&recv->r_frag->f_sg);
ret = 0; out: @@@ -409,7 -409,9 +409,7 @@@ void rds_ib_recv_refill(struct rds_conn
rdsdebug("recv %p ibinc %p page %p addr %lu\n", recv, recv->r_ibinc, sg_page(&recv->r_frag->f_sg), - (long) ib_sg_dma_address( - ic->i_cm_id->device, - &recv->r_frag->f_sg)); + (long)sg_dma_address(&recv->r_frag->f_sg));
/* XXX when can this fail? */ ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, NULL); @@@ -984,9 -986,9 +984,9 @@@ void rds_ib_recv_cqe_handler(struct rds } else { /* We expect errors as the qp is drained during shutdown */ if (rds_conn_up(conn) || rds_conn_connecting(conn)) - rds_ib_conn_error(conn, "recv completion on <%pI6c,%pI6c> had status %u (%s), disconnecting and reconnecting\n", + rds_ib_conn_error(conn, "recv completion on <%pI6c,%pI6c, %d> had status %u (%s), disconnecting and reconnecting\n", &conn->c_laddr, &conn->c_faddr, - wc->status, + conn->c_tos, wc->status, ib_wc_status_msg(wc->status)); }
diff --combined net/rds/ib_send.c index f2d2d92306e2,09c46f2e97fa..18f2341202f8 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@@ -305,8 -305,9 +305,9 @@@ void rds_ib_send_cqe_handler(struct rds
/* We expect errors as the qp is drained during shutdown */ if (wc->status != IB_WC_SUCCESS && rds_conn_up(conn)) { - rds_ib_conn_error(conn, "send completion on <%pI6c,%pI6c> had status %u (%s), disconnecting and reconnecting\n", - &conn->c_laddr, &conn->c_faddr, wc->status, + rds_ib_conn_error(conn, "send completion on <%pI6c,%pI6c,%d> had status %u (%s), disconnecting and reconnecting\n", + &conn->c_laddr, &conn->c_faddr, + conn->c_tos, wc->status, ib_wc_status_msg(wc->status)); } } @@@ -645,16 -646,16 +646,16 @@@ int rds_ib_xmit(struct rds_connection * if (i < work_alloc && scat != &rm->data.op_sg[rm->data.op_count]) { len = min(RDS_FRAG_SIZE, - ib_sg_dma_len(dev, scat) - rm->data.op_dmaoff); + sg_dma_len(scat) - rm->data.op_dmaoff); send->s_wr.num_sge = 2;
- send->s_sge[1].addr = ib_sg_dma_address(dev, scat); + send->s_sge[1].addr = sg_dma_address(scat); send->s_sge[1].addr += rm->data.op_dmaoff; send->s_sge[1].length = len;
bytes_sent += len; rm->data.op_dmaoff += len; - if (rm->data.op_dmaoff == ib_sg_dma_len(dev, scat)) { + if (rm->data.op_dmaoff == sg_dma_len(scat)) { scat++; rm->data.op_dmasg++; rm->data.op_dmaoff = 0; @@@ -808,8 -809,8 +809,8 @@@ int rds_ib_xmit_atomic(struct rds_conne }
/* Convert our struct scatterlist to struct ib_sge */ - send->s_sge[0].addr = ib_sg_dma_address(ic->i_cm_id->device, op->op_sg); - send->s_sge[0].length = ib_sg_dma_len(ic->i_cm_id->device, op->op_sg); + send->s_sge[0].addr = sg_dma_address(op->op_sg); + send->s_sge[0].length = sg_dma_len(op->op_sg); send->s_sge[0].lkey = ic->i_pd->local_dma_lkey;
rdsdebug("rva %Lx rpa %Lx len %u\n", op->op_remote_addr, @@@ -921,8 -922,9 +922,8 @@@ int rds_ib_xmit_rdma(struct rds_connect
for (j = 0; j < send->s_rdma_wr.wr.num_sge && scat != &op->op_sg[op->op_count]; j++) { - len = ib_sg_dma_len(ic->i_cm_id->device, scat); - send->s_sge[j].addr = - ib_sg_dma_address(ic->i_cm_id->device, scat); + len = sg_dma_len(scat); + send->s_sge[j].addr = sg_dma_address(scat); send->s_sge[j].length = len; send->s_sge[j].lkey = ic->i_pd->local_dma_lkey;
diff --combined net/sched/cls_tcindex.c index 38bb882bb958,14d6b4058045..e6cf20bc8e80 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@@ -48,7 -48,7 +48,7 @@@ struct tcindex_data u32 hash; /* hash table size; 0 if undefined */ u32 alloc_hash; /* allocated size */ u32 fall_through; /* 0: only classify if explicit match */ - struct rcu_head rcu; + struct rcu_work rwork; };
static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) @@@ -173,7 -173,7 +173,7 @@@ static void tcindex_destroy_fexts_work( }
static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last, - struct netlink_ext_ack *extack) + bool rtnl_held, struct netlink_ext_ack *extack) { struct tcindex_data *p = rtnl_dereference(tp->root); struct tcindex_filter_result *r = arg; @@@ -221,11 -221,17 +221,11 @@@ found return 0; }
-static int tcindex_destroy_element(struct tcf_proto *tp, - void *arg, struct tcf_walker *walker) -{ - bool last; - - return tcindex_delete(tp, arg, &last, false, NULL); -} - -static void __tcindex_destroy(struct rcu_head *head) +static void tcindex_destroy_work(struct work_struct *work) { - struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); + struct tcindex_data *p = container_of(to_rcu_work(work), + struct tcindex_data, + rwork);
kfree(p->perfect); kfree(p->h); @@@ -252,11 -258,9 +252,11 @@@ static int tcindex_filter_result_init(s return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); }
-static void __tcindex_partial_destroy(struct rcu_head *head) +static void tcindex_partial_destroy_work(struct work_struct *work) { - struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); + struct tcindex_data *p = container_of(to_rcu_work(work), + struct tcindex_data, + rwork);
kfree(p->perfect); kfree(p); @@@ -271,7 -275,7 +271,7 @@@ static void tcindex_free_perfect_hash(s kfree(cp->perfect); }
-static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) +static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp) { int i, err = 0;
@@@ -285,9 -289,6 +285,9 @@@ TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); if (err < 0) goto errout; +#ifdef CONFIG_NET_CLS_ACT + cp->perfect[i].exts.net = net; +#endif }
return 0; @@@ -304,16 -305,16 +304,16 @@@ tcindex_set_parms(struct net *net, stru struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) { struct tcindex_filter_result new_filter_result, *old_r = r; - struct tcindex_filter_result cr; struct tcindex_data *cp = NULL, *oldp; struct tcindex_filter *f = NULL; /* make gcc behave */ + struct tcf_result cr = {}; int err, balloc = 0; struct tcf_exts e;
err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); if (err < 0) return err; - err = tcf_exts_validate(net, tp, tb, est, &e, ovr, extack); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr, true, extack); if (err < 0) goto errout;
@@@ -336,7 -337,7 +336,7 @@@ if (p->perfect) { int i;
- if (tcindex_alloc_perfect_hash(cp) < 0) + if (tcindex_alloc_perfect_hash(net, cp) < 0) goto errout; for (i = 0; i < cp->hash; i++) cp->perfect[i].res = p->perfect[i].res; @@@ -347,8 -348,11 +347,8 @@@ err = tcindex_filter_result_init(&new_filter_result); if (err < 0) goto errout1; - err = tcindex_filter_result_init(&cr); - if (err < 0) - goto errout1; if (old_r) - cr.res = r->res; + cr = r->res;
if (tb[TCA_TCINDEX_HASH]) cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); @@@ -402,7 -406,7 +402,7 @@@ err = -ENOMEM; if (!cp->perfect && !cp->h) { if (valid_perfect_hash(cp)) { - if (tcindex_alloc_perfect_hash(cp) < 0) + if (tcindex_alloc_perfect_hash(net, cp) < 0) goto errout_alloc; balloc = 1; } else { @@@ -439,8 -443,8 +439,8 @@@ }
if (tb[TCA_TCINDEX_CLASSID]) { - cr.res.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); - tcf_bind_filter(tp, &cr.res, base); + cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); + tcf_bind_filter(tp, &cr, base); }
if (old_r && old_r != r) { @@@ -452,7 -456,7 +452,7 @@@ }
oldp = p; - r->res = cr.res; + r->res = cr; tcf_exts_change(&r->exts, &e);
rcu_assign_pointer(tp->root, cp); @@@ -471,12 -475,10 +471,12 @@@ ; /* nothing */
rcu_assign_pointer(*fp, f); + } else { + tcf_exts_destroy(&new_filter_result.exts); }
if (oldp) - call_rcu(&oldp->rcu, __tcindex_partial_destroy); + tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work); return 0;
errout_alloc: @@@ -485,6 -487,7 +485,6 @@@ else if (balloc == 2) kfree(cp->h); errout1: - tcf_exts_destroy(&cr.exts); tcf_exts_destroy(&new_filter_result.exts); errout: kfree(cp); @@@ -496,7 -499,7 +496,7 @@@ static in tcindex_change(struct net *net, struct sk_buff *in_skb, struct tcf_proto *tp, unsigned long base, u32 handle, struct nlattr **tca, void **arg, bool ovr, - struct netlink_ext_ack *extack) + bool rtnl_held, struct netlink_ext_ack *extack) { struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *tb[TCA_TCINDEX_MAX + 1]; @@@ -519,7 -522,8 +519,8 @@@ tca[TCA_RATE], ovr, extack); }
- static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) + static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker, + bool rtnl_held) { struct tcindex_data *p = rtnl_dereference(tp->root); struct tcindex_filter *f, *next; @@@ -555,43 -559,24 +556,43 @@@ } }
- static void tcindex_destroy(struct tcf_proto *tp, + static void tcindex_destroy(struct tcf_proto *tp, bool rtnl_held, struct netlink_ext_ack *extack) { struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcf_walker walker; + int i;
pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); - walker.count = 0; - walker.skip = 0; - walker.fn = tcindex_destroy_element; - tcindex_walk(tp, &walker, true);
- call_rcu(&p->rcu, __tcindex_destroy); + if (p->perfect) { + for (i = 0; i < p->hash; i++) { + struct tcindex_filter_result *r = p->perfect + i; + + tcf_unbind_filter(tp, &r->res); + if (tcf_exts_get_net(&r->exts)) + tcf_queue_work(&r->rwork, + tcindex_destroy_rexts_work); + else + __tcindex_destroy_rexts(r); + } + } + + for (i = 0; p->h && i < p->hash; i++) { + struct tcindex_filter *f, *next; + bool last; + + for (f = rtnl_dereference(p->h[i]); f; f = next) { + next = rtnl_dereference(f->next); - tcindex_delete(tp, &f->result, &last, NULL); ++ tcindex_delete(tp, &f->result, &last, false, NULL); + } + } + + tcf_queue_work(&p->rwork, tcindex_destroy_work); }
static int tcindex_dump(struct net *net, struct tcf_proto *tp, void *fh, - struct sk_buff *skb, struct tcmsg *t) + struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) { struct tcindex_data *p = rtnl_dereference(tp->root); struct tcindex_filter_result *r = fh; diff --combined net/sched/sch_generic.c index 968a85fe4d4a,e24568f9246c..38e5add14fab --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@@ -500,7 -500,7 +500,7 @@@ static void dev_watchdog_down(struct ne * netif_carrier_on - set carrier * @dev: network device * - * Device has detected that carrier. + * Device has detected acquisition of carrier. */ void netif_carrier_on(struct net_device *dev) { @@@ -1366,7 -1366,11 +1366,11 @@@ static void mini_qdisc_rcu_func(struct void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp, struct tcf_proto *tp_head) { - struct mini_Qdisc *miniq_old = rtnl_dereference(*miniqp->p_miniq); + /* Protected with chain0->filter_chain_lock. + * Can't access chain directly because tp_head can be NULL. + */ + struct mini_Qdisc *miniq_old = + rcu_dereference_protected(*miniqp->p_miniq, 1); struct mini_Qdisc *miniq;
if (!tp_head) { diff --combined net/smc/smc_cdc.c index fb07ad8d69a6,28bbdb04bc35..d0b0f4c865b4 --- a/net/smc/smc_cdc.c +++ b/net/smc/smc_cdc.c @@@ -101,10 -101,14 +101,12 @@@ int smc_cdc_msg_send(struct smc_connect
conn->tx_cdc_seq++; conn->local_tx_ctrl.seqno = conn->tx_cdc_seq; - smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, - &conn->local_tx_ctrl, conn); - smc_curs_copy(&cfed, &((struct smc_host_cdc_msg *)wr_buf)->cons, conn); + smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf, conn, &cfed); rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend); - if (!rc) + if (!rc) { smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn); + conn->local_rx_ctrl.prod_flags.cons_curs_upd_req = 0; + }
return rc; } @@@ -192,6 -196,7 +194,7 @@@ int smcd_cdc_msg_send(struct smc_connec if (rc) return rc; smc_curs_copy(&conn->rx_curs_confirmed, &curs, conn); + conn->local_rx_ctrl.prod_flags.cons_curs_upd_req = 0; /* Calculate transmitted data and increment free send buffer space */ diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin, &conn->tx_curs_sent); @@@ -268,26 -273,18 +271,18 @@@ static void smc_cdc_msg_recv_action(str smp_mb__after_atomic(); smc->sk.sk_data_ready(&smc->sk); } else { - if (conn->local_rx_ctrl.prod_flags.write_blocked || - conn->local_rx_ctrl.prod_flags.cons_curs_upd_req || - conn->local_rx_ctrl.prod_flags.urg_data_pending) { - if (conn->local_rx_ctrl.prod_flags.urg_data_pending) - conn->urg_state = SMC_URG_NOTYET; - /* force immediate tx of current consumer cursor, but - * under send_lock to guarantee arrival in seqno-order - */ - if (smc->sk.sk_state != SMC_INIT) - smc_tx_sndbuf_nonempty(conn); - } + if (conn->local_rx_ctrl.prod_flags.write_blocked) + smc->sk.sk_data_ready(&smc->sk); + if (conn->local_rx_ctrl.prod_flags.urg_data_pending) + conn->urg_state = SMC_URG_NOTYET; }
- /* piggy backed tx info */ /* trigger sndbuf consumer: RDMA write into peer RMBE and CDC */ - if (diff_cons && smc_tx_prepared_sends(conn)) { + if ((diff_cons && smc_tx_prepared_sends(conn)) || + conn->local_rx_ctrl.prod_flags.cons_curs_upd_req || + conn->local_rx_ctrl.prod_flags.urg_data_pending) smc_tx_sndbuf_nonempty(conn); - /* trigger socket release if connection closed */ - smc_close_wake_tx_prepared(smc); - } + if (diff_cons && conn->urg_tx_pend && atomic_read(&conn->peer_rmbe_space) == conn->peer_rmbe_size) { /* urg data confirmed by peer, indicate we're ready for more */ diff --combined net/smc/smc_cdc.h index f1cdde9d4b89,e3b6b367f3b6..861dc24c588c --- a/net/smc/smc_cdc.h +++ b/net/smc/smc_cdc.h @@@ -211,27 -211,26 +211,27 @@@ static inline int smc_curs_diff_large(u
static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer, union smc_host_cursor *local, + union smc_host_cursor *save, struct smc_connection *conn) { - union smc_host_cursor temp; - - smc_curs_copy(&temp, local, conn); - peer->count = htonl(temp.count); - peer->wrap = htons(temp.wrap); + smc_curs_copy(save, local, conn); + peer->count = htonl(save->count); + peer->wrap = htons(save->wrap); /* peer->reserved = htons(0); must be ensured by caller */ }
static inline void smc_host_msg_to_cdc(struct smc_cdc_msg *peer, - struct smc_host_cdc_msg *local, - struct smc_connection *conn) + struct smc_connection *conn, + union smc_host_cursor *save) { + struct smc_host_cdc_msg *local = &conn->local_tx_ctrl; + peer->common.type = local->common.type; peer->len = local->len; peer->seqno = htons(local->seqno); peer->token = htonl(local->token); - smc_host_cursor_to_cdc(&peer->prod, &local->prod, conn); - smc_host_cursor_to_cdc(&peer->cons, &local->cons, conn); + smc_host_cursor_to_cdc(&peer->prod, &local->prod, save, conn); + smc_host_cursor_to_cdc(&peer->cons, &local->cons, save, conn); peer->prod_flags = local->prod_flags; peer->conn_state_flags = local->conn_state_flags; } @@@ -270,17 -269,18 +270,18 @@@ static inline void smcr_cdc_msg_to_host }
static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local, - struct smcd_cdc_msg *peer) + struct smcd_cdc_msg *peer, + struct smc_connection *conn) { union smc_host_cursor temp;
temp.wrap = peer->prod.wrap; temp.count = peer->prod.count; - atomic64_set(&local->prod.acurs, atomic64_read(&temp.acurs)); + smc_curs_copy(&local->prod, &temp, conn);
temp.wrap = peer->cons.wrap; temp.count = peer->cons.count; - atomic64_set(&local->cons.acurs, atomic64_read(&temp.acurs)); + smc_curs_copy(&local->cons, &temp, conn); local->prod_flags = peer->cons.prod_flags; local->conn_state_flags = peer->cons.conn_state_flags; } @@@ -290,7 -290,7 +291,7 @@@ static inline void smc_cdc_msg_to_host( struct smc_connection *conn) { if (conn->lgr->is_smcd) - smcd_cdc_msg_to_host(local, (struct smcd_cdc_msg *)peer); + smcd_cdc_msg_to_host(local, (struct smcd_cdc_msg *)peer, conn); else smcr_cdc_msg_to_host(local, peer, conn); } diff --combined net/tipc/link.c index 85ad5c0678d0,ac306d17f8ad..341ecd796aa4 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@@ -1126,7 -1126,7 +1126,7 @@@ static bool tipc_data_input(struct tipc skb_queue_tail(mc_inputq, skb); return true; } - /* else: fall through */ + /* fall through */ case CONN_MANAGER: skb_queue_tail(inputq, skb); return true; @@@ -1145,7 -1145,7 +1145,7 @@@ default: pr_warn("Dropping received illegal msg type\n"); kfree_skb(skb); - return false; + return true; }; }
@@@ -1425,10 -1425,6 +1425,10 @@@ static void tipc_link_build_proto_msg(s l->rcv_unacked = 0; } else { /* RESET_MSG or ACTIVATE_MSG */ + if (mtyp == ACTIVATE_MSG) { + msg_set_dest_session_valid(hdr, 1); + msg_set_dest_session(hdr, l->peer_session); + } msg_set_max_pkt(hdr, l->advertised_mtu); strcpy(data, l->if_name); msg_set_size(hdr, INT_H_SIZE + TIPC_MAX_IF_NAME); @@@ -1646,17 -1642,6 +1646,17 @@@ static int tipc_link_proto_rcv(struct t rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT); break; } + + /* If this endpoint was re-created while peer was ESTABLISHING + * it doesn't know current session number. Force re-synch. + */ + if (mtyp == ACTIVATE_MSG && msg_dest_session_valid(hdr) && + l->session != msg_dest_session(hdr)) { + if (less(l->session, msg_dest_session(hdr))) + l->session = msg_dest_session(hdr) + 1; + break; + } + /* ACTIVATE_MSG serves as PEER_RESET if link is already down */ if (mtyp == RESET_MSG || !link_is_up(l)) rc = tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT); diff --combined net/wireless/nl80211.c index d91a408db113,a3cc039b9f55..e36437abc45a --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@@ -250,7 -250,7 +250,7 @@@ nl80211_pmsr_ftm_req_attr_policy[NL8021 [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = NLA_POLICY_MAX(NLA_U8, 15), [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = - NLA_POLICY_MAX(NLA_U8, 15), + NLA_POLICY_MAX(NLA_U8, 31), [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 }, [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG }, [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG }, @@@ -259,15 -259,13 +259,13 @@@ static const struct nla_policy nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = { [NL80211_PMSR_TYPE_FTM] = - NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, - nl80211_pmsr_ftm_req_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy), };
static const struct nla_policy nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = { [NL80211_PMSR_REQ_ATTR_DATA] = - NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX, - nl80211_pmsr_req_data_policy), + NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy), [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG }, };
@@@ -280,8 -278,7 +278,7 @@@ nl80211_psmr_peer_attr_policy[NL80211_P */ [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED }, [NL80211_PMSR_PEER_ATTR_REQ] = - NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX, - nl80211_pmsr_req_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy), [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT }, };
@@@ -292,8 -289,7 +289,7 @@@ nl80211_pmsr_attr_policy[NL80211_PMSR_A [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT }, [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT }, [NL80211_PMSR_ATTR_PEERS] = - NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX, - nl80211_psmr_peer_attr_policy), + NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy), };
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { @@@ -555,8 -551,8 +551,8 @@@ }, [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), [NL80211_ATTR_PEER_MEASUREMENTS] = - NLA_POLICY_NESTED(NL80211_PMSR_ATTR_MAX, - nl80211_pmsr_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_attr_policy), + [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1), };
/* policy for the key attributes */ @@@ -2278,6 -2274,15 +2274,15 @@@ static int nl80211_send_wiphy(struct cf if (nl80211_send_pmsr_capa(rdev, msg)) goto nla_put_failure;
+ state->split_start++; + break; + case 15: + if (rdev->wiphy.akm_suites && + nla_put(msg, NL80211_ATTR_AKM_SUITES, + sizeof(u32) * rdev->wiphy.n_akm_suites, + rdev->wiphy.akm_suites)) + goto nla_put_failure; + /* done */ state->split_start = 0; break; @@@ -4540,6 -4545,9 +4545,9 @@@ static int nl80211_start_ap(struct sk_b
nl80211_calculate_ap_params(¶ms);
+ if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) + params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; + wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { @@@ -4851,6 -4859,11 +4859,11 @@@ static int nl80211_send_station(struct PUT_SINFO(PLID, plid, u16); PUT_SINFO(PLINK_STATE, plink_state, u8); PUT_SINFO_U64(RX_DURATION, rx_duration); + PUT_SINFO_U64(TX_DURATION, tx_duration); + + if (wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
switch (rdev->wiphy.signal_type) { case CFG80211_SIGNAL_TYPE_MBM: @@@ -5470,6 -5483,15 +5483,15 @@@ static int nl80211_set_station(struct s nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); }
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) + params.airtime_weight = + nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]); + + if (params.airtime_weight && + !wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + return -EOPNOTSUPP; + /* Include parameters for TDLS peer (will check later) */ err = nl80211_set_station_tdls(info, ¶ms); if (err) @@@ -5598,6 -5620,15 +5620,15 @@@ static int nl80211_new_station(struct s params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) + params.airtime_weight = + nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]); + + if (params.airtime_weight && + !wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + return -EOPNOTSUPP; + err = nl80211_parse_sta_channel_info(info, ¶ms); if (err) return err; @@@ -5803,7 -5834,13 +5834,13 @@@ static int nl80211_send_mpath(struct sk pinfo->discovery_timeout)) || ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) && nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, - pinfo->discovery_retries))) + pinfo->discovery_retries)) || + ((pinfo->filled & MPATH_INFO_HOP_COUNT) && + nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT, + pinfo->hop_count)) || + ((pinfo->filled & MPATH_INFO_PATH_CHANGE) && + nla_put_u32(msg, NL80211_MPATH_INFO_PATH_CHANGE, + pinfo->path_change_count))) goto nla_put_failure;
nla_nest_end(msg, pinfoattr); @@@ -9857,7 -9894,10 +9894,10 @@@ static int nl80211_setdel_pmksa(struct }
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + !(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP && + wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AP_PMKSA_CACHING))) return -EOPNOTSUPP;
switch (info->genlhdr->cmd) { @@@ -13047,7 -13087,9 +13087,9 @@@ static int nl80211_external_auth(struc if (!rdev->ops->external_auth) return -EOPNOTSUPP;
- if (!info->attrs[NL80211_ATTR_SSID]) + if (!info->attrs[NL80211_ATTR_SSID] && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL;
if (!info->attrs[NL80211_ATTR_BSSID]) @@@ -13058,18 -13100,24 +13100,24 @@@
memset(¶ms, 0, sizeof(params));
- params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); - if (params.ssid.ssid_len == 0 || - params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]), - params.ssid.ssid_len); + if (info->attrs[NL80211_ATTR_SSID]) { + params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid.ssid_len == 0 || + params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + memcpy(params.ssid.ssid, + nla_data(info->attrs[NL80211_ATTR_SSID]), + params.ssid.ssid_len); + }
memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+ if (info->attrs[NL80211_ATTR_PMKID]) + params.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); + return rdev_external_auth(rdev, dev, ¶ms); }
diff --combined net/xdp/xdp_umem.c index 37e1fe180769,5ab236c5c9a5..77520eacee8f --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@@ -13,12 -13,15 +13,15 @@@ #include <linux/mm.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> + #include <linux/idr.h>
#include "xdp_umem.h" #include "xsk_queue.h"
#define XDP_UMEM_MIN_CHUNK_SIZE 2048
+ static DEFINE_IDA(umem_ida); + void xdp_add_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs) { unsigned long flags; @@@ -67,6 -70,7 +70,7 @@@ struct xdp_umem *xdp_get_umem_from_qid(
return NULL; } + EXPORT_SYMBOL(xdp_get_umem_from_qid);
static void xdp_clear_umem_at_qid(struct net_device *dev, u16 queue_id) { @@@ -125,10 -129,9 +129,10 @@@ int xdp_umem_assign_dev(struct xdp_ume return 0;
err_unreg_umem: - xdp_clear_umem_at_qid(dev, queue_id); if (!force_zc) err = 0; /* fallback to copy mode */ + if (err) + xdp_clear_umem_at_qid(dev, queue_id); out_rtnl_unlock: rtnl_unlock(); return err; @@@ -194,6 -197,8 +198,8 @@@ static void xdp_umem_release(struct xdp
xdp_umem_clear_dev(umem);
+ ida_simple_remove(&umem_ida, umem->id); + if (umem->fq) { xskq_destroy(umem->fq); umem->fq = NULL; @@@ -260,10 -265,10 +266,10 @@@ static int xdp_umem_pin_pages(struct xd if (!umem->pgs) return -ENOMEM;
- down_write(¤t->mm->mmap_sem); - npgs = get_user_pages(umem->address, umem->npgs, - gup_flags, &umem->pgs[0], NULL); - up_write(¤t->mm->mmap_sem); + down_read(¤t->mm->mmap_sem); + npgs = get_user_pages_longterm(umem->address, umem->npgs, + gup_flags, &umem->pgs[0], NULL); + up_read(¤t->mm->mmap_sem);
if (npgs != umem->npgs) { if (npgs >= 0) { @@@ -400,8 -405,16 +406,16 @@@ struct xdp_umem *xdp_umem_create(struc if (!umem) return ERR_PTR(-ENOMEM);
+ err = ida_simple_get(&umem_ida, 0, 0, GFP_KERNEL); + if (err < 0) { + kfree(umem); + return ERR_PTR(err); + } + umem->id = err; + err = xdp_umem_reg(umem, mr); if (err) { + ida_simple_remove(&umem_ida, umem->id); kfree(umem); return ERR_PTR(err); } diff --combined net/xdp/xsk.c index 45f3b528dc09,949d3bbccb2f..41731c9bb26f --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@@ -27,14 -27,10 +27,10 @@@
#include "xsk_queue.h" #include "xdp_umem.h" + #include "xsk.h"
#define TX_BATCH_SIZE 16
- static struct xdp_sock *xdp_sk(struct sock *sk) - { - return (struct xdp_sock *)sk; - } - bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs) { return READ_ONCE(xs->rx) && READ_ONCE(xs->umem) && @@@ -350,6 -346,10 +346,10 @@@ static int xsk_release(struct socket *s
net = sock_net(sk);
+ mutex_lock(&net->xdp.lock); + sk_del_node_init_rcu(sk); + mutex_unlock(&net->xdp.lock); + local_bh_disable(); sock_prot_inuse_add(net, sk->sk_prot, -1); local_bh_enable(); @@@ -669,8 -669,6 +669,8 @@@ static int xsk_mmap(struct file *file, if (!umem) return -EINVAL;
+ /* Matches the smp_wmb() in XDP_UMEM_REG */ + smp_rmb(); if (offset == XDP_UMEM_PGOFF_FILL_RING) q = READ_ONCE(umem->fq); else if (offset == XDP_UMEM_PGOFF_COMPLETION_RING) @@@ -680,8 -678,6 +680,8 @@@ if (!q) return -EINVAL;
+ /* Matches the smp_wmb() in xsk_init_queue */ + smp_rmb(); qpg = virt_to_head_page(q->ring); if (size > (PAGE_SIZE << compound_order(qpg))) return -EINVAL; @@@ -750,6 -746,10 +750,10 @@@ static int xsk_create(struct net *net, mutex_init(&xs->mutex); spin_lock_init(&xs->tx_completion_lock);
+ mutex_lock(&net->xdp.lock); + sk_add_node_rcu(sk, &net->xdp.list); + mutex_unlock(&net->xdp.lock); + local_bh_disable(); sock_prot_inuse_add(net, &xsk_proto, 1); local_bh_enable(); @@@ -763,6 -763,23 +767,23 @@@ static const struct net_proto_family xs .owner = THIS_MODULE, };
+ static int __net_init xsk_net_init(struct net *net) + { + mutex_init(&net->xdp.lock); + INIT_HLIST_HEAD(&net->xdp.list); + return 0; + } + + static void __net_exit xsk_net_exit(struct net *net) + { + WARN_ON_ONCE(!hlist_empty(&net->xdp.list)); + } + + static struct pernet_operations xsk_net_ops = { + .init = xsk_net_init, + .exit = xsk_net_exit, + }; + static int __init xsk_init(void) { int err; @@@ -775,8 -792,13 +796,13 @@@ if (err) goto out_proto;
+ err = register_pernet_subsys(&xsk_net_ops); + if (err) + goto out_sk; return 0;
+ out_sk: + sock_unregister(PF_XDP); out_proto: proto_unregister(&xsk_proto); out: