The following commit has been merged in the master branch: commit 77c7c32667913e2644d1b9b35f0a51fc5b1057c5 Merge: f217bc96ddafc57de7fe1ce4a1517b814e85dd5e 9e5f10fe577be7974c721c0c2050fa6c967d4565 Author: Stephen Rothwell sfr@canb.auug.org.au Date: Mon Aug 23 11:58:15 2021 +1000
next-20210820/net-next
diff --combined Documentation/admin-guide/kernel-parameters.txt index 267d8488de3f,ee0569a040c6..e817420d1658 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@@ -380,9 -380,6 +380,9 @@@ arm64.nopauth [ARM64] Unconditionally disable Pointer Authentication support
+ arm64.nomte [ARM64] Unconditionally disable Memory Tagging Extension + support + ataflop= [HW,M68k]
atarimouse= [HW,MOUSE] Atari Mouse @@@ -4170,15 -4167,6 +4170,15 @@@ Format: <bool> (1/Y/y=enable, 0/N/n=disable) default: disabled
+ printk.console_no_auto_verbose= + Disable console loglevel raise on oops, panic + or lockdep-detected issues (only if lock debug is on). + With an exception to setups with low baudrate on + serial console, keeping this 0 is a good choice + in order to provide more debug information. + Format: <bool> + default: 0 (auto_verbose is enabled) + printk.devkmsg={on,off,ratelimit} Control writing to /dev/kmsg. on - unlimited logging to /dev/kmsg from userspace @@@ -4957,8 -4945,6 +4957,6 @@@ sa1100ir [NET] See drivers/net/irda/sa1100_ir.c.
- sbni= [NET] Granch SBNI12 leased line adapter - sched_verbose [KNL] Enables verbose scheduler debug messages.
schedstats= [KNL,X86] Enable or disable scheduled statistics. diff --combined MAINTAINERS index 557dbdbac0c5,652657b27e0d..5c7b958849c0 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -1488,7 -1488,7 +1488,7 @@@ M: Miquel Raynal <miquel.raynal@bootlin M: Naga Sureshkumar Relli nagasure@xilinx.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: Documentation/devicetree/bindings/mtd/arm,pl353-smc.yaml +F: Documentation/devicetree/bindings/memory-controllers/arm,pl353-smc.yaml F: drivers/memory/pl353-smc.c
ARM PRIMECELL CLCD PL110 DRIVER @@@ -2010,12 -2010,10 +2010,12 @@@ M: Krzysztof Halasa <khalasa@piap.pl L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml +F: Documentation/devicetree/bindings/bus/intel,ixp4xx-expansion-bus-controller.yaml F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt F: Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml F: Documentation/devicetree/bindings/timer/intel,ixp4xx-timer.yaml F: arch/arm/mach-ixp4xx/ +F: drivers/bus/intel-ixp4xx-eb.c F: drivers/clocksource/timer-ixp4xx.c F: drivers/crypto/ixp4xx_crypto.c F: drivers/gpio/gpio-ixp4xx.c @@@ -2309,14 -2307,14 +2309,14 @@@ N: oxna
ARM/PALM TREO SUPPORT M: Tomas Cech sleep_walker@suse.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/palmtreo.*
ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT M: Marek Vasut marek.vasut@gmail.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/include/mach/palmld.h @@@ -2330,7 -2328,7 +2330,7 @@@ F: arch/arm/mach-pxa/palmtx.
ARM/PALMZ72 SUPPORT M: Sergey Lapin slapin@ossfans.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/palmz72.* @@@ -2500,7 -2498,7 +2500,7 @@@ N: s5pv21
ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT M: Andrzej Hajda a.hajda@samsung.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-g2d/ @@@ -2517,14 -2515,14 +2517,14 @@@ ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPO 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-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-jpeg/
ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT M: Andrzej Hajda a.hajda@samsung.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-mfc/ @@@ -3542,7 -3540,7 +3542,7 @@@ BROADCOM BCM5301X ARM ARCHITECTUR M: Hauke Mehrtens hauke@hauke-m.de M: Rafa�� Mi��ecki zajec5@gmail.com M: bcm-kernel-feedback-list@broadcom.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/bcm470* F: arch/arm/boot/dts/bcm5301* @@@ -3552,7 -3550,7 +3552,7 @@@ F: arch/arm/mach-bcm/bcm_5301x. BROADCOM BCM53573 ARM ARCHITECTURE M: Rafa�� Mi��ecki rafal@milecki.pl L: bcm-kernel-feedback-list@broadcom.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/bcm47189* F: arch/arm/boot/dts/bcm53573* @@@ -3868,16 -3866,6 +3868,16 @@@ L: bcm-kernel-feedback-list@broadcom.co S: Maintained F: drivers/mtd/nand/raw/brcmnand/
+BROADCOM STB PCIE DRIVER +M: Jim Quinlan jim2101024@gmail.com +M: Nicolas Saenz Julienne nsaenz@kernel.org +M: Florian Fainelli f.fainelli@gmail.com +M: bcm-kernel-feedback-list@broadcom.com +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +F: drivers/pci/controller/pcie-brcmstb.c + BROADCOM SYSTEMPORT ETHERNET DRIVER M: Florian Fainelli f.fainelli@gmail.com L: bcm-kernel-feedback-list@broadcom.com @@@ -4510,10 -4498,9 +4510,10 @@@ L: clang-built-linux@googlegroups.co S: Supported W: https://clangbuiltlinux.github.io/ B: https://github.com/ClangBuiltLinux/linux/issues -C: irc://chat.freenode.net/clangbuiltlinux +C: irc://irc.libera.chat/clangbuiltlinux F: Documentation/kbuild/llvm.rst F: include/linux/compiler-clang.h +F: scripts/Makefile.clang F: scripts/clang-tools/ K: \b(?i:clang|llvm)\b
@@@ -4623,7 -4610,7 +4623,7 @@@ F: include/linux/clk F: include/linux/of_clk.h X: drivers/clk/clkdev.c
-COMMON INTERNET FILE SYSTEM (CIFS) +COMMON INTERNET FILE SYSTEM CLIENT (CIFS) M: Steve French sfrench@samba.org L: linux-cifs@vger.kernel.org L: samba-technical@lists.samba.org (moderated for non-subscribers) @@@ -4847,7 -4834,7 +4847,7 @@@ CPUIDLE DRIVER - ARM BIG LITTL M: Lorenzo Pieralisi lorenzo.pieralisi@arm.com M: Daniel Lezcano daniel.lezcano@linaro.org L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git F: drivers/cpuidle/cpuidle-big_little.c @@@ -4867,14 -4854,14 +4867,14 @@@ CPUIDLE DRIVER - ARM PSC M: Lorenzo Pieralisi lorenzo.pieralisi@arm.com M: Sudeep Holla sudeep.holla@arm.com L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/cpuidle/cpuidle-psci.c
CPUIDLE DRIVER - ARM PSCI PM DOMAIN M: Ulf Hansson ulf.hansson@linaro.org L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/cpuidle/cpuidle-psci.h F: drivers/cpuidle/cpuidle-psci-domain.c @@@ -5697,6 -5684,7 +5697,7 @@@ DPAA2 ETHERNET SWITCH DRIVE M: Ioana Ciornei ioana.ciornei@nxp.com L: netdev@vger.kernel.org S: Maintained + F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/switch-driver.rst F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch* F: drivers/net/ethernet/freescale/dpaa2/dpsw*
@@@ -6917,6 -6905,12 +6918,12 @@@ M: Mark Einon <mark.einon@gmail.com S: Odd Fixes F: drivers/net/ethernet/agere/
+ ETAS ES58X CAN/USB DRIVER + M: Vincent Mailhol mailhol.vincent@wanadoo.fr + L: linux-can@vger.kernel.org + S: Maintained + F: drivers/net/can/usb/etas_es58x/ + ETHERNET BRIDGE M: Roopa Prabhu roopa@nvidia.com M: Nikolay Aleksandrov nikolay@nvidia.com @@@ -7209,7 -7203,7 +7216,7 @@@ F: tools/firewire
FIRMWARE FRAMEWORK FOR ARMV8-A M: Sudeep Holla sudeep.holla@arm.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/arm_ffa/ F: include/linux/arm_ffa.h @@@ -7388,7 -7382,7 +7395,7 @@@ F: include/linux/platform_data/video-im
FREESCALE IMX DDR PMU DRIVER M: Frank Li Frank.li@nxp.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/admin-guide/perf/imx-ddr.rst F: Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml @@@ -7480,7 -7474,7 +7487,7 @@@ F: drivers/tty/serial/ucc_uart. FREESCALE SOC DRIVERS M: Li Yang leoyang.li@nxp.com L: linuxppc-dev@lists.ozlabs.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml F: Documentation/devicetree/bindings/soc/fsl/ @@@ -8408,7 -8402,7 +8415,7 @@@ F: drivers/crypto/hisilicon/sgl. F: drivers/crypto/hisilicon/zip/
HISILICON ROCE DRIVER -M: Lijun Ou oulijun@huawei.com +M: Wenpeng Liang liangwenpeng@huawei.com M: Weihang Li liweihang@huawei.com L: linux-rdma@vger.kernel.org S: Maintained @@@ -9762,11 -9756,6 +9769,6 @@@ M: David Sterba <dsterba@suse.com S: Odd Fixes F: drivers/tty/ipwireless/
- IPX NETWORK LAYER - L: netdev@vger.kernel.org - S: Obsolete - F: include/uapi/linux/ipx.h - IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY) M: Marc Zyngier maz@kernel.org S: Maintained @@@ -10065,7 -10054,6 +10067,7 @@@ F: fs/autofs KERNEL BUILD + files below scripts/ (unless maintained elsewhere) M: Masahiro Yamada masahiroy@kernel.org M: Michal Marek michal.lkml@markovi.net +R: Nick Desaulniers ndesaulniers@google.com L: linux-kbuild@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git @@@ -10117,16 -10105,6 +10119,16 @@@ T: git git://git.kernel.org/pub/scm/lin F: Documentation/dev-tools/kselftest* F: tools/testing/selftests/
+KERNEL SMB3 SERVER (KSMBD) +M: Namjae Jeon namjae.jeon@samsung.com +M: Sergey Senozhatsky senozhatsky@chromium.org +M: Steve French sfrench@samba.org +M: Hyunchul Lee hyc.lee@gmail.com +L: linux-cifs@vger.kernel.org +S: Maintained +T: git git://git.samba.org/ksmbd.git +F: fs/ksmbd/ + KERNEL UNIT TESTING FRAMEWORK (KUnit) M: Brendan Higgins brendanhiggins@google.com L: linux-kselftest@vger.kernel.org @@@ -10412,6 -10390,7 +10414,7 @@@ F: net/core/skmsg. F: net/core/sock_map.c F: net/ipv4/tcp_bpf.c F: net/ipv4/udp_bpf.c + F: net/unix/unix_bpf.c
LANDLOCK SECURITY MODULE M: Micka��l Sala��n mic@digikod.net @@@ -11054,6 -11033,18 +11057,18 @@@ F: drivers/mailbox/arm_mhuv2. F: include/linux/mailbox/arm_mhuv2_message.h F: Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
+ MANAGEMENT COMPONENT TRANSPORT PROTOCOL (MCTP) + M: Jeremy Kerr jk@codeconstruct.com.au + M: Matt Johnston matt@codeconstruct.com.au + L: netdev@vger.kernel.org + S: Maintained + F: Documentation/networking/mctp.rst + F: drivers/net/mctp/ + F: include/net/mctp.h + F: include/net/mctpdevice.h + F: include/net/netns/mctp.h + F: net/mctp/ + MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 M: Michael Kerrisk mtk.manpages@gmail.com L: linux-man@vger.kernel.org @@@ -11064,7 -11055,7 +11079,7 @@@ MARDUK (CREATOR CI40) DEVICE TREE SUPPO M: Rahul Bedarkar rahulbedarkar89@gmail.com L: linux-mips@vger.kernel.org S: Maintained -F: arch/mips/boot/dts/img/pistachio_marduk.dts +F: arch/mips/boot/dts/img/pistachio*
MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn andrew@lunn.ch @@@ -11116,7 -11107,7 +11131,7 @@@ F: drivers/net/wireless/marvell/liberta
MARVELL MACCHIATOBIN SUPPORT M: Russell King linux@armlinux.org.uk -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
@@@ -11351,6 -11342,12 +11366,12 @@@ W: https://linuxtv.or T: git git://linuxtv.org/media_tree.git F: drivers/media/radio/radio-maxiradio*
+ MAXLINEAR ETHERNET PHY DRIVER + M: Xu Liang lxu@maxlinear.com + L: netdev@vger.kernel.org + S: Supported + F: drivers/net/phy/mxl-gpy.c + MCBA MICROCHIP CAN BUS ANALYZER TOOL DRIVER R: Yasushi SHOJI yashi@spacecubics.com L: linux-can@vger.kernel.org @@@ -12667,7 -12664,6 +12688,7 @@@ M: Laurent Pinchart <laurent.pinchart@i L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml F: drivers/media/i2c/mt9p031.c F: include/media/i2c/mt9p031.h
@@@ -13278,15 -13274,6 +13299,15 @@@ T: git git://git.kernel.org/pub/scm/lin F: Documentation/filesystems/ntfs.rst F: fs/ntfs/
+NTFS3 FILESYSTEM +M: Konstantin Komarov almaz.alexandrovich@paragon-software.com +L: ntfs3@lists.linux.dev +S: Supported +W: http://www.paragon-software.com/ +T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git +F: Documentation/filesystems/ntfs3.rst +F: fs/ntfs3/ + NUBUS SUBSYSTEM M: Finn Thain fthain@linux-m68k.org L: linux-m68k@lists.linux-m68k.org @@@ -13720,13 -13707,6 +13741,13 @@@ S: Maintaine T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov13858.c
+OMNIVISION OV13B10 SENSOR DRIVER +M: Arec Kao arec.kao@intel.com +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: drivers/media/i2c/ov13b10.c + OMNIVISION OV2680 SENSOR DRIVER M: Rui Miguel Silva rmfrfs@gmail.com L: linux-media@vger.kernel.org @@@ -13821,15 -13801,6 +13842,15 @@@ T: git git://linuxtv.org/media_tree.gi F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml F: drivers/media/i2c/ov8856.c
+OMNIVISION OV9282 SENSOR DRIVER +M: Paul J. Murphy paul.j.murphy@intel.com +M: Daniele Alessandrelli daniele.alessandrelli@intel.com +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml +F: drivers/media/i2c/ov9282.c + OMNIVISION OV9640 SENSOR DRIVER M: Petr Cvek petrcvekcz@gmail.com L: linux-media@vger.kernel.org @@@ -13920,6 -13891,12 +13941,12 @@@ F: Documentation/devicetree F: arch/*/boot/dts/ F: include/dt-bindings/
+ OPENCOMPUTE PTP CLOCK DRIVER + M: Jonathan Lemon jonathan.lemon@gmail.com + L: netdev@vger.kernel.org + S: Maintained + F: drivers/ptp/ptp_ocp.c + OPENCORES I2C BUS DRIVER M: Peter Korsgaard peter@korsgaard.com M: Andrew Lunn andrew@lunn.ch @@@ -14192,7 -14169,7 +14219,7 @@@ F: drivers/pci/controller/pcie-altera. PCI DRIVER FOR APPLIEDMICRO XGENE M: Toan Le toan@os.amperecomputing.com L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci.txt F: drivers/pci/controller/pci-xgene.c @@@ -14200,7 -14177,7 +14227,7 @@@ PCI DRIVER FOR ARM VERSATILE PLATFORM M: Rob Herring robh@kernel.org L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/versatile.yaml F: drivers/pci/controller/pci-versatile.c @@@ -14208,7 -14185,7 +14235,7 @@@ PCI DRIVER FOR ARMADA 8K M: Thomas Petazzoni thomas.petazzoni@bootlin.com L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/pci-armada8k.txt F: drivers/pci/controller/dwc/pcie-armada8k.c @@@ -14226,7 -14203,7 +14253,7 @@@ M: Mingkai Hu <mingkai.hu@nxp.com M: Roy Zang roy.zang@nxp.com L: linuxppc-dev@lists.ozlabs.org L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/pci/controller/dwc/*layerscape*
@@@ -14306,7 -14283,7 +14333,7 @@@ F: drivers/pci/controller/pci-tegra. PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER M: Hou Zhiqiang Zhiqiang.Hou@nxp.com L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@@ -14340,7 -14317,7 +14367,7 @@@ PCI DRIVER FOR TI DRA7XX/J721 M: Kishon Vijay Abraham I kishon@ti.com L: linux-omap@vger.kernel.org L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/pci/ti-pci.txt F: drivers/pci/controller/cadence/pci-j721e.c @@@ -14396,7 -14373,7 +14423,7 @@@ F: drivers/pci/controller/pcie-altera-m PCI MSI DRIVER FOR APPLIEDMICRO XGENE M: Toan Le toan@os.amperecomputing.com L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt F: drivers/pci/controller/pci-xgene-msi.c @@@ -14480,13 -14457,6 +14507,13 @@@ S: Maintaine F: Documentation/devicetree/bindings/pci/hisilicon-histb-pcie.txt F: drivers/pci/controller/dwc/pcie-histb.c
+PCIE DRIVER FOR INTEL LGM GW SOC +M: Rahul Tanwar rtanwar@maxlinear.com +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/intel-gw-pcie.yaml +F: drivers/pci/controller/dwc/pcie-intel-gw.c + PCIE DRIVER FOR MEDIATEK M: Ryder Lee ryder.lee@mediatek.com M: Jianjun Wang jianjun.wang@mediatek.com @@@ -14759,6 -14729,14 +14786,6 @@@ S: Maintaine W: http://www.st.com/spear F: drivers/pinctrl/spear/
-PISTACHIO SOC SUPPORT -M: James Hartley james.hartley@sondrel.com -L: linux-mips@vger.kernel.org -S: Odd Fixes -F: arch/mips/boot/dts/img/pistachio* -F: arch/mips/configs/pistachio*_defconfig -F: arch/mips/pistachio/ - PKTCDVD DRIVER M: linux-block@vger.kernel.org S: Orphan @@@ -14893,7 -14871,7 +14920,7 @@@ F: include/linux/dtpm. POWER STATE COORDINATION INTERFACE (PSCI) M: Mark Rutland mark.rutland@arm.com M: Lorenzo Pieralisi lorenzo.pieralisi@arm.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/psci/ F: include/linux/psci.h @@@ -14975,11 -14953,6 +15002,11 @@@ S: Maintaine F: include/linux/printk.h F: kernel/printk/
+PRINTK INDEXING +R: Chris Down chris@chrisdown.name +S: Maintained +F: kernel/printk/index.c + PRISM54 WIRELESS DRIVER M: Luis Chamberlain mcgrof@kernel.org L: linux-wireless@vger.kernel.org @@@ -15425,7 -15398,7 +15452,7 @@@ F: arch/hexagon
QUALCOMM HIDMA DRIVER M: Sinan Kaya okaya@kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-msm@vger.kernel.org L: dmaengine@vger.kernel.org S: Supported @@@ -16510,12 -16483,6 +16537,12 @@@ F: drivers/phy/samsung/phy-s5pv210-usb2 F: drivers/phy/samsung/phy-samsung-usb2.c F: drivers/phy/samsung/phy-samsung-usb2.h
+SANCLOUD BEAGLEBONE ENHANCED DEVICE TREE +M: Paul Barker paul.barker@sancloud.com +R: Marc Murphy marc.murphy@sancloud.com +S: Supported +F: arch/arm/boot/dts/am335x-sancloud* + SC1200 WDT DRIVER M: Zwane Mwaikambo zwanem@gmail.com S: Maintained @@@ -17121,7 -17088,7 +17148,7 @@@ SECURE MONITOR CALL(SMC) CALLING CONVEN M: Mark Rutland mark.rutland@arm.com M: Lorenzo Pieralisi lorenzo.pieralisi@arm.com M: Sudeep Holla sudeep.holla@arm.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/smccc/ F: include/linux/arm-smccc.h @@@ -17238,7 -17205,7 +17265,7 @@@ F: drivers/media/pci/solo6x10
SOFTWARE DELEGATED EXCEPTION INTERFACE (SDEI) M: James Morse james.morse@arm.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/firmware/sdei.txt F: drivers/firmware/arm_sdei.c @@@ -17353,15 -17320,6 +17380,15 @@@ T: git git://linuxtv.org/media_tree.gi F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c
+SONY IMX335 SENSOR DRIVER +M: Paul J. Murphy paul.j.murphy@intel.com +M: Daniele Alessandrelli daniele.alessandrelli@intel.com +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml +F: drivers/media/i2c/imx335.c + SONY IMX355 SENSOR DRIVER M: Tianshu Qiu tian.shu.qiu@intel.com L: linux-media@vger.kernel.org @@@ -17369,15 -17327,6 +17396,15 @@@ S: Maintaine T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/imx355.c
+SONY IMX412 SENSOR DRIVER +M: Paul J. Murphy paul.j.murphy@intel.com +M: Daniele Alessandrelli daniele.alessandrelli@intel.com +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml +F: drivers/media/i2c/imx412.c + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky maximlevitsky@gmail.com M: Alex Dubov oakad@yahoo.com @@@ -18024,7 -17973,7 +18051,7 @@@ F: drivers/mfd/syscon. SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers M: Sudeep Holla sudeep.holla@arm.com R: Cristian Marussi cristian.marussi@arm.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/firmware/arm,sc[mp]i.yaml F: drivers/clk/clk-sc[mp]i.c @@@ -18035,7 -17984,6 +18062,7 @@@ F: drivers/regulator/scmi-regulator. F: drivers/reset/reset-scmi.c F: include/linux/sc[mp]i_protocol.h F: include/trace/events/scmi.h +F: include/uapi/linux/virtio_scmi.h
SYSTEM RESET/SHUTDOWN DRIVERS M: Sebastian Reichel sre@kernel.org @@@ -18397,7 -18345,7 +18424,7 @@@ TEXAS INSTRUMENTS' SYSTEM CONTROL INTER M: Nishanth Menon nm@ti.com M: Tero Kristo kristo@kernel.org M: Santosh Shilimkar ssantosh@kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt @@@ -18454,7 -18402,6 +18481,7 @@@ F: drivers/thermal F: include/linux/cpu_cooling.h F: include/linux/thermal.h F: include/uapi/linux/thermal.h +F: tools/thermal/
THERMAL DRIVER FOR AMLOGIC SOCS M: Guillaume La Roque glaroque@baylibre.com @@@ -18887,14 -18834,6 +18914,14 @@@ F: arch/x86/mm/testmmiotrace. F: include/linux/mmiotrace.h F: kernel/trace/trace_mmiotrace.c
+TRADITIONAL CHINESE DOCUMENTATION +M: Hu Haowen src.res@email.cn +L: linux-doc-tw-discuss@lists.sourceforge.net +S: Maintained +W: https://github.com/srcres258/linux-doc +T: git git://github.com/srcres258/linux-doc.git doc-zh-tw +F: Documentation/translations/zh_TW/ + TRIVIAL PATCHES M: Jiri Kosina trivial@kernel.org S: Maintained @@@ -19804,15 -19743,6 +19831,15 @@@ S: Maintaine F: include/uapi/linux/virtio_snd.h F: sound/virtio/*
+VIRTIO I2C DRIVER +M: Jie Deng jie.deng@intel.com +M: Viresh Kumar viresh.kumar@linaro.org +L: linux-i2c@vger.kernel.org +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/i2c/busses/i2c-virtio.c +F: include/uapi/linux/virtio_i2c.h + VIRTUAL BOX GUEST DEVICE DRIVER M: Hans de Goede hdegoede@redhat.com M: Arnd Bergmann arnd@arndb.de diff --combined arch/arm64/boot/dts/freescale/imx8mm.dtsi index e956dcf4b208,1608a48495b6..2f632e8ca388 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@@ -192,9 -192,10 +192,9 @@@ };
pmu { - compatible = "arm,armv8-pmuv3"; + compatible = "arm,cortex-a53-pmu"; interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; - interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>; };
timer { @@@ -240,7 -241,6 +240,7 @@@ };
usbphynop1: usbphynop1 { + #phy-cells = <0>; compatible = "usb-nop-xceiv"; clocks = <&clk IMX8MM_CLK_USB_PHY_REF>; assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>; @@@ -249,7 -249,6 +249,7 @@@ };
usbphynop2: usbphynop2 { + #phy-cells = <0>; compatible = "usb-nop-xceiv"; clocks = <&clk IMX8MM_CLK_USB_PHY_REF>; assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>; @@@ -921,7 -920,7 +921,7 @@@ };
fec1: ethernet@30be0000 { - compatible = "fsl,imx8mm-fec", "fsl,imx6sx-fec"; + compatible = "fsl,imx8mm-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec"; reg = <0x30be0000 0x10000>; interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, @@@ -969,7 -968,7 +969,7 @@@ clock-names = "usb1_ctrl_root_clk"; assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>; assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>; - fsl,usbphy = <&usbphynop1>; + phys = <&usbphynop1>; fsl,usbmisc = <&usbmisc1 0>; status = "disabled"; }; @@@ -988,7 -987,7 +988,7 @@@ clock-names = "usb1_ctrl_root_clk"; assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>; assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>; - fsl,usbphy = <&usbphynop2>; + phys = <&usbphynop2>; fsl,usbmisc = <&usbmisc2 0>; status = "disabled"; }; diff --combined arch/arm64/boot/dts/freescale/imx8mn.dtsi index 2d154a3bf0ea,e6de293865b0..da6c942fb7f9 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@@ -190,6 -190,7 +190,6 @@@ compatible = "arm,cortex-a53-pmu"; interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; - interrupt-affinity = <&A53_0>, <&A53_1>, <&A53_2>, <&A53_3>; };
psci { @@@ -922,7 -923,7 +922,7 @@@ };
fec1: ethernet@30be0000 { - compatible = "fsl,imx8mn-fec", "fsl,imx6sx-fec"; + compatible = "fsl,imx8mn-fec", "fsl,imx8mq-fec", "fsl,imx6sx-fec"; reg = <0x30be0000 0x10000>; interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, @@@ -970,7 -971,7 +970,7 @@@ clock-names = "usb1_ctrl_root_clk"; assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>; assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>; - fsl,usbphy = <&usbphynop1>; + phys = <&usbphynop1>; fsl,usbmisc = <&usbmisc1 0>; status = "disabled"; }; @@@ -1038,7 -1039,6 +1038,7 @@@ };
usbphynop1: usbphynop1 { + #phy-cells = <0>; compatible = "usb-nop-xceiv"; clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>; diff --combined drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8a97640cdfe7,8eb59666aac1..893bdaf03043 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@@ -72,8 -72,7 +72,8 @@@ #include "bnxt_debugfs.h"
#define BNXT_TX_TIMEOUT (5 * HZ) -#define BNXT_DEF_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_HW) +#define BNXT_DEF_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_HW | \ + NETIF_MSG_TX_ERR)
MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Broadcom BCM573xx network driver"); @@@ -278,6 -277,8 +278,8 @@@ static const u16 bnxt_async_events_arr[ ASYNC_EVENT_CMPL_EVENT_ID_DEBUG_NOTIFICATION, ASYNC_EVENT_CMPL_EVENT_ID_RING_MONITOR_MSG, ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST, + ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP, + ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT, };
static struct workqueue_struct *bnxt_pf_wq; @@@ -366,33 -367,6 +368,33 @@@ static u16 bnxt_xmit_get_cfa_action(str return md_dst->u.port_info.port_id; }
+static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + u16 prod) +{ + bnxt_db_write(bp, &txr->tx_db, prod); + txr->kick_pending = 0; +} + +static bool bnxt_txr_netif_try_stop_queue(struct bnxt *bp, + struct bnxt_tx_ring_info *txr, + struct netdev_queue *txq) +{ + netif_tx_stop_queue(txq); + + /* netif_tx_stop_queue() must be done before checking + * tx index in bnxt_tx_avail() below, because in + * bnxt_tx_int(), we update tx index before checking for + * netif_tx_queue_stopped(). + */ + smp_mb(); + if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh) { + netif_tx_wake_queue(txq); + return false; + } + + return true; +} + static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); @@@ -412,7 -386,6 +414,7 @@@ i = skb_get_queue_mapping(skb); if (unlikely(i >= bp->tx_nr_rings)) { dev_kfree_skb_any(skb); + atomic_long_inc(&dev->tx_dropped); return NETDEV_TX_OK; }
@@@ -422,12 -395,8 +424,12 @@@
free_size = bnxt_tx_avail(bp, txr); if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) { - netif_tx_stop_queue(txq); - return NETDEV_TX_BUSY; + /* We must have raced with NAPI cleanup */ + if (net_ratelimit() && txr->kick_pending) + netif_warn(bp, tx_err, dev, + "bnxt: ring busy w/ flush pending!\n"); + if (bnxt_txr_netif_try_stop_queue(bp, txr, txq)) + return NETDEV_TX_BUSY; }
length = skb->len; @@@ -550,16 -519,21 +552,16 @@@ normal_tx: if (length < BNXT_MIN_PKT_SIZE) { pad = BNXT_MIN_PKT_SIZE - length; - if (skb_pad(skb, pad)) { + if (skb_pad(skb, pad)) /* SKB already freed. */ - tx_buf->skb = NULL; - return NETDEV_TX_OK; - } + goto tx_kick_pending; length = BNXT_MIN_PKT_SIZE; }
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(&pdev->dev, mapping))) { - dev_kfree_skb_any(skb); - tx_buf->skb = NULL; - return NETDEV_TX_OK; - } + if (unlikely(dma_mapping_error(&pdev->dev, mapping))) + goto tx_free;
dma_unmap_addr_set(tx_buf, mapping, mapping); flags = (len << TX_BD_LEN_SHIFT) | TX_BD_TYPE_LONG_TX_BD | @@@ -646,17 -620,24 +648,17 @@@ txr->tx_prod = prod;
if (!netdev_xmit_more() || netif_xmit_stopped(txq)) - bnxt_db_write(bp, &txr->tx_db, prod); + bnxt_txr_db_kick(bp, txr, prod); + else + txr->kick_pending = 1;
tx_done:
if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) { if (netdev_xmit_more() && !tx_buf->is_push) - bnxt_db_write(bp, &txr->tx_db, prod); - - netif_tx_stop_queue(txq); + bnxt_txr_db_kick(bp, txr, prod);
- /* netif_tx_stop_queue() must be done before checking - * tx index in bnxt_tx_avail() below, because in - * bnxt_tx_int(), we update tx index before checking for - * netif_tx_queue_stopped(). - */ - smp_mb(); - if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh) - netif_tx_wake_queue(txq); + bnxt_txr_netif_try_stop_queue(bp, txr, txq); } return NETDEV_TX_OK;
@@@ -669,6 -650,7 +671,6 @@@ tx_dma_error /* start back at beginning and unmap skb */ prod = txr->tx_prod; tx_buf = &txr->tx_buf_ring[prod]; - tx_buf->skb = NULL; dma_unmap_single(&pdev->dev, dma_unmap_addr(tx_buf, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); prod = NEXT_TX(prod); @@@ -682,13 -664,7 +684,13 @@@ PCI_DMA_TODEVICE); }
+tx_free: dev_kfree_skb_any(skb); +tx_kick_pending: + if (txr->kick_pending) + bnxt_txr_db_kick(bp, txr, txr->tx_prod); + txr->tx_buf_ring[txr->tx_prod].skb = NULL; + atomic_long_inc(&dev->tx_dropped); return NETDEV_TX_OK; }
@@@ -758,9 -734,14 +760,9 @@@ next_tx_int smp_mb();
if (unlikely(netif_tx_queue_stopped(txq)) && - (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)) { - __netif_tx_lock(txq, smp_processor_id()); - if (netif_tx_queue_stopped(txq) && - bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh && - txr->dev_state != BNXT_DEV_STATE_CLOSING) - netif_tx_wake_queue(txq); - __netif_tx_unlock(txq); - } + bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh && + READ_ONCE(txr->dev_state) != BNXT_DEV_STATE_CLOSING) + netif_tx_wake_queue(txq); }
static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, @@@ -1788,10 -1769,6 +1790,10 @@@ static int bnxt_rx_pkt(struct bnxt *bp if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons)) return -EBUSY;
+ /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); prod = rxr->rx_prod;
if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) { @@@ -2014,10 -1991,6 +2016,10 @@@ static int bnxt_force_rx_discard(struc if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons)) return -EBUSY;
+ /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); cmp_type = RX_CMP_TYPE(rxcmp); if (cmp_type == CMP_TYPE_RX_L2_CMP) { rxcmp1->rx_cmp_cfa_code_errors_v2 |= @@@ -2074,6 -2047,19 +2076,19 @@@ static u16 bnxt_agg_ring_id_to_grp_idx( return INVALID_HW_RING_ID; }
+ static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2) + { + switch (BNXT_EVENT_ERROR_REPORT_TYPE(data1)) { + case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_INVALID_SIGNAL: + netdev_err(bp->dev, "1PPS: Received invalid signal on pin%lu from the external source. Please fix the signal and reconfigure the pin\n", + BNXT_EVENT_INVALID_SIGNAL_DATA(data2)); + break; + default: + netdev_err(bp->dev, "FW reported unknown error type\n"); + break; + } + } + #define BNXT_GET_EVENT_PORT(data) \ ((data) & \ ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK) @@@ -2234,6 -2220,14 +2249,14 @@@ static int bnxt_async_event_process(str } goto async_event_process_exit; } + case ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP: { + bnxt_ptp_pps_event(bp, data1, data2); + goto async_event_process_exit; + } + case ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT: { + bnxt_event_error_report(bp, data1, data2); + goto async_event_process_exit; + } default: goto async_event_process_exit; } @@@ -2483,10 -2477,6 +2506,10 @@@ static int bnxt_poll_nitroa0(struct nap if (!TX_CMP_VALID(txcmp, raw_cons)) break;
+ /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) { tmp_raw_cons = NEXT_RAW_CMP(raw_cons); cp_cons = RING_CMP(tmp_raw_cons); @@@ -3176,6 -3166,58 +3199,58 @@@ static int bnxt_alloc_tx_rings(struct b return 0; }
+ static void bnxt_free_cp_arrays(struct bnxt_cp_ring_info *cpr) + { + kfree(cpr->cp_desc_ring); + cpr->cp_desc_ring = NULL; + kfree(cpr->cp_desc_mapping); + cpr->cp_desc_mapping = NULL; + } + + static int bnxt_alloc_cp_arrays(struct bnxt_cp_ring_info *cpr, int n) + { + cpr->cp_desc_ring = kcalloc(n, sizeof(*cpr->cp_desc_ring), GFP_KERNEL); + if (!cpr->cp_desc_ring) + return -ENOMEM; + cpr->cp_desc_mapping = kcalloc(n, sizeof(*cpr->cp_desc_mapping), + GFP_KERNEL); + if (!cpr->cp_desc_mapping) + return -ENOMEM; + return 0; + } + + static void bnxt_free_all_cp_arrays(struct bnxt *bp) + { + int i; + + if (!bp->bnapi) + return; + for (i = 0; i < bp->cp_nr_rings; i++) { + struct bnxt_napi *bnapi = bp->bnapi[i]; + + if (!bnapi) + continue; + bnxt_free_cp_arrays(&bnapi->cp_ring); + } + } + + static int bnxt_alloc_all_cp_arrays(struct bnxt *bp) + { + int i, n = bp->cp_nr_pages; + + for (i = 0; i < bp->cp_nr_rings; i++) { + struct bnxt_napi *bnapi = bp->bnapi[i]; + int rc; + + if (!bnapi) + continue; + rc = bnxt_alloc_cp_arrays(&bnapi->cp_ring, n); + if (rc) + return rc; + } + return 0; + } + static void bnxt_free_cp_rings(struct bnxt *bp) { int i; @@@ -3203,6 -3245,7 +3278,7 @@@ if (cpr2) { ring = &cpr2->cp_ring_struct; bnxt_free_ring(bp, &ring->ring_mem); + bnxt_free_cp_arrays(cpr2); kfree(cpr2); cpr->cp_ring_arr[j] = NULL; } @@@ -3221,6 -3264,12 +3297,12 @@@ static struct bnxt_cp_ring_info *bnxt_a if (!cpr) return NULL;
+ rc = bnxt_alloc_cp_arrays(cpr, bp->cp_nr_pages); + if (rc) { + bnxt_free_cp_arrays(cpr); + kfree(cpr); + return NULL; + } ring = &cpr->cp_ring_struct; rmem = &ring->ring_mem; rmem->nr_pages = bp->cp_nr_pages; @@@ -3231,6 -3280,7 +3313,7 @@@ rc = bnxt_alloc_ring(bp, rmem); if (rc) { bnxt_free_ring(bp, rmem); + bnxt_free_cp_arrays(cpr); kfree(cpr); cpr = NULL; } @@@ -3663,9 -3713,15 +3746,15 @@@ void bnxt_set_ring_params(struct bnxt * if (jumbo_factor > agg_factor) agg_factor = jumbo_factor; } - agg_ring_size = ring_size * agg_factor; + if (agg_factor) { + if (ring_size > BNXT_MAX_RX_DESC_CNT_JUM_ENA) { + ring_size = BNXT_MAX_RX_DESC_CNT_JUM_ENA; + netdev_warn(bp->dev, "RX ring size reduced from %d to %d because the jumbo ring is now enabled\n", + bp->rx_ring_size, ring_size); + bp->rx_ring_size = ring_size; + } + agg_ring_size = ring_size * agg_factor;
- if (agg_ring_size) { bp->rx_agg_nr_pages = bnxt_calc_nr_ring_pages(agg_ring_size, RX_DESC_CNT); if (bp->rx_agg_nr_pages > MAX_RX_AGG_PAGES) { @@@ -4266,6 -4322,7 +4355,7 @@@ static void bnxt_free_mem(struct bnxt * bnxt_free_tx_rings(bp); bnxt_free_rx_rings(bp); bnxt_free_cp_rings(bp); + bnxt_free_all_cp_arrays(bp); bnxt_free_ntp_fltrs(bp, irq_re_init); if (irq_re_init) { bnxt_free_ring_stats(bp); @@@ -4386,6 -4443,10 +4476,10 @@@ static int bnxt_alloc_mem(struct bnxt * goto alloc_mem_err; }
+ rc = bnxt_alloc_all_cp_arrays(bp); + if (rc) + goto alloc_mem_err; + bnxt_init_ring_struct(bp);
rc = bnxt_alloc_rx_rings(bp); @@@ -7531,9 -7592,14 +7625,14 @@@ static int __bnxt_hwrm_ptp_qcfg(struct rc = -ENODEV; goto no_ptp; } - return 0; + rc = bnxt_ptp_init(bp); + if (!rc) + return 0; + + netdev_warn(bp->dev, "PTP initialization failed.\n");
no_ptp: + bnxt_ptp_clear(bp); kfree(ptp); bp->ptp_cfg = NULL; return rc; @@@ -7576,6 -7642,8 +7675,8 @@@ static int __bnxt_hwrm_func_qcaps(struc flags_ext = le32_to_cpu(resp->flags_ext); if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_EXT_HW_STATS_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED; + if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_PTP_PPS_SUPPORTED)) + bp->fw_cap |= BNXT_FW_CAP_PTP_PPS;
bp->tx_push_thresh = 0; if ((flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED) && @@@ -7613,6 -7681,7 +7714,7 @@@ if (flags & FUNC_QCAPS_RESP_FLAGS_PTP_SUPPORTED) { __bnxt_hwrm_ptp_qcfg(bp); } else { + bnxt_ptp_clear(bp); kfree(bp->ptp_cfg); bp->ptp_cfg = NULL; } @@@ -9161,9 -9230,10 +9263,9 @@@ static void bnxt_disable_napi(struct bn for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
+ napi_disable(&bp->bnapi[i]->napi); if (bp->bnapi[i]->rx_ring) cancel_work_sync(&cpr->dim.work); - - napi_disable(&bp->bnapi[i]->napi); } }
@@@ -9197,11 -9267,9 +9299,11 @@@ void bnxt_tx_disable(struct bnxt *bp if (bp->tx_ring) { for (i = 0; i < bp->tx_nr_rings; i++) { txr = &bp->tx_ring[i]; - txr->dev_state = BNXT_DEV_STATE_CLOSING; + WRITE_ONCE(txr->dev_state, BNXT_DEV_STATE_CLOSING); } } + /* Make sure napi polls see @dev_state change */ + synchronize_net(); /* Drop carrier first to prevent TX timeout */ netif_carrier_off(bp->dev); /* Stop all TX queues */ @@@ -9215,10 -9283,8 +9317,10 @@@ void bnxt_tx_enable(struct bnxt *bp
for (i = 0; i < bp->tx_nr_rings; i++) { txr = &bp->tx_ring[i]; - txr->dev_state = 0; + WRITE_ONCE(txr->dev_state, 0); } + /* Make sure napi polls see @dev_state change */ + synchronize_net(); netif_tx_wake_all_queues(bp->dev); if (bp->link_info.link_up) netif_carrier_on(bp->dev); @@@ -10316,15 -10382,9 +10418,9 @@@ static int bnxt_open(struct net_device if (rc) return rc;
- if (bnxt_ptp_init(bp)) { - netdev_warn(dev, "PTP initialization failed.\n"); - kfree(bp->ptp_cfg); - bp->ptp_cfg = NULL; - } rc = __bnxt_open_nic(bp, true, true); if (rc) { bnxt_hwrm_if_change(bp, false); - bnxt_ptp_clear(bp); } else { if (test_and_clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state)) { if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { @@@ -10415,7 -10475,6 +10511,6 @@@ static int bnxt_close(struct net_devic { struct bnxt *bp = netdev_priv(dev);
- bnxt_ptp_clear(bp); bnxt_hwmon_close(bp); bnxt_close_nic(bp, true, true); bnxt_hwrm_shutdown_link(bp); @@@ -10804,9 -10863,6 +10899,9 @@@ static bool bnxt_rfs_supported(struct b return true; return false; } + /* 212 firmware is broken for aRFS */ + if (BNXT_FW_MAJ(bp) == 212) + return false; if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp)) return true; if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) @@@ -11405,7 -11461,6 +11500,6 @@@ static void bnxt_fw_reset_close(struct bnxt_clear_int_mode(bp); pci_disable_device(bp->pdev); } - bnxt_ptp_clear(bp); __bnxt_close_nic(bp, true, false); bnxt_vf_reps_free(bp); bnxt_clear_int_mode(bp); @@@ -11441,13 -11496,20 +11535,20 @@@ static bool is_bnxt_fw_ok(struct bnxt * static void bnxt_force_fw_reset(struct bnxt *bp) { struct bnxt_fw_health *fw_health = bp->fw_health; + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; u32 wait_dsecs;
if (!test_bit(BNXT_STATE_OPEN, &bp->state) || test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) return;
- set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + if (ptp) { + spin_lock_bh(&ptp->ptp_lock); + set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + spin_unlock_bh(&ptp->ptp_lock); + } else { + set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + } bnxt_fw_reset_close(bp); wait_dsecs = fw_health->master_func_wait_dsecs; if (fw_health->master) { @@@ -11503,9 -11565,16 +11604,16 @@@ void bnxt_fw_reset(struct bnxt *bp bnxt_rtnl_lock_sp(bp); if (test_bit(BNXT_STATE_OPEN, &bp->state) && !test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; int n = 0, tmo;
- set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + if (ptp) { + spin_lock_bh(&ptp->ptp_lock); + set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + spin_unlock_bh(&ptp->ptp_lock); + } else { + set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + } if (bp->pf.active_vfs && !test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) n = bnxt_get_registered_vfs(bp); @@@ -12177,6 -12246,7 +12285,7 @@@ static void bnxt_fw_reset_task(struct w bnxt_reenable_sriov(bp); bnxt_vf_reps_alloc(bp); bnxt_vf_reps_open(bp); + bnxt_ptp_reapply_pps(bp); bnxt_dl_health_recovery_done(bp); bnxt_dl_health_status_update(bp, true); rtnl_unlock(); @@@ -12708,7 -12778,7 +12817,7 @@@ static const struct net_device_ops bnxt .ndo_stop = bnxt_close, .ndo_get_stats64 = bnxt_get_stats64, .ndo_set_rx_mode = bnxt_set_rx_mode, - .ndo_do_ioctl = bnxt_ioctl, + .ndo_eth_ioctl = bnxt_ioctl, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = bnxt_change_mac_addr, .ndo_change_mtu = bnxt_change_mtu, @@@ -12747,6 -12817,7 +12856,7 @@@ static void bnxt_remove_one(struct pci_ if (BNXT_PF(bp)) devlink_port_type_clear(&bp->dl_port);
+ bnxt_ptp_clear(bp); pci_disable_pcie_error_reporting(pdev); unregister_netdev(dev); clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); @@@ -13359,6 -13430,7 +13469,7 @@@ init_err_pci_clean bnxt_free_hwrm_short_cmd_req(bp); bnxt_free_hwrm_resources(bp); bnxt_ethtool_free(bp); + bnxt_ptp_clear(bp); kfree(bp->ptp_cfg); bp->ptp_cfg = NULL; kfree(bp->fw_health); diff --combined drivers/net/ethernet/broadcom/bnxt/bnxt.h index ba4e0fc38520,9c3324e76ff7..7b989b6e4f6e --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@@ -496,6 -496,16 +496,16 @@@ struct rx_tpa_end_cmp_ext !!((data1) & \ ASYNC_EVENT_CMPL_ERROR_RECOVERY_EVENT_DATA1_FLAGS_RECOVERY_ENABLED)
+ #define BNXT_EVENT_ERROR_REPORT_TYPE(data1) \ + (((data1) & \ + ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_MASK) >>\ + ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_SFT) + + #define BNXT_EVENT_INVALID_SIGNAL_DATA(data2) \ + (((data2) & \ + ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA2_PIN_ID_MASK) >>\ + ASYNC_EVENT_CMPL_ERROR_REPORT_INVALID_SIGNAL_EVENT_DATA2_PIN_ID_SFT) + struct nqe_cn { __le16 type; #define NQ_CN_TYPE_MASK 0x3fUL @@@ -586,15 -596,17 +596,17 @@@ #define MAX_TPA_SEGS_P5 0x3f
#if (BNXT_PAGE_SHIFT == 16) - #define MAX_RX_PAGES 1 + #define MAX_RX_PAGES_AGG_ENA 1 + #define MAX_RX_PAGES 4 #define MAX_RX_AGG_PAGES 4 #define MAX_TX_PAGES 1 - #define MAX_CP_PAGES 8 + #define MAX_CP_PAGES 16 #else - #define MAX_RX_PAGES 8 + #define MAX_RX_PAGES_AGG_ENA 8 + #define MAX_RX_PAGES 32 #define MAX_RX_AGG_PAGES 32 #define MAX_TX_PAGES 8 - #define MAX_CP_PAGES 64 + #define MAX_CP_PAGES 128 #endif
#define RX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct rx_bd)) @@@ -612,6 -624,7 +624,7 @@@ #define HW_CMPD_RING_SIZE (sizeof(struct tx_cmp) * CP_DESC_CNT)
#define BNXT_MAX_RX_DESC_CNT (RX_DESC_CNT * MAX_RX_PAGES - 1) + #define BNXT_MAX_RX_DESC_CNT_JUM_ENA (RX_DESC_CNT * MAX_RX_PAGES_AGG_ENA - 1) #define BNXT_MAX_RX_JUM_DESC_CNT (RX_DESC_CNT * MAX_RX_AGG_PAGES - 1) #define BNXT_MAX_TX_DESC_CNT (TX_DESC_CNT * MAX_TX_PAGES - 1)
@@@ -786,7 -799,6 +799,7 @@@ struct bnxt_tx_ring_info u16 tx_prod; u16 tx_cons; u16 txq_index; + u8 kick_pending; struct bnxt_db_info tx_db;
struct tx_bd *tx_desc_ring[MAX_TX_PAGES]; @@@ -963,11 -975,11 +976,11 @@@ struct bnxt_cp_ring_info struct dim dim;
union { - struct tx_cmp *cp_desc_ring[MAX_CP_PAGES]; - struct nqe_cn *nq_desc_ring[MAX_CP_PAGES]; + struct tx_cmp **cp_desc_ring; + struct nqe_cn **nq_desc_ring; };
- dma_addr_t cp_desc_mapping[MAX_CP_PAGES]; + dma_addr_t *cp_desc_mapping;
struct bnxt_stats_mem stats; u32 hw_stats_ctx_id; @@@ -1888,6 -1900,7 +1901,7 @@@ struct bnxt #define BNXT_FW_CAP_VLAN_RX_STRIP 0x01000000 #define BNXT_FW_CAP_VLAN_TX_INSERT 0x02000000 #define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED 0x04000000 + #define BNXT_FW_CAP_PTP_PPS 0x10000000 #define BNXT_FW_CAP_RING_MONITOR 0x40000000
#define BNXT_NEW_RM(bp) ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM) diff --combined drivers/net/ethernet/cirrus/Kconfig index d8af9e64dd1e,dac1764ba740..c51b5e043c5e --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@@ -6,7 -6,7 +6,7 @@@ config NET_VENDOR_CIRRUS bool "Cirrus devices" default y - depends on ISA || EISA || ARM || MAC || COMPILE_TEST + depends on ISA || EISA || ARM || MAC help If you have a network (Ethernet) card belonging to this class, say Y.
@@@ -18,9 -18,16 +18,16 @@@ if NET_VENDOR_CIRRUS
config CS89x0 - tristate "CS89x0 support" - depends on ISA || EISA || ARM + tristate + + config CS89x0_ISA + tristate "CS89x0 ISA driver support" + depends on HAS_IOPORT_MAP + depends on ISA depends on !PPC32 + depends on CS89x0_PLATFORM=n + select NETDEV_LEGACY_INIT + select CS89x0 help Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the file @@@ -30,15 -37,15 +37,15 @@@ will be called cs89x0.
config CS89x0_PLATFORM - bool "CS89x0 platform driver support" if HAS_IOPORT_MAP - default !HAS_IOPORT_MAP - depends on CS89x0 + tristate "CS89x0 platform driver support" + depends on ARM || COMPILE_TEST + select CS89x0 help - Say Y to compile the cs89x0 driver as a platform driver. This - makes this driver suitable for use on certain evaluation boards - such as the iMX21ADS. + Say Y to compile the cs89x0 platform driver. This makes this driver + suitable for use on certain evaluation boards such as the iMX21ADS.
- If you are unsure, say N. + To compile this driver as a module, choose M here. The module + will be called cs89x0.
config EP93XX_ETH tristate "EP93xx Ethernet support" diff --combined drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index 98cc0133c343,d260993ab2dc..1419c8dccea2 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@@ -41,14 -41,14 +41,14 @@@ static struct dpaa2_switch_fdb *dpaa2_s return NULL; }
- static struct dpaa2_switch_acl_tbl * - dpaa2_switch_acl_tbl_get_unused(struct ethsw_core *ethsw) + static struct dpaa2_switch_filter_block * + dpaa2_switch_filter_block_get_unused(struct ethsw_core *ethsw) { int i;
for (i = 0; i < ethsw->sw_attr.num_ifs; i++) - if (!ethsw->acls[i].in_use) - return ðsw->acls[i]; + if (!ethsw->filter_blocks[i].in_use) + return ðsw->filter_blocks[i]; return NULL; }
@@@ -594,12 -594,18 +594,18 @@@ static int dpaa2_switch_port_change_mtu return 0; }
- static int dpaa2_switch_port_carrier_state_sync(struct net_device *netdev) + static int dpaa2_switch_port_link_state_update(struct net_device *netdev) { struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct dpsw_link_state state; int err;
+ /* When we manage the MAC/PHY using phylink there is no need + * to manually update the netif_carrier. + */ + if (dpaa2_switch_port_is_type_phy(port_priv)) + return 0; + /* Interrupts are received even though no one issued an 'ifconfig up' * on the switch interface. Ignore these link state update interrupts */ @@@ -677,12 -683,14 +683,14 @@@ static int dpaa2_switch_port_open(struc struct ethsw_core *ethsw = port_priv->ethsw_data; int err;
- /* Explicitly set carrier off, otherwise - * netif_carrier_ok() will return true and cause 'ip link show' - * to report the LOWER_UP flag, even though the link - * notification wasn't even received. - */ - netif_carrier_off(netdev); + if (!dpaa2_switch_port_is_type_phy(port_priv)) { + /* Explicitly set carrier off, otherwise + * netif_carrier_ok() will return true and cause 'ip link show' + * to report the LOWER_UP flag, even though the link + * notification wasn't even received. + */ + netif_carrier_off(netdev); + }
err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0, port_priv->ethsw_data->dpsw_handle, @@@ -692,23 -700,12 +700,12 @@@ return err; }
- /* sync carrier state */ - err = dpaa2_switch_port_carrier_state_sync(netdev); - if (err) { - netdev_err(netdev, - "dpaa2_switch_port_carrier_state_sync err %d\n", err); - goto err_carrier_sync; - } - dpaa2_switch_enable_ctrl_if_napi(ethsw);
- return 0; + if (dpaa2_switch_port_is_type_phy(port_priv)) + phylink_start(port_priv->mac->phylink);
- err_carrier_sync: - dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx); - return err; + return 0; }
static int dpaa2_switch_port_stop(struct net_device *netdev) @@@ -717,6 -714,13 +714,13 @@@ struct ethsw_core *ethsw = port_priv->ethsw_data; int err;
+ if (dpaa2_switch_port_is_type_phy(port_priv)) { + phylink_stop(port_priv->mac->phylink); + } else { + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } + err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, port_priv->ethsw_data->dpsw_handle, port_priv->idx); @@@ -1127,28 -1131,28 +1131,28 @@@ err_exit }
static int - dpaa2_switch_setup_tc_cls_flower(struct dpaa2_switch_acl_tbl *acl_tbl, + dpaa2_switch_setup_tc_cls_flower(struct dpaa2_switch_filter_block *filter_block, struct flow_cls_offload *f) { switch (f->command) { case FLOW_CLS_REPLACE: - return dpaa2_switch_cls_flower_replace(acl_tbl, f); + return dpaa2_switch_cls_flower_replace(filter_block, f); case FLOW_CLS_DESTROY: - return dpaa2_switch_cls_flower_destroy(acl_tbl, f); + return dpaa2_switch_cls_flower_destroy(filter_block, f); default: return -EOPNOTSUPP; } }
static int - dpaa2_switch_setup_tc_cls_matchall(struct dpaa2_switch_acl_tbl *acl_tbl, + dpaa2_switch_setup_tc_cls_matchall(struct dpaa2_switch_filter_block *block, struct tc_cls_matchall_offload *f) { switch (f->command) { case TC_CLSMATCHALL_REPLACE: - return dpaa2_switch_cls_matchall_replace(acl_tbl, f); + return dpaa2_switch_cls_matchall_replace(block, f); case TC_CLSMATCHALL_DESTROY: - return dpaa2_switch_cls_matchall_destroy(acl_tbl, f); + return dpaa2_switch_cls_matchall_destroy(block, f); default: return -EOPNOTSUPP; } @@@ -1170,106 -1174,122 +1174,122 @@@ static int dpaa2_switch_port_setup_tc_b
static LIST_HEAD(dpaa2_switch_block_cb_list);
- static int dpaa2_switch_port_acl_tbl_bind(struct ethsw_port_priv *port_priv, - struct dpaa2_switch_acl_tbl *acl_tbl) + static int + dpaa2_switch_port_acl_tbl_bind(struct ethsw_port_priv *port_priv, + struct dpaa2_switch_filter_block *block) { struct ethsw_core *ethsw = port_priv->ethsw_data; struct net_device *netdev = port_priv->netdev; struct dpsw_acl_if_cfg acl_if_cfg; int err;
- if (port_priv->acl_tbl) + if (port_priv->filter_block) return -EINVAL;
acl_if_cfg.if_id[0] = port_priv->idx; acl_if_cfg.num_ifs = 1; err = dpsw_acl_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, - acl_tbl->id, &acl_if_cfg); + block->acl_id, &acl_if_cfg); if (err) { netdev_err(netdev, "dpsw_acl_add_if err %d\n", err); return err; }
- acl_tbl->ports |= BIT(port_priv->idx); - port_priv->acl_tbl = acl_tbl; + block->ports |= BIT(port_priv->idx); + port_priv->filter_block = block;
return 0; }
static int dpaa2_switch_port_acl_tbl_unbind(struct ethsw_port_priv *port_priv, - struct dpaa2_switch_acl_tbl *acl_tbl) + struct dpaa2_switch_filter_block *block) { struct ethsw_core *ethsw = port_priv->ethsw_data; struct net_device *netdev = port_priv->netdev; struct dpsw_acl_if_cfg acl_if_cfg; int err;
- if (port_priv->acl_tbl != acl_tbl) + if (port_priv->filter_block != block) return -EINVAL;
acl_if_cfg.if_id[0] = port_priv->idx; acl_if_cfg.num_ifs = 1; err = dpsw_acl_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, - acl_tbl->id, &acl_if_cfg); + block->acl_id, &acl_if_cfg); if (err) { netdev_err(netdev, "dpsw_acl_add_if err %d\n", err); return err; }
- acl_tbl->ports &= ~BIT(port_priv->idx); - port_priv->acl_tbl = NULL; + block->ports &= ~BIT(port_priv->idx); + port_priv->filter_block = NULL; return 0; }
static int dpaa2_switch_port_block_bind(struct ethsw_port_priv *port_priv, - struct dpaa2_switch_acl_tbl *acl_tbl) + struct dpaa2_switch_filter_block *block) { - struct dpaa2_switch_acl_tbl *old_acl_tbl = port_priv->acl_tbl; + struct dpaa2_switch_filter_block *old_block = port_priv->filter_block; int err;
+ /* Offload all the mirror entries found in the block on this new port + * joining it. + */ + err = dpaa2_switch_block_offload_mirror(block, port_priv); + if (err) + return err; + /* If the port is already bound to this ACL table then do nothing. This * can happen when this port is the first one to join a tc block */ - if (port_priv->acl_tbl == acl_tbl) + if (port_priv->filter_block == block) return 0;
- err = dpaa2_switch_port_acl_tbl_unbind(port_priv, old_acl_tbl); + err = dpaa2_switch_port_acl_tbl_unbind(port_priv, old_block); if (err) return err;
/* Mark the previous ACL table as being unused if this was the last * port that was using it. */ - if (old_acl_tbl->ports == 0) - old_acl_tbl->in_use = false; + if (old_block->ports == 0) + old_block->in_use = false;
- return dpaa2_switch_port_acl_tbl_bind(port_priv, acl_tbl); + return dpaa2_switch_port_acl_tbl_bind(port_priv, block); }
- static int dpaa2_switch_port_block_unbind(struct ethsw_port_priv *port_priv, - struct dpaa2_switch_acl_tbl *acl_tbl) + static int + dpaa2_switch_port_block_unbind(struct ethsw_port_priv *port_priv, + struct dpaa2_switch_filter_block *block) { struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpaa2_switch_acl_tbl *new_acl_tbl; + struct dpaa2_switch_filter_block *new_block; int err;
+ /* Unoffload all the mirror entries found in the block from the + * port leaving it. + */ + err = dpaa2_switch_block_unoffload_mirror(block, port_priv); + if (err) + return err; + /* We are the last port that leaves a block (an ACL table). * We'll continue to use this table. */ - if (acl_tbl->ports == BIT(port_priv->idx)) + if (block->ports == BIT(port_priv->idx)) return 0;
- err = dpaa2_switch_port_acl_tbl_unbind(port_priv, acl_tbl); + err = dpaa2_switch_port_acl_tbl_unbind(port_priv, block); if (err) return err;
- if (acl_tbl->ports == 0) - acl_tbl->in_use = false; + if (block->ports == 0) + block->in_use = false;
- new_acl_tbl = dpaa2_switch_acl_tbl_get_unused(ethsw); - new_acl_tbl->in_use = true; - return dpaa2_switch_port_acl_tbl_bind(port_priv, new_acl_tbl); + new_block = dpaa2_switch_filter_block_get_unused(ethsw); + new_block->in_use = true; + return dpaa2_switch_port_acl_tbl_bind(port_priv, new_block); }
static int dpaa2_switch_setup_tc_block_bind(struct net_device *netdev, @@@ -1277,7 -1297,7 +1297,7 @@@ { struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpaa2_switch_acl_tbl *acl_tbl; + struct dpaa2_switch_filter_block *filter_block; struct flow_block_cb *block_cb; bool register_block = false; int err; @@@ -1287,24 -1307,24 +1307,24 @@@ ethsw);
if (!block_cb) { - /* If the ACL table is not already known, then this port must - * be the first to join it. In this case, we can just continue - * to use our private table + /* If the filter block is not already known, then this port + * must be the first to join it. In this case, we can just + * continue to use our private table */ - acl_tbl = port_priv->acl_tbl; + filter_block = port_priv->filter_block;
block_cb = flow_block_cb_alloc(dpaa2_switch_port_setup_tc_block_cb_ig, - ethsw, acl_tbl, NULL); + ethsw, filter_block, NULL); if (IS_ERR(block_cb)) return PTR_ERR(block_cb);
register_block = true; } else { - acl_tbl = flow_block_cb_priv(block_cb); + filter_block = flow_block_cb_priv(block_cb); }
flow_block_cb_incref(block_cb); - err = dpaa2_switch_port_block_bind(port_priv, acl_tbl); + err = dpaa2_switch_port_block_bind(port_priv, filter_block); if (err) goto err_block_bind;
@@@ -1327,7 -1347,7 +1347,7 @@@ static void dpaa2_switch_setup_tc_block { struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpaa2_switch_acl_tbl *acl_tbl; + struct dpaa2_switch_filter_block *filter_block; struct flow_block_cb *block_cb; int err;
@@@ -1337,8 -1357,8 +1357,8 @@@ if (!block_cb) return;
- acl_tbl = flow_block_cb_priv(block_cb); - err = dpaa2_switch_port_block_unbind(port_priv, acl_tbl); + filter_block = flow_block_cb_priv(block_cb); + err = dpaa2_switch_port_block_unbind(port_priv, filter_block); if (!err && !flow_block_cb_decref(block_cb)) { flow_block_cb_remove(block_cb, f); list_del(&block_cb->driver_list); @@@ -1403,41 -1423,103 +1423,103 @@@ bool dpaa2_switch_port_dev_check(const return netdev->netdev_ops == &dpaa2_switch_port_ops; }
- static void dpaa2_switch_links_state_update(struct ethsw_core *ethsw) + static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv) { - int i; + struct fsl_mc_device *dpsw_port_dev, *dpmac_dev; + struct dpaa2_mac *mac; + int err;
- for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - dpaa2_switch_port_carrier_state_sync(ethsw->ports[i]->netdev); - dpaa2_switch_port_set_mac_addr(ethsw->ports[i]); + dpsw_port_dev = to_fsl_mc_device(port_priv->netdev->dev.parent); + dpmac_dev = fsl_mc_get_endpoint(dpsw_port_dev, port_priv->idx); + + if (PTR_ERR(dpmac_dev) == -EPROBE_DEFER) + return PTR_ERR(dpmac_dev); + + if (IS_ERR(dpmac_dev) || dpmac_dev->dev.type != &fsl_mc_bus_dpmac_type) + return 0; + + mac = kzalloc(sizeof(*mac), GFP_KERNEL); + if (!mac) + return -ENOMEM; + + mac->mc_dev = dpmac_dev; + mac->mc_io = port_priv->ethsw_data->mc_io; + mac->net_dev = port_priv->netdev; + + err = dpaa2_mac_open(mac); + if (err) + goto err_free_mac; + port_priv->mac = mac; + + if (dpaa2_switch_port_is_type_phy(port_priv)) { + err = dpaa2_mac_connect(mac); + if (err) { + netdev_err(port_priv->netdev, + "Error connecting to the MAC endpoint %pe\n", + ERR_PTR(err)); + goto err_close_mac; + } } + + return 0; + + err_close_mac: + dpaa2_mac_close(mac); + port_priv->mac = NULL; + err_free_mac: + kfree(mac); + return err; + } + + static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv) + { + if (dpaa2_switch_port_is_type_phy(port_priv)) + dpaa2_mac_disconnect(port_priv->mac); + + if (!dpaa2_switch_port_has_mac(port_priv)) + return; + + dpaa2_mac_close(port_priv->mac); + kfree(port_priv->mac); + port_priv->mac = NULL; }
static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) { struct device *dev = (struct device *)arg; struct ethsw_core *ethsw = dev_get_drvdata(dev); - - /* Mask the events and the if_id reserved bits to be cleared on read */ - u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; - int err; + struct ethsw_port_priv *port_priv; + u32 status = ~0; + int err, if_id;
err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, DPSW_IRQ_INDEX_IF, &status); if (err) { dev_err(dev, "Can't get irq status (err %d)\n", err); - - err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, 0xFFFFFFFF); - if (err) - dev_err(dev, "Can't clear irq status (err %d)\n", err); goto out; }
- if (status & DPSW_IRQ_EVENT_LINK_CHANGED) - dpaa2_switch_links_state_update(ethsw); + if_id = (status & 0xFFFF0000) >> 16; + port_priv = ethsw->ports[if_id]; + + if (status & DPSW_IRQ_EVENT_LINK_CHANGED) { + dpaa2_switch_port_link_state_update(port_priv->netdev); + dpaa2_switch_port_set_mac_addr(port_priv); + } + + if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) { + if (dpaa2_switch_port_has_mac(port_priv)) + dpaa2_switch_port_disconnect_mac(port_priv); + else + dpaa2_switch_port_connect_mac(port_priv); + }
out: + err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, status); + if (err) + dev_err(dev, "Can't clear irq status (err %d)\n", err); + return IRQ_HANDLED; }
@@@ -1889,8 -1971,12 +1971,12 @@@ static int dpaa2_switch_port_attr_set_e return notifier_from_errno(err); }
+ static struct notifier_block dpaa2_switch_port_switchdev_nb; + static struct notifier_block dpaa2_switch_port_switchdev_blocking_nb; + static int dpaa2_switch_port_bridge_join(struct net_device *netdev, - struct net_device *upper_dev) + struct net_device *upper_dev, + struct netlink_ext_ack *extack) { struct ethsw_port_priv *port_priv = netdev_priv(netdev); struct ethsw_core *ethsw = port_priv->ethsw_data; @@@ -1906,8 -1992,8 +1992,8 @@@
other_port_priv = netdev_priv(other_dev); if (other_port_priv->ethsw_data != port_priv->ethsw_data) { - netdev_err(netdev, - "Interface from a different DPSW is in the bridge already!\n"); + NL_SET_ERR_MSG_MOD(extack, + "Interface from a different DPSW is in the bridge already"); return -EINVAL; } } @@@ -1929,8 -2015,16 +2015,16 @@@ if (err) goto err_egress_flood;
+ err = switchdev_bridge_port_offload(netdev, netdev, NULL, + &dpaa2_switch_port_switchdev_nb, + &dpaa2_switch_port_switchdev_blocking_nb, + false, extack); + if (err) + goto err_switchdev_offload; + return 0;
+ err_switchdev_offload: err_egress_flood: dpaa2_switch_port_set_fdb(port_priv, NULL); return err; @@@ -1956,6 -2050,13 +2050,13 @@@ static int dpaa2_switch_port_restore_rx return dpaa2_switch_port_vlan_add(arg, vlan_proto, vid); }
+ static void dpaa2_switch_port_pre_bridge_leave(struct net_device *netdev) + { + switchdev_bridge_port_unoffload(netdev, NULL, + &dpaa2_switch_port_switchdev_nb, + &dpaa2_switch_port_switchdev_blocking_nb); + } + static int dpaa2_switch_port_bridge_leave(struct net_device *netdev) { struct ethsw_port_priv *port_priv = netdev_priv(netdev); @@@ -2029,6 -2130,28 +2130,28 @@@ static int dpaa2_switch_prevent_bridgin return 0; }
+ static int + dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev, + struct net_device *upper_dev, + struct netlink_ext_ack *extack) + { + int err; + + if (!br_vlan_enabled(upper_dev)) { + NL_SET_ERR_MSG_MOD(extack, "Cannot join a VLAN-unaware bridge"); + return -EOPNOTSUPP; + } + + err = dpaa2_switch_prevent_bridging_with_8021q_upper(netdev); + if (err) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot join a bridge while VLAN uppers are present"); + return 0; + } + + return 0; + } + static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) { @@@ -2049,25 -2172,23 +2172,23 @@@ if (!netif_is_bridge_master(upper_dev)) break;
- if (!br_vlan_enabled(upper_dev)) { - NL_SET_ERR_MSG_MOD(extack, "Cannot join a VLAN-unaware bridge"); - err = -EOPNOTSUPP; + err = dpaa2_switch_prechangeupper_sanity_checks(netdev, + upper_dev, + extack); + if (err) goto out; - }
- err = dpaa2_switch_prevent_bridging_with_8021q_upper(netdev); - if (err) { - NL_SET_ERR_MSG_MOD(extack, - "Cannot join a bridge while VLAN uppers are present"); - goto out; - } + if (!info->linking) + dpaa2_switch_port_pre_bridge_leave(netdev);
break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; if (netif_is_bridge_master(upper_dev)) { if (info->linking) - err = dpaa2_switch_port_bridge_join(netdev, upper_dev); + err = dpaa2_switch_port_bridge_join(netdev, + upper_dev, + extack); else err = dpaa2_switch_port_bridge_leave(netdev); } @@@ -2952,7 -3073,7 +3073,7 @@@ static int dpaa2_switch_port_trap_mac_a acl_entry.cfg.precedence = 0; acl_entry.cfg.result.action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
- return dpaa2_switch_acl_entry_add(port_priv->acl_tbl, &acl_entry); + return dpaa2_switch_acl_entry_add(port_priv->filter_block, &acl_entry); }
static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port) @@@ -2965,7 -3086,7 +3086,7 @@@ }; struct net_device *netdev = port_priv->netdev; struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpaa2_switch_acl_tbl *acl_tbl; + struct dpaa2_switch_filter_block *filter_block; struct dpsw_fdb_cfg fdb_cfg = {0}; struct dpsw_if_attr dpsw_if_attr; struct dpaa2_switch_fdb *fdb; @@@ -3020,14 -3141,15 +3141,15 @@@ return err; }
- acl_tbl = dpaa2_switch_acl_tbl_get_unused(ethsw); - acl_tbl->ethsw = ethsw; - acl_tbl->id = acl_tbl_id; - acl_tbl->in_use = true; - acl_tbl->num_rules = 0; - INIT_LIST_HEAD(&acl_tbl->entries); + filter_block = dpaa2_switch_filter_block_get_unused(ethsw); + filter_block->ethsw = ethsw; + filter_block->acl_id = acl_tbl_id; + filter_block->in_use = true; + filter_block->num_acl_rules = 0; + INIT_LIST_HEAD(&filter_block->acl_entries); + INIT_LIST_HEAD(&filter_block->mirror_entries);
- err = dpaa2_switch_port_acl_tbl_bind(port_priv, acl_tbl); + err = dpaa2_switch_port_acl_tbl_bind(port_priv, filter_block); if (err) return err;
@@@ -3038,30 -3160,26 +3160,30 @@@ return err; }
-static void dpaa2_switch_takedown(struct fsl_mc_device *sw_dev) +static void dpaa2_switch_ctrl_if_teardown(struct ethsw_core *ethsw) +{ + dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); + dpaa2_switch_free_dpio(ethsw); + dpaa2_switch_destroy_rings(ethsw); + dpaa2_switch_drain_bp(ethsw); + dpaa2_switch_free_dpbp(ethsw); +} + +static void dpaa2_switch_teardown(struct fsl_mc_device *sw_dev) { struct device *dev = &sw_dev->dev; struct ethsw_core *ethsw = dev_get_drvdata(dev); int err;
+ dpaa2_switch_ctrl_if_teardown(ethsw); + + destroy_workqueue(ethsw->workqueue); + err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); if (err) dev_warn(dev, "dpsw_close err %d\n", err); }
-static void dpaa2_switch_ctrl_if_teardown(struct ethsw_core *ethsw) -{ - dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); - dpaa2_switch_free_dpio(ethsw); - dpaa2_switch_destroy_rings(ethsw); - dpaa2_switch_drain_bp(ethsw); - dpaa2_switch_free_dpbp(ethsw); -} - static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev) { struct ethsw_port_priv *port_priv; @@@ -3072,6 -3190,8 +3194,6 @@@ dev = &sw_dev->dev; ethsw = dev_get_drvdata(dev);
- dpaa2_switch_ctrl_if_teardown(ethsw); - dpaa2_switch_teardown_irqs(sw_dev);
dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); @@@ -3079,14 -3199,17 +3201,15 @@@ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { port_priv = ethsw->ports[i]; unregister_netdev(port_priv->netdev); + dpaa2_switch_port_disconnect_mac(port_priv); free_netdev(port_priv->netdev); }
kfree(ethsw->fdbs); - kfree(ethsw->acls); + kfree(ethsw->filter_blocks); kfree(ethsw->ports);
- dpaa2_switch_takedown(sw_dev); - - destroy_workqueue(ethsw->workqueue); + dpaa2_switch_teardown(sw_dev);
fsl_mc_portal_free(ethsw->mc_io);
@@@ -3156,6 -3279,10 +3279,10 @@@ static int dpaa2_switch_probe_port(stru goto err_port_probe; port_priv->learn_ena = false;
+ err = dpaa2_switch_port_connect_mac(port_priv); + if (err) + goto err_port_probe; + return 0;
err_port_probe: @@@ -3199,7 -3326,7 +3326,7 @@@ static int dpaa2_switch_probe(struct fs GFP_KERNEL); if (!(ethsw->ports)) { err = -ENOMEM; - goto err_takedown; + goto err_teardown; }
ethsw->fdbs = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->fdbs), @@@ -3209,9 -3336,10 +3336,10 @@@ goto err_free_ports; }
- ethsw->acls = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->acls), - GFP_KERNEL); - if (!ethsw->acls) { + ethsw->filter_blocks = kcalloc(ethsw->sw_attr.num_ifs, + sizeof(*ethsw->filter_blocks), + GFP_KERNEL); + if (!ethsw->filter_blocks) { err = -ENOMEM; goto err_free_fdbs; } @@@ -3231,17 -3359,16 +3359,16 @@@ ðsw->fq[i].napi, dpaa2_switch_poll, NAPI_POLL_WEIGHT);
- err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle); - if (err) { - dev_err(ethsw->dev, "dpsw_enable err %d\n", err); - goto err_free_netdev; - } - /* Setup IRQs */ err = dpaa2_switch_setup_irqs(sw_dev); if (err) goto err_stop;
+ /* By convention, if the mirror port is equal to the number of switch + * interfaces, then mirroring of any kind is disabled. + */ + ethsw->mirror_port = ethsw->sw_attr.num_ifs; + /* Register the netdev only when the entire setup is done and the * switch port interfaces are ready to receive traffic */ @@@ -3264,14 -3391,14 +3391,14 @@@ err_stop err_free_netdev: for (i--; i >= 0; i--) free_netdev(ethsw->ports[i]->netdev); - kfree(ethsw->acls); + kfree(ethsw->filter_blocks); err_free_fdbs: kfree(ethsw->fdbs); err_free_ports: kfree(ethsw->ports);
-err_takedown: - dpaa2_switch_takedown(sw_dev); +err_teardown: + dpaa2_switch_teardown(sw_dev);
err_free_cmdport: fsl_mc_portal_free(ethsw->mc_io); diff --combined drivers/net/ethernet/intel/iavf/iavf.h index 90793b36126e,b351ad653d12..68c80f04113c --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@@ -136,7 -136,6 +136,7 @@@ struct iavf_q_vector struct iavf_mac_filter { struct list_head list; u8 macaddr[ETH_ALEN]; + bool is_new_mac; /* filter is new, wait for PF decision */ bool remove; /* filter needs to be removed */ bool add; /* filter needs to be added */ }; @@@ -186,12 -185,6 +186,6 @@@ enum iavf_state_t __IAVF_RUNNING, /* opened, working */ };
- enum iavf_critical_section_t { - __IAVF_IN_CRITICAL_TASK, /* cannot be interrupted */ - __IAVF_IN_CLIENT_TASK, - __IAVF_IN_REMOVE_TASK, /* device being removed */ - }; - #define IAVF_CLOUD_FIELD_OMAC 0x01 #define IAVF_CLOUD_FIELD_IMAC 0x02 #define IAVF_CLOUD_FIELD_IVLAN 0x04 @@@ -236,6 -229,9 +230,9 @@@ struct iavf_adapter struct iavf_q_vector *q_vectors; struct list_head vlan_filter_list; struct list_head mac_filter_list; + struct mutex crit_lock; + struct mutex client_lock; + struct mutex remove_lock; /* Lock to protect accesses to MAC and VLAN lists */ spinlock_t mac_vlan_list_lock; char misc_vector_name[IFNAMSIZ + 9]; diff --combined drivers/net/ethernet/intel/iavf/iavf_main.c index 606a01ce4073,197789167a49..23762a7ef740 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@@ -131,6 -131,27 +131,27 @@@ enum iavf_status iavf_free_virt_mem_d(s return 0; }
+ /** + * iavf_lock_timeout - try to lock mutex but give up after timeout + * @lock: mutex that should be locked + * @msecs: timeout in msecs + * + * Returns 0 on success, negative on failure + **/ + static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs) + { + unsigned int wait, delay = 10; + + for (wait = 0; wait < msecs; wait += delay) { + if (mutex_trylock(lock)) + return 0; + + msleep(delay); + } + + return -1; + } + /** * iavf_schedule_reset - Set the flags and schedule a reset event * @adapter: board private structure @@@ -751,7 -772,6 +772,7 @@@ struct iavf_mac_filter *iavf_add_filter
list_add_tail(&f->list, &adapter->mac_filter_list); f->add = true; + f->is_new_mac = true; adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; } else { f->remove = false; @@@ -1916,7 -1936,7 +1937,7 @@@ static void iavf_watchdog_task(struct w struct iavf_hw *hw = &adapter->hw; u32 reg_val;
- if (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section)) + if (!mutex_trylock(&adapter->crit_lock)) goto restart_watchdog;
if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) @@@ -1934,8 -1954,7 +1955,7 @@@ adapter->state = __IAVF_STARTUP; adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED; queue_delayed_work(iavf_wq, &adapter->init_task, 10); - clear_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); /* Don't reschedule the watchdog, since we've restarted * the init task. When init_task contacts the PF and * gets everything set up again, it'll restart the @@@ -1945,14 -1964,13 +1965,13 @@@ } adapter->aq_required = 0; adapter->current_op = VIRTCHNL_OP_UNKNOWN; - clear_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); queue_delayed_work(iavf_wq, &adapter->watchdog_task, msecs_to_jiffies(10)); goto watchdog_done; case __IAVF_RESETTING: - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2); return; case __IAVF_DOWN: @@@ -1975,7 -1993,7 +1994,7 @@@ } break; case __IAVF_REMOVE: - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); return; default: goto restart_watchdog; @@@ -1984,7 -2002,6 +2003,6 @@@ /* check for hw reset */ reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK; if (!reg_val) { - adapter->state = __IAVF_RESETTING; adapter->flags |= IAVF_FLAG_RESET_PENDING; adapter->aq_required = 0; adapter->current_op = VIRTCHNL_OP_UNKNOWN; @@@ -1998,7 -2015,7 +2016,7 @@@ watchdog_done if (adapter->state == __IAVF_RUNNING || adapter->state == __IAVF_COMM_FAILED) iavf_detect_recover_hung(&adapter->vsi); - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); restart_watchdog: if (adapter->aq_required) queue_delayed_work(iavf_wq, &adapter->watchdog_task, @@@ -2062,7 -2079,7 +2080,7 @@@ static void iavf_disable_vf(struct iavf memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE); iavf_shutdown_adminq(&adapter->hw); adapter->netdev->flags &= ~IFF_UP; - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); adapter->flags &= ~IAVF_FLAG_RESET_PENDING; adapter->state = __IAVF_DOWN; wake_up(&adapter->down_waitqueue); @@@ -2095,11 -2112,14 +2113,14 @@@ static void iavf_reset_task(struct work /* When device is being removed it doesn't make sense to run the reset * task, just return in such a case. */ - if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) + if (mutex_is_locked(&adapter->remove_lock)) return;
- while (test_and_set_bit(__IAVF_IN_CLIENT_TASK, - &adapter->crit_section)) + if (iavf_lock_timeout(&adapter->crit_lock, 200)) { + schedule_work(&adapter->reset_task); + return; + } + while (!mutex_trylock(&adapter->client_lock)) usleep_range(500, 1000); if (CLIENT_ENABLED(adapter)) { adapter->flags &= ~(IAVF_FLAG_CLIENT_NEEDS_OPEN | @@@ -2151,7 -2171,7 +2172,7 @@@ dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", reg_val); iavf_disable_vf(adapter); - clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); + mutex_unlock(&adapter->client_lock); return; /* Do not attempt to reinit. It's dead, Jim. */ }
@@@ -2278,13 -2298,13 +2299,13 @@@ continue_reset adapter->state = __IAVF_DOWN; wake_up(&adapter->down_waitqueue); } - clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->client_lock); + mutex_unlock(&adapter->crit_lock);
return; reset_err: - clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->client_lock); + mutex_unlock(&adapter->crit_lock); dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); iavf_close(netdev); } @@@ -2312,6 -2332,8 +2333,8 @@@ static void iavf_adminq_task(struct wor if (!event.msg_buf) goto out;
+ if (iavf_lock_timeout(&adapter->crit_lock, 200)) + goto freedom; do { ret = iavf_clean_arq_element(hw, &event, &pending); v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high); @@@ -2325,6 -2347,7 +2348,7 @@@ if (pending != 0) memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE); } while (pending); + mutex_unlock(&adapter->crit_lock);
if ((adapter->flags & (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) || @@@ -2391,7 -2414,7 +2415,7 @@@ static void iavf_client_task(struct wor * later. */
- if (test_and_set_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section)) + if (!mutex_trylock(&adapter->client_lock)) return;
if (adapter->flags & IAVF_FLAG_SERVICE_CLIENT_REQUESTED) { @@@ -2414,7 -2437,7 +2438,7 @@@ adapter->flags &= ~IAVF_FLAG_CLIENT_NEEDS_OPEN; } out: - clear_bit(__IAVF_IN_CLIENT_TASK, &adapter->crit_section); + mutex_unlock(&adapter->client_lock); }
/** @@@ -3017,8 -3040,7 +3041,7 @@@ static int iavf_configure_clsflower(str if (!filter) return -ENOMEM;
- while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section)) { + while (!mutex_trylock(&adapter->crit_lock)) { if (--count == 0) goto err; udelay(1); @@@ -3049,7 -3071,7 +3072,7 @@@ err if (err) kfree(filter);
- clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock); return err; }
@@@ -3196,8 -3218,7 +3219,7 @@@ static int iavf_open(struct net_device return -EIO; }
- while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section)) + while (!mutex_trylock(&adapter->crit_lock)) usleep_range(500, 1000);
if (adapter->state != __IAVF_DOWN) { @@@ -3232,7 -3253,7 +3254,7 @@@
iavf_irq_enable(adapter, true);
- clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock);
return 0;
@@@ -3244,7 -3265,7 +3266,7 @@@ err_setup_rx err_setup_tx: iavf_free_all_tx_resources(adapter); err_unlock: - clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock);
return err; } @@@ -3268,8 -3289,7 +3290,7 @@@ static int iavf_close(struct net_devic if (adapter->state <= __IAVF_DOWN_PENDING) return 0;
- while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section)) + while (!mutex_trylock(&adapter->crit_lock)) usleep_range(500, 1000);
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); @@@ -3280,7 -3300,7 +3301,7 @@@ adapter->state = __IAVF_DOWN_PENDING; iavf_free_traffic_irqs(adapter);
- clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock);
/* We explicitly don't free resources here because the hardware is * still active and can DMA into memory. Resources are cleared in @@@ -3629,6 -3649,10 +3650,10 @@@ static void iavf_init_task(struct work_ init_task.work); struct iavf_hw *hw = &adapter->hw;
+ if (iavf_lock_timeout(&adapter->crit_lock, 5000)) { + dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__); + return; + } switch (adapter->state) { case __IAVF_STARTUP: if (iavf_startup(adapter) < 0) @@@ -3641,14 -3665,14 +3666,14 @@@ case __IAVF_INIT_GET_RESOURCES: if (iavf_init_get_resources(adapter) < 0) goto init_failed; - return; + goto out; default: goto init_failed; }
queue_delayed_work(iavf_wq, &adapter->init_task, msecs_to_jiffies(30)); - return; + goto out; init_failed: if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) { dev_err(&adapter->pdev->dev, @@@ -3657,9 -3681,11 +3682,11 @@@ iavf_shutdown_adminq(hw); adapter->state = __IAVF_STARTUP; queue_delayed_work(iavf_wq, &adapter->init_task, HZ * 5); - return; + goto out; } queue_delayed_work(iavf_wq, &adapter->init_task, HZ); + out: + mutex_unlock(&adapter->crit_lock); }
/** @@@ -3676,9 -3702,12 +3703,12 @@@ static void iavf_shutdown(struct pci_de if (netif_running(netdev)) iavf_close(netdev);
+ if (iavf_lock_timeout(&adapter->crit_lock, 5000)) + dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__); /* Prevent the watchdog from running. */ adapter->state = __IAVF_REMOVE; adapter->aq_required = 0; + mutex_unlock(&adapter->crit_lock);
#ifdef CONFIG_PM pci_save_state(pdev); @@@ -3772,6 -3801,9 +3802,9 @@@ static int iavf_probe(struct pci_dev *p /* set up the locks for the AQ, do this only once in probe * and destroy them only once in remove */ + mutex_init(&adapter->crit_lock); + mutex_init(&adapter->client_lock); + mutex_init(&adapter->remove_lock); mutex_init(&hw->aq.asq_mutex); mutex_init(&hw->aq.arq_mutex);
@@@ -3823,8 -3855,7 +3856,7 @@@ static int __maybe_unused iavf_suspend(
netif_device_detach(netdev);
- while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK, - &adapter->crit_section)) + while (!mutex_trylock(&adapter->crit_lock)) usleep_range(500, 1000);
if (netif_running(netdev)) { @@@ -3835,7 -3866,7 +3867,7 @@@ iavf_free_misc_irq(adapter); iavf_reset_interrupt_capability(adapter);
- clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section); + mutex_unlock(&adapter->crit_lock);
return 0; } @@@ -3897,7 -3928,7 +3929,7 @@@ static void iavf_remove(struct pci_dev struct iavf_hw *hw = &adapter->hw; int err; /* Indicate we are in remove and not to run reset_task */ - set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section); + mutex_lock(&adapter->remove_lock); cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); cancel_delayed_work_sync(&adapter->client_task); @@@ -3912,10 -3943,6 +3944,6 @@@ err); }
- /* Shut down all the garbage mashers on the detention level */ - adapter->state = __IAVF_REMOVE; - adapter->aq_required = 0; - adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; iavf_request_reset(adapter); msleep(50); /* If the FW isn't responding, kick it once, but only once. */ @@@ -3923,6 -3950,13 +3951,13 @@@ iavf_request_reset(adapter); msleep(50); } + if (iavf_lock_timeout(&adapter->crit_lock, 5000)) + dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__); + + /* Shut down all the garbage mashers on the detention level */ + adapter->state = __IAVF_REMOVE; + adapter->aq_required = 0; + adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; iavf_free_all_tx_resources(adapter); iavf_free_all_rx_resources(adapter); iavf_misc_irq_disable(adapter); @@@ -3942,6 -3976,11 +3977,11 @@@ /* destroy the locks only once, here */ mutex_destroy(&hw->aq.arq_mutex); mutex_destroy(&hw->aq.asq_mutex); + mutex_destroy(&adapter->client_lock); + mutex_unlock(&adapter->crit_lock); + mutex_destroy(&adapter->crit_lock); + mutex_unlock(&adapter->remove_lock); + mutex_destroy(&adapter->remove_lock);
iounmap(hw->hw_addr); pci_release_regions(pdev); diff --combined drivers/net/ethernet/intel/ice/ice_devlink.c index 7fe6e8ea39f0,8c863d64930b..14afce82ef63 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@@ -42,9 -42,7 +42,9 @@@ static int ice_info_pba(struct ice_pf *
status = ice_read_pba_string(hw, (u8 *)ctx->buf, sizeof(ctx->buf)); if (status) - return -EIO; + /* We failed to locate the PBA, so just skip this entry */ + dev_dbg(ice_pf_to_dev(pf), "Failed to read Product Board Assembly string, status %s\n", + ice_stat_str(status));
return 0; } @@@ -477,7 -475,7 +477,7 @@@ struct ice_pf *ice_allocate_pf(struct d { struct devlink *devlink;
- devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf)); + devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf), dev); if (!devlink) return NULL;
@@@ -504,7 -502,7 +504,7 @@@ int ice_devlink_register(struct ice_pf struct device *dev = ice_pf_to_dev(pf); int err;
- err = devlink_register(devlink, dev); + err = devlink_register(devlink); if (err) { dev_err(dev, "devlink registration failed: %d\n", err); return err; diff --combined drivers/net/ethernet/mscc/ocelot.c index 2948d731a1c1,5209650fd25f..8ec194178aa2 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@@ -377,7 -377,7 +377,7 @@@ static u32 ocelot_read_eq_avail(struct return ocelot_read_rix(ocelot, QSYS_SW_STATUS, port); }
- int ocelot_port_flush(struct ocelot *ocelot, int port) + static int ocelot_port_flush(struct ocelot *ocelot, int port) { unsigned int pause_ena; int err, val; @@@ -429,63 -429,118 +429,118 @@@
return err; } - EXPORT_SYMBOL(ocelot_port_flush);
- void ocelot_adjust_link(struct ocelot *ocelot, int port, - struct phy_device *phydev) + void ocelot_phylink_mac_link_down(struct ocelot *ocelot, int port, + unsigned int link_an_mode, + phy_interface_t interface, + unsigned long quirks) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - int speed, mode = 0; + int err; + + ocelot_port_rmwl(ocelot_port, 0, DEV_MAC_ENA_CFG_RX_ENA, + DEV_MAC_ENA_CFG); + + ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); + + err = ocelot_port_flush(ocelot, port); + if (err) + dev_err(ocelot->dev, "failed to flush port %d: %d\n", + port, err); + + /* Put the port in reset. */ + if (interface != PHY_INTERFACE_MODE_QSGMII || + !(quirks & OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP)) + ocelot_port_rmwl(ocelot_port, + DEV_CLOCK_CFG_MAC_TX_RST | + DEV_CLOCK_CFG_MAC_TX_RST, + DEV_CLOCK_CFG_MAC_TX_RST | + DEV_CLOCK_CFG_MAC_TX_RST, + DEV_CLOCK_CFG); + } + EXPORT_SYMBOL_GPL(ocelot_phylink_mac_link_down); + + void ocelot_phylink_mac_link_up(struct ocelot *ocelot, int port, + struct phy_device *phydev, + unsigned int link_an_mode, + phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause, + unsigned long quirks) + { + struct ocelot_port *ocelot_port = ocelot->ports[port]; + int mac_speed, mode = 0; + u32 mac_fc_cfg; + + /* The MAC might be integrated in systems where the MAC speed is fixed + * and it's the PCS who is performing the rate adaptation, so we have + * to write "1000Mbps" into the LINK_SPEED field of DEV_CLOCK_CFG + * (which is also its default value). + */ + if ((quirks & OCELOT_QUIRK_PCS_PERFORMS_RATE_ADAPTATION) || + speed == SPEED_1000) { + mac_speed = OCELOT_SPEED_1000; + mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + } else if (speed == SPEED_2500) { + mac_speed = OCELOT_SPEED_2500; + mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + } else if (speed == SPEED_100) { + mac_speed = OCELOT_SPEED_100; + } else { + mac_speed = OCELOT_SPEED_10; + } + + if (duplex == DUPLEX_FULL) + mode |= DEV_MAC_MODE_CFG_FDX_ENA;
- switch (phydev->speed) { + ocelot_port_writel(ocelot_port, mode, DEV_MAC_MODE_CFG); + + /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and + * PORT_RST bits in DEV_CLOCK_CFG. + */ + ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(mac_speed), + DEV_CLOCK_CFG); + + switch (speed) { case SPEED_10: - speed = OCELOT_SPEED_10; + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(OCELOT_SPEED_10); break; case SPEED_100: - speed = OCELOT_SPEED_100; + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(OCELOT_SPEED_100); break; case SPEED_1000: - speed = OCELOT_SPEED_1000; - mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; - break; case SPEED_2500: - speed = OCELOT_SPEED_2500; - mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(OCELOT_SPEED_1000); break; default: - dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n", - port, phydev->speed); + dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", + port, speed); return; }
- phy_print_status(phydev); - - if (!phydev->link) - return; - - /* Only full duplex supported for now */ - ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA | - mode, DEV_MAC_MODE_CFG); - - /* Disable HDX fast control */ - ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS, - DEV_PORT_MISC); + /* Handle RX pause in all cases, with 2500base-X this is used for rate + * adaptation. + */ + mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
- /* SGMII only for now */ - ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA, - PCS1G_MODE_CFG); - ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); + if (tx_pause) + mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | + SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | + SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | + SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
- /* Enable PCS */ - ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); + /* Flow control. Link speed is only used here to evaluate the time + * specification in incoming pause frames. + */ + ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
- /* No aneg on SGMII */ - ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG); + ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
- /* No loopback */ - ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); + ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_ENA, tx_pause);
- /* Enable MAC module */ + /* Undo the effects of ocelot_phylink_mac_link_down: + * enable MAC module + */ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
@@@ -502,39 -557,8 +557,8 @@@ /* Core: Enable port for frame transfer */ ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 1); - - /* Flow control */ - ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | - SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA | - SYS_MAC_FC_CFG_ZERO_PAUSE_ENA | - SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | - SYS_MAC_FC_CFG_FC_LINK_SPEED(speed), - SYS_MAC_FC_CFG, port); - ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); - } - EXPORT_SYMBOL(ocelot_adjust_link); - - void ocelot_port_enable(struct ocelot *ocelot, int port, - struct phy_device *phy) - { - /* Enable receiving frames on the port, and activate auto-learning of - * MAC addresses. - */ - ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | - ANA_PORT_PORT_CFG_RECV_ENA | - ANA_PORT_PORT_CFG_PORTID_VAL(port), - ANA_PORT_PORT_CFG, port); - } - EXPORT_SYMBOL(ocelot_port_enable); - - void ocelot_port_disable(struct ocelot *ocelot, int port) - { - struct ocelot_port *ocelot_port = ocelot->ports[port]; - - ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); - ocelot_fields_write(ocelot, port, QSYS_SWITCH_PORT_MODE_PORT_ENA, 0); } - EXPORT_SYMBOL(ocelot_port_disable); + EXPORT_SYMBOL_GPL(ocelot_phylink_mac_link_up);
static void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port, struct sk_buff *clone) @@@ -1334,7 -1358,6 +1358,7 @@@ void ocelot_apply_bridge_fwd_mask(struc struct net_device *bond = ocelot_port->bond;
mask = ocelot_get_bridge_fwd_mask(ocelot, bridge); + mask |= cpu_fwd_mask; mask &= ~BIT(port); if (bond) { mask &= ~ocelot_get_bond_mask(ocelot, bond, @@@ -1957,6 -1980,15 +1981,15 @@@ void ocelot_init_port(struct ocelot *oc /* Disable source address learning for standalone mode */ ocelot_port_set_learning(ocelot, port, false);
+ /* Set the port's initial logical port ID value, enable receiving + * frames on it, and configure the MAC address learning type to + * automatic. + */ + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | + ANA_PORT_PORT_CFG_RECV_ENA | + ANA_PORT_PORT_CFG_PORTID_VAL(port), + ANA_PORT_PORT_CFG, port); + /* Enable vcap lookups */ ocelot_vcap_enable(ocelot, port); } diff --combined drivers/net/ethernet/smsc/Kconfig index 6571a6a90c1a,72e42a868346..30573013d2ed --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@@ -23,6 -23,7 +23,7 @@@ config SMC919 tristate "SMC 9194 support" depends on ISA select CRC32 + select NETDEV_LEGACY_INIT help This is support for the SMC9xxx based Ethernet cards. Choose this option if you have a DELL laptop with the docking station, or @@@ -37,6 -38,7 +38,6 @@@ config SMC91 tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on !OF || GPIOLIB depends on ARM || ARM64 || ATARI_ETHERNAT || COLDFIRE || \ MIPS || NIOS2 || SUPERH || XTENSA || H8300 || COMPILE_TEST help diff --combined drivers/net/usb/pegasus.c index 9f9dd0de33cb,36dafcb3d04a..6a92a3fef75e --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@@ -446,7 -446,7 +446,7 @@@ static int enable_net_traffic(struct ne write_mii_word(pegasus, 0, 0x1b, &auxmode); }
- return 0; + return ret; fail: netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); return ret; @@@ -835,7 -835,7 +835,7 @@@ static int pegasus_open(struct net_devi if (!pegasus->rx_skb) goto exit;
- res = set_registers(pegasus, EthID, 6, net->dev_addr); + set_registers(pegasus, EthID, 6, net->dev_addr);
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), @@@ -1001,7 -1001,8 +1001,8 @@@ static const struct ethtool_ops ops = .set_link_ksettings = pegasus_set_link_ksettings, };
- static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) + static int pegasus_siocdevprivate(struct net_device *net, struct ifreq *rq, + void __user *udata, int cmd) { __u16 *data = (__u16 *) &rq->ifr_ifru; pegasus_t *pegasus = netdev_priv(net); @@@ -1269,7 -1270,7 +1270,7 @@@ static int pegasus_resume(struct usb_in static const struct net_device_ops pegasus_netdev_ops = { .ndo_open = pegasus_open, .ndo_stop = pegasus_close, - .ndo_do_ioctl = pegasus_ioctl, + .ndo_siocdevprivate = pegasus_siocdevprivate, .ndo_start_xmit = pegasus_start_xmit, .ndo_set_rx_mode = pegasus_set_multicast, .ndo_tx_timeout = pegasus_tx_timeout, diff --combined drivers/net/usb/r8152.c index 79832374f78d,d7fbc81b518a..aa66671c484d --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@@ -3955,28 -3955,17 +3955,28 @@@ static void rtl_clear_bp(struct r8152 * case RTL_VER_06: ocp_write_byte(tp, type, PLA_BP_EN, 0); break; + case RTL_VER_14: + ocp_write_word(tp, type, USB_BP2_EN, 0); + + ocp_write_word(tp, type, USB_BP_8, 0); + ocp_write_word(tp, type, USB_BP_9, 0); + ocp_write_word(tp, type, USB_BP_10, 0); + ocp_write_word(tp, type, USB_BP_11, 0); + ocp_write_word(tp, type, USB_BP_12, 0); + ocp_write_word(tp, type, USB_BP_13, 0); + ocp_write_word(tp, type, USB_BP_14, 0); + ocp_write_word(tp, type, USB_BP_15, 0); + break; case RTL_VER_08: case RTL_VER_09: case RTL_VER_10: case RTL_VER_11: case RTL_VER_12: case RTL_VER_13: - case RTL_VER_14: case RTL_VER_15: default: if (type == MCU_TYPE_USB) { - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0);
ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0); ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0); @@@ -4342,6 -4331,7 +4342,6 @@@ static bool rtl8152_is_fw_mac_ok(struc case RTL_VER_11: case RTL_VER_12: case RTL_VER_13: - case RTL_VER_14: case RTL_VER_15: fw_reg = 0xf800; bp_ba_addr = PLA_BP_BA; @@@ -4349,13 -4339,6 +4349,13 @@@ bp_start = PLA_BP_0; max_bp = 8; break; + case RTL_VER_14: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = USB_BP2_EN; + bp_start = PLA_BP_0; + max_bp = 16; + break; default: goto out; } @@@ -9190,7 -9173,7 +9190,7 @@@ static int rtl8152_change_mtu(struct ne static const struct net_device_ops rtl8152_netdev_ops = { .ndo_open = rtl8152_open, .ndo_stop = rtl8152_close, - .ndo_do_ioctl = rtl8152_ioctl, + .ndo_eth_ioctl = rtl8152_ioctl, .ndo_start_xmit = rtl8152_start_xmit, .ndo_tx_timeout = rtl8152_tx_timeout, .ndo_set_features = rtl8152_set_features, diff --combined drivers/net/virtio_net.c index eee493685aad,2e42210a6503..c8c9ad7ca2b5 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@@ -63,7 -63,7 +63,7 @@@ static const unsigned long guest_offloa VIRTIO_NET_F_GUEST_CSUM };
-#define GUEST_OFFLOAD_LRO_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ +#define GUEST_OFFLOAD_GRO_HW_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \ (1ULL << VIRTIO_NET_F_GUEST_ECN) | \ (1ULL << VIRTIO_NET_F_GUEST_UFO)) @@@ -380,7 -380,7 +380,7 @@@ static struct sk_buff *page_to_skb(stru struct page *page, unsigned int offset, unsigned int len, unsigned int truesize, bool hdr_valid, unsigned int metasize, - bool whole_page) + unsigned int headroom) { struct sk_buff *skb; struct virtio_net_hdr_mrg_rxbuf *hdr; @@@ -398,28 -398,16 +398,16 @@@ else hdr_padded_len = sizeof(struct padded_vnet_hdr);
- /* If whole_page, there is an offset between the beginning of the + /* If headroom is not 0, there is an offset between the beginning of the * data and the allocated space, otherwise the data and the allocated * space are aligned. * * Buffers with headroom use PAGE_SIZE as alloc size, see * add_recvbuf_mergeable() + get_mergeable_buf_len() */ - if (whole_page) { - /* Buffers with whole_page use PAGE_SIZE as alloc size, - * see add_recvbuf_mergeable() + get_mergeable_buf_len() - */ - truesize = PAGE_SIZE; - - /* page maybe head page, so we should get the buf by p, not the - * page - */ - tailroom = truesize - len - offset_in_page(p); - buf = (char *)((unsigned long)p & PAGE_MASK); - } else { - tailroom = truesize - len; - buf = p; - } + truesize = headroom ? PAGE_SIZE : truesize; + tailroom = truesize - len - headroom; + buf = p - headroom;
len -= hdr_len; offset += hdr_padded_len; @@@ -978,7 -966,8 +966,8 @@@ static struct sk_buff *receive_mergeabl put_page(page); head_skb = page_to_skb(vi, rq, xdp_page, offset, len, PAGE_SIZE, false, - metasize, true); + metasize, + VIRTIO_XDP_HEADROOM); return head_skb; } break; @@@ -1029,7 -1018,7 +1018,7 @@@ rcu_read_unlock();
head_skb = page_to_skb(vi, rq, page, offset, len, truesize, !xdp_prog, - metasize, !!headroom); + metasize, headroom); curr_skb = head_skb;
if (unlikely(!curr_skb)) @@@ -2208,14 -2197,14 +2197,14 @@@ static int virtnet_set_channels(struct if (vi->rq[0].xdp_prog) return -EINVAL;
- get_online_cpus(); + cpus_read_lock(); err = _virtnet_set_queues(vi, queue_pairs); if (err) { - put_online_cpus(); + cpus_read_unlock(); goto err; } virtnet_set_affinity(vi); - put_online_cpus(); + cpus_read_unlock();
netif_set_real_num_tx_queues(dev, queue_pairs); netif_set_real_num_rx_queues(dev, queue_pairs); @@@ -2515,7 -2504,7 +2504,7 @@@ static int virtnet_xdp_set(struct net_d virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))) { - NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO/CSUM, disable LRO/CSUM first"); + NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing GRO_HW/CSUM, disable GRO_HW/CSUM first"); return -EOPNOTSUPP; }
@@@ -2646,15 -2635,15 +2635,15 @@@ static int virtnet_set_features(struct u64 offloads; int err;
- if ((dev->features ^ features) & NETIF_F_LRO) { + if ((dev->features ^ features) & NETIF_F_GRO_HW) { if (vi->xdp_enabled) return -EBUSY;
- if (features & NETIF_F_LRO) + if (features & NETIF_F_GRO_HW) offloads = vi->guest_offloads_capable; else offloads = vi->guest_offloads_capable & - ~GUEST_OFFLOAD_LRO_MASK; + ~GUEST_OFFLOAD_GRO_HW_MASK;
err = virtnet_set_guest_offloads(vi, offloads); if (err) @@@ -2970,9 -2959,9 +2959,9 @@@ static int init_vqs(struct virtnet_inf if (ret) goto err_free;
- get_online_cpus(); + cpus_read_lock(); virtnet_set_affinity(vi); - put_online_cpus(); + cpus_read_unlock();
return 0;
@@@ -3134,9 -3123,9 +3123,9 @@@ static int virtnet_probe(struct virtio_ dev->features |= NETIF_F_RXCSUM; if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6)) - dev->features |= NETIF_F_LRO; + dev->features |= NETIF_F_GRO_HW; if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) - dev->hw_features |= NETIF_F_LRO; + dev->hw_features |= NETIF_F_GRO_HW;
dev->vlan_features = dev->features;
diff --combined drivers/net/vrf.c index 8bbe2a7bb141,662e26117353..bf2fac913942 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@@ -857,30 -857,24 +857,24 @@@ static int vrf_finish_output(struct ne unsigned int hh_len = LL_RESERVED_SPACE(dev); struct neighbour *neigh; bool is_v6gw = false; - int ret = -EINVAL;
nf_reset_ct(skb);
/* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { - struct sk_buff *skb2; - - skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); - if (!skb2) { - ret = -ENOMEM; - goto err; + skb = skb_expand_head(skb, hh_len); + if (!skb) { + dev->stats.tx_errors++; + return -ENOMEM; } - if (skb->sk) - skb_set_owner_w(skb2, skb->sk); - - consume_skb(skb); - skb = skb2; }
rcu_read_lock_bh();
neigh = ip_neigh_for_gw(rt, skb, &is_v6gw); if (!IS_ERR(neigh)) { + int ret; + sock_confirm_neigh(skb, neigh); /* if crossing protocols, can not use the cached header */ ret = neigh_output(neigh, skb, is_v6gw); @@@ -889,9 -883,8 +883,8 @@@ }
rcu_read_unlock_bh(); - err: vrf_tx_error(skb->dev, skb); - return ret; + return -EINVAL; }
static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb) @@@ -1367,8 -1360,6 +1360,8 @@@ static struct sk_buff *vrf_ip6_rcv(stru bool need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr); bool is_ndisc = ipv6_ndisc_frame(skb);
+ nf_reset_ct(skb); + /* loopback, multicast & non-ND link-local traffic; do not push through * packet taps again. Reset pkt_type for upper layers to process skb. * For strict packets with a source LLA, determine the dst using the @@@ -1431,8 -1422,6 +1424,8 @@@ static struct sk_buff *vrf_ip_rcv(struc skb->skb_iif = vrf_dev->ifindex; IPCB(skb)->flags |= IPSKB_L3SLAVE;
+ nf_reset_ct(skb); + if (ipv4_is_multicast(ip_hdr(skb)->daddr)) goto out;
diff --combined drivers/ptp/Kconfig index e085c255da0c,8ad88c3e79aa..32660dc11354 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@@ -8,6 -8,7 +8,7 @@@ menu "PTP clock support config PTP_1588_CLOCK tristate "PTP clock support" depends on NET && POSIX_TIMERS + default ETHERNET select PPS select NET_PTP_CLASSIFY help @@@ -26,6 -27,18 +27,18 @@@ To compile this driver as a module, choose M here: the module will be called ptp.
+ config PTP_1588_CLOCK_OPTIONAL + tristate + default y if PTP_1588_CLOCK=n + default PTP_1588_CLOCK + help + Drivers that can optionally use the PTP_1588_CLOCK framework + should depend on this symbol to prevent them from being built + into vmlinux while the PTP support itself is in a loadable + module. + If PTP support is disabled, this dependency will still be + met, and drivers refer to dummy helpers. + config PTP_1588_CLOCK_DTE tristate "Broadcom DTE as PTP clock" depends on PTP_1588_CLOCK @@@ -90,9 -103,8 +103,9 @@@ config PTP_1588_CLOCK_INE config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" depends on X86_32 || COMPILE_TEST - depends on HAS_IOMEM && NET + depends on HAS_IOMEM && PCI + depends on NET - imply PTP_1588_CLOCK + depends on PTP_1588_CLOCK help This driver adds support for using the PCH EG20T as a PTP clock. The hardware supports time stamping of PTP packets @@@ -158,6 -170,15 +171,15 @@@ config PTP_1588_CLOCK_OC tristate "OpenCompute TimeCard as PTP clock" depends on PTP_1588_CLOCK depends on HAS_IOMEM && PCI + depends on SPI && I2C && MTD + depends on !S390 + imply SPI_MEM + imply SPI_XILINX + imply MTD_SPI_NOR + imply I2C_XILINX + select SERIAL_8250 + select NET_DEVLINK + default n help This driver adds support for an OpenCompute time card. diff --combined drivers/s390/net/qeth_core_main.c index f96755a0a261,5b973f377504..41ca6273b750 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@@ -57,8 -57,7 +57,7 @@@ struct qeth_dbf_info qeth_dbf[QETH_DBF_ }; EXPORT_SYMBOL_GPL(qeth_dbf);
- struct kmem_cache *qeth_core_header_cache; - EXPORT_SYMBOL_GPL(qeth_core_header_cache); + static struct kmem_cache *qeth_core_header_cache; static struct kmem_cache *qeth_qdio_outbuf_cache;
static struct device *qeth_core_root_dev; @@@ -101,8 -100,6 +100,6 @@@ static const char *qeth_get_cardname(st return " OSD Express"; case QETH_CARD_TYPE_IQD: return " HiperSockets"; - case QETH_CARD_TYPE_OSN: - return " OSN QDIO"; case QETH_CARD_TYPE_OSM: return " OSM QDIO"; case QETH_CARD_TYPE_OSX: @@@ -157,8 -154,6 +154,6 @@@ const char *qeth_get_cardname_short(str } case QETH_CARD_TYPE_IQD: return "HiperSockets"; - case QETH_CARD_TYPE_OSN: - return "OSN"; case QETH_CARD_TYPE_OSM: return "OSM_1000"; case QETH_CARD_TYPE_OSX: @@@ -431,6 -426,13 +426,13 @@@ static enum iucv_tx_notify qeth_compute return n; }
+ static void qeth_put_cmd(struct qeth_cmd_buffer *iob) + { + if (refcount_dec_and_test(&iob->ref_count)) { + kfree(iob->data); + kfree(iob); + } + } static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len, void *data) { @@@ -499,12 -501,11 +501,11 @@@ static void qeth_dequeue_cmd(struct qet spin_unlock_irq(&card->lock); }
- void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason) + static void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason) { iob->rc = reason; complete(&iob->done); } - EXPORT_SYMBOL_GPL(qeth_notify_cmd);
static void qeth_flush_local_addrs4(struct qeth_card *card) { @@@ -781,10 -782,7 +782,7 @@@ static struct qeth_ipa_cmd *qeth_check_ QETH_CARD_TEXT(card, 5, "chkipad");
if (IS_IPA_REPLY(cmd)) { - if (cmd->hdr.command != IPA_CMD_SETCCID && - cmd->hdr.command != IPA_CMD_DELCCID && - cmd->hdr.command != IPA_CMD_MODCCID && - cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) + if (cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) qeth_issue_ipa_msg(cmd, cmd->hdr.return_code, card); return cmd; } @@@ -819,8 -817,6 +817,6 @@@ if (card->discipline->control_event_handler(card, cmd)) return cmd; return NULL; - case IPA_CMD_MODCCID: - return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: if (cmd->hdr.prot_version == QETH_PROT_IPV4) qeth_add_local_addrs4(card, &cmd->data.local_addrs4); @@@ -877,15 -873,6 +873,6 @@@ static int qeth_check_idx_response(stru return 0; }
- void qeth_put_cmd(struct qeth_cmd_buffer *iob) - { - if (refcount_dec_and_test(&iob->ref_count)) { - kfree(iob->data); - kfree(iob); - } - } - EXPORT_SYMBOL_GPL(qeth_put_cmd); - static void qeth_release_buffer_cb(struct qeth_card *card, struct qeth_cmd_buffer *iob, unsigned int data_length) @@@ -899,9 -886,9 +886,9 @@@ static void qeth_cancel_cmd(struct qeth qeth_put_cmd(iob); }
- struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel, - unsigned int length, unsigned int ccws, - long timeout) + static struct qeth_cmd_buffer *qeth_alloc_cmd(struct qeth_channel *channel, + unsigned int length, + unsigned int ccws, long timeout) { struct qeth_cmd_buffer *iob;
@@@ -927,7 -914,6 +914,6 @@@ iob->length = length; return iob; } - EXPORT_SYMBOL_GPL(qeth_alloc_cmd);
static void qeth_issue_next_read_cb(struct qeth_card *card, struct qeth_cmd_buffer *iob, @@@ -958,11 -944,6 +944,6 @@@ cmd = qeth_check_ipa_data(card, cmd); if (!cmd) goto out; - if (IS_OSN(card) && card->osn_info.assist_cb && - cmd->hdr.command != IPA_CMD_STARTLAN) { - card->osn_info.assist_cb(card->dev, cmd); - goto out; - } }
/* match against pending cmd requests */ @@@ -1835,7 -1816,7 +1816,7 @@@ static enum qeth_discipline_id qeth_enf { enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED;
- if (IS_OSM(card) || IS_OSN(card)) + if (IS_OSM(card)) disc = QETH_DISCIPLINE_LAYER2; else if (IS_VM_NIC(card)) disc = IS_IQD(card) ? QETH_DISCIPLINE_LAYER3 : @@@ -1885,7 -1866,6 +1866,6 @@@ static void qeth_idx_init(struct qeth_c card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD; break; case QETH_CARD_TYPE_OSD: - case QETH_CARD_TYPE_OSN: card->info.func_level = QETH_IDX_FUNC_LEVEL_OSD; break; default: @@@ -2442,9 -2422,7 +2422,7 @@@ static int qeth_ulp_enable_cb(struct qe
static u8 qeth_mpc_select_prot_type(struct qeth_card *card) { - if (IS_OSN(card)) - return QETH_PROT_OSN2; - return IS_LAYER2(card) ? QETH_PROT_LAYER2 : QETH_PROT_TCPIP; + return IS_LAYER2(card) ? QETH_MPC_PROT_L2 : QETH_MPC_PROT_L3; }
static int qeth_ulp_enable(struct qeth_card *card) @@@ -3000,10 -2978,8 +2978,8 @@@ static void qeth_ipa_finalize_cmd(struc __ipa_cmd(iob)->hdr.seqno = card->seqno.ipa++; }
- void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, - u16 cmd_length, - bool (*match)(struct qeth_cmd_buffer *iob, - struct qeth_cmd_buffer *reply)) + static void qeth_prepare_ipa_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob, u16 cmd_length) { u8 prot_type = qeth_mpc_select_prot_type(card); u16 total_length = iob->length; @@@ -3011,7 -2987,6 +2987,6 @@@ qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, total_length, iob->data); iob->finalize = qeth_ipa_finalize_cmd; - iob->match = match;
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2); @@@ -3022,7 -2997,6 +2997,6 @@@ &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);
static bool qeth_ipa_match_reply(struct qeth_cmd_buffer *iob, struct qeth_cmd_buffer *reply) @@@ -3046,7 -3020,8 +3020,8 @@@ struct qeth_cmd_buffer *qeth_ipa_alloc_ if (!iob) return NULL;
- qeth_prepare_ipa_cmd(card, iob, data_length, qeth_ipa_match_reply); + qeth_prepare_ipa_cmd(card, iob, data_length); + iob->match = qeth_ipa_match_reply;
hdr = &__ipa_cmd(iob)->hdr; hdr->command = cmd_code; @@@ -3804,10 -3779,14 +3779,10 @@@ static void qeth_qdio_output_handler(st unsigned long card_ptr) { struct qeth_card *card = (struct qeth_card *) card_ptr; - struct net_device *dev = card->dev;
- QETH_CARD_TEXT(card, 6, "qdouhdl"); - if (qdio_error & QDIO_ERROR_FATAL) { - QETH_CARD_TEXT(card, 2, "achkcond"); - netif_tx_stop_all_queues(dev); - qeth_schedule_recovery(card); - } + QETH_CARD_TEXT(card, 2, "achkcond"); + netif_tx_stop_all_queues(card->dev); + qeth_schedule_recovery(card); }
/** @@@ -3890,7 -3869,8 +3865,8 @@@ static int qeth_get_elements_for_frags( * Returns the number of pages, and thus QDIO buffer elements, needed to map the * skb's data (both its linear part and paged fragments). */ - unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset) + static unsigned int qeth_count_elements(struct sk_buff *skb, + unsigned int data_offset) { unsigned int elements = qeth_get_elements_for_frags(skb); addr_t end = (addr_t)skb->data + skb_headlen(skb); @@@ -3900,7 -3880,6 +3876,6 @@@ elements += qeth_get_elements_for_range(start, end); return elements; } - EXPORT_SYMBOL_GPL(qeth_count_elements);
#define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \ MAX_TCP_HEADER) @@@ -4188,10 -4167,11 +4163,11 @@@ static int __qeth_xmit(struct qeth_car return 0; }
- int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, - struct sk_buff *skb, struct qeth_hdr *hdr, - unsigned int offset, unsigned int hd_len, - int elements_needed) + static int qeth_do_send_packet(struct qeth_card *card, + struct qeth_qdio_out_q *queue, + struct sk_buff *skb, struct qeth_hdr *hdr, + unsigned int offset, unsigned int hd_len, + unsigned int elements_needed) { unsigned int start_index = queue->next_buf_to_fill; struct qeth_qdio_out_buffer *buffer; @@@ -4271,7 -4251,6 +4247,6 @@@ out netif_tx_start_queue(txq); return rc; } - EXPORT_SYMBOL_GPL(qeth_do_send_packet);
static void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len, struct sk_buff *skb, @@@ -4550,7 -4529,6 +4525,6 @@@ static int qeth_mdio_read(struct net_de case MII_BMCR: /* Basic mode control register */ rc = BMCR_FULLDPLX; if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH) && - (card->info.link_type != QETH_LINK_TYPE_OSN) && (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH) && (card->info.link_type != QETH_LINK_TYPE_25GBIT_ETH)) rc |= BMCR_SPEED100; @@@ -5262,10 -5240,6 +5236,6 @@@ static struct ccw_device_id qeth_ids[] .driver_info = QETH_CARD_TYPE_OSD}, {CCW_DEVICE_DEVTYPE(0x1731, 0x05, 0x1732, 0x05), .driver_info = QETH_CARD_TYPE_IQD}, - #ifdef CONFIG_QETH_OSN - {CCW_DEVICE_DEVTYPE(0x1731, 0x06, 0x1732, 0x06), - .driver_info = QETH_CARD_TYPE_OSN}, - #endif {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x03), .driver_info = QETH_CARD_TYPE_OSM}, #ifdef CONFIG_QETH_OSX @@@ -5624,14 -5598,6 +5594,6 @@@ static void qeth_receive_skb(struct qet bool is_cso;
switch (hdr->hdr.l2.id) { - case QETH_HEADER_TYPE_OSN: - skb_push(skb, sizeof(*hdr)); - skb_copy_to_linear_data(skb, hdr, sizeof(*hdr)); - QETH_CARD_STAT_ADD(card, rx_bytes, skb->len); - QETH_CARD_STAT_INC(card, rx_packets); - - card->osn_info.data_cb(skb); - return; #if IS_ENABLED(CONFIG_QETH_L3) case QETH_HEADER_TYPE_LAYER3: qeth_l3_rebuild_skb(card, skb, hdr); @@@ -5746,16 -5712,6 +5708,6 @@@ next_packet linear_len = sizeof(struct iphdr); headroom = ETH_HLEN; break; - case QETH_HEADER_TYPE_OSN: - skb_len = hdr->hdr.osn.pdu_length; - if (!IS_OSN(card)) { - QETH_CARD_STAT_INC(card, rx_dropped_notsupp); - goto walk_packet; - } - - linear_len = skb_len; - headroom = sizeof(struct qeth_hdr); - break; default: if (hdr->hdr.l2.id & QETH_HEADER_MASK_INVAL) QETH_CARD_STAT_INC(card, rx_frame_errors); @@@ -5773,8 -5729,7 +5725,7 @@@
use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) || (skb_len > READ_ONCE(priv->rx_copybreak) && - !atomic_read(&card->force_alloc_skb) && - !IS_OSN(card)); + !atomic_read(&card->force_alloc_skb));
if (use_rx_sg) { /* QETH_CQ_ENABLED only: */ @@@ -6331,14 -6286,9 +6282,9 @@@ void qeth_remove_discipline(struct qeth card->discipline = NULL; }
- const struct device_type qeth_generic_devtype = { + static const struct device_type qeth_generic_devtype = { .name = "qeth_generic", }; - EXPORT_SYMBOL_GPL(qeth_generic_devtype); - - static const struct device_type qeth_osn_devtype = { - .name = "qeth_osn", - };
#define DBF_NAME_LEN 20
@@@ -6421,10 -6371,6 +6367,6 @@@ static struct net_device *qeth_alloc_ne case QETH_CARD_TYPE_OSM: dev = alloc_etherdev(sizeof(*priv)); break; - case QETH_CARD_TYPE_OSN: - dev = alloc_netdev(sizeof(*priv), "osn%d", NET_NAME_UNKNOWN, - ether_setup); - break; default: dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_OUT_QUEUES, 1); } @@@ -6438,23 -6384,19 +6380,19 @@@
dev->ml_priv = card; dev->watchdog_timeo = QETH_TX_TIMEOUT; - dev->min_mtu = IS_OSN(card) ? 64 : 576; + dev->min_mtu = 576; /* initialized when device first goes online: */ dev->max_mtu = 0; dev->mtu = 0; SET_NETDEV_DEV(dev, &card->gdev->dev); netif_carrier_off(dev);
- if (IS_OSN(card)) { - dev->ethtool_ops = &qeth_osn_ethtool_ops; - } else { - dev->ethtool_ops = &qeth_ethtool_ops; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->hw_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_SG; - if (IS_IQD(card)) - dev->features |= NETIF_F_SG; - } + dev->ethtool_ops = &qeth_ethtool_ops; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->hw_features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_SG; + if (IS_IQD(card)) + dev->features |= NETIF_F_SG;
return dev; } @@@ -6517,10 -6459,7 +6455,7 @@@ static int qeth_core_probe_device(struc if (rc) goto err_chp_desc;
- if (IS_OSN(card)) - gdev->dev.groups = qeth_osn_dev_groups; - else - gdev->dev.groups = qeth_dev_groups; + gdev->dev.groups = qeth_dev_groups;
enforced_disc = qeth_enforce_discipline(card); switch (enforced_disc) { @@@ -6534,8 -6473,6 +6469,6 @@@ if (rc) goto err_setup_disc;
- gdev->dev.type = IS_OSN(card) ? &qeth_osn_devtype : - card->discipline->devtype; break; }
@@@ -6653,36 -6590,42 +6586,42 @@@ static struct ccwgroup_driver qeth_core .shutdown = qeth_core_shutdown, };
- struct qeth_card *qeth_get_card_by_busid(char *bus_id) - { - struct ccwgroup_device *gdev; - struct qeth_card *card; - - gdev = get_ccwgroupdev_by_busid(&qeth_core_ccwgroup_driver, bus_id); - if (!gdev) - return NULL; - - card = dev_get_drvdata(&gdev->dev); - put_device(&gdev->dev); - return card; - } - EXPORT_SYMBOL_GPL(qeth_get_card_by_busid); - - int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + int qeth_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *data, int cmd) { struct qeth_card *card = dev->ml_priv; - struct mii_ioctl_data *mii_data; int rc = 0;
switch (cmd) { case SIOC_QETH_ADP_SET_SNMP_CONTROL: - rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data); + rc = qeth_snmp_command(card, data); break; case SIOC_QETH_GET_CARD_TYPE: if ((IS_OSD(card) || IS_OSM(card) || IS_OSX(card)) && !IS_VM_NIC(card)) return 1; return 0; + case SIOC_QETH_QUERY_OAT: + rc = qeth_query_oat_command(card, data); + break; + default: + if (card->discipline->do_ioctl) + rc = card->discipline->do_ioctl(dev, rq, data, cmd); + else + rc = -EOPNOTSUPP; + } + if (rc) + QETH_CARD_TEXT_(card, 2, "ioce%x", rc); + return rc; + } + EXPORT_SYMBOL_GPL(qeth_siocdevprivate); + + int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + { + struct qeth_card *card = dev->ml_priv; + struct mii_ioctl_data *mii_data; + int rc = 0; + + switch (cmd) { case SIOCGMIIPHY: mii_data = if_mii(rq); mii_data->phy_id = 0; @@@ -6695,14 -6638,8 +6634,8 @@@ mii_data->val_out = qeth_mdio_read(dev, mii_data->phy_id, mii_data->reg_num); break; - case SIOC_QETH_QUERY_OAT: - rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data); - break; default: - if (card->discipline->do_ioctl) - rc = card->discipline->do_ioctl(dev, rq, cmd); - else - rc = -EOPNOTSUPP; + return -EOPNOTSUPP; } if (rc) QETH_CARD_TEXT_(card, 2, "ioce%x", rc); diff --combined include/linux/filter.h index c1711c9f9439,1797e8506929..a8108890629b --- a/include/linux/filter.h +++ b/include/linux/filter.h @@@ -5,6 -5,8 +5,6 @@@ #ifndef __LINUX_FILTER_H__ #define __LINUX_FILTER_H__
-#include <stdarg.h> - #include <linux/atomic.h> #include <linux/refcount.h> #include <linux/compat.h> @@@ -572,7 -574,8 +572,8 @@@ struct bpf_prog kprobe_override:1, /* Do we override a kprobe? */ has_callchain_buf:1, /* callchain buffer allocated? */ enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ - call_get_stack:1; /* Do we call bpf_get_stack() or bpf_get_stackid() */ + call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ + call_get_func_ip:1; /* Do we call get_func_ip() */ enum bpf_prog_type type; /* Type of BPF program */ enum bpf_attach_type expected_attach_type; /* For some prog types */ u32 len; /* Number of filter blocks */ @@@ -773,6 -776,10 +774,10 @@@ static inline u32 bpf_prog_run_clear_cb
DECLARE_BPF_DISPATCHER(xdp)
+ DECLARE_STATIC_KEY_FALSE(bpf_master_redirect_enabled_key); + + u32 xdp_master_redirect(struct xdp_buff *xdp); + static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog, struct xdp_buff *xdp) { @@@ -780,7 -787,14 +785,14 @@@ * under local_bh_disable(), which provides the needed RCU protection * for accessing map entries. */ - return __BPF_PROG_RUN(prog, xdp, BPF_DISPATCHER_FUNC(xdp)); + u32 act = __BPF_PROG_RUN(prog, xdp, BPF_DISPATCHER_FUNC(xdp)); + + if (static_branch_unlikely(&bpf_master_redirect_enabled_key)) { + if (act == XDP_TX && netif_is_bond_slave(xdp->rxq->dev)) + act = xdp_master_redirect(xdp); + } + + return act; }
void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog); diff --combined include/linux/memcontrol.h index 24797929d8a1,f0ee30881ca9..20151c4f1e0e --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@@ -612,15 -612,12 +612,15 @@@ static inline bool mem_cgroup_disabled( return !cgroup_subsys_enabled(memory_cgrp_subsys); }
-static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, - struct mem_cgroup *memcg, - bool in_low_reclaim) +static inline void mem_cgroup_protection(struct mem_cgroup *root, + struct mem_cgroup *memcg, + unsigned long *min, + unsigned long *low) { + *min = *low = 0; + if (mem_cgroup_disabled()) - return 0; + return;
/* * There is no reclaim protection applied to a targeted reclaim. @@@ -656,10 -653,13 +656,10 @@@ * */ if (root == memcg) - return 0; - - if (in_low_reclaim) - return READ_ONCE(memcg->memory.emin); + return;
- return max(READ_ONCE(memcg->memory.emin), - READ_ONCE(memcg->memory.elow)); + *min = READ_ONCE(memcg->memory.emin); + *low = READ_ONCE(memcg->memory.elow); }
void mem_cgroup_calculate_protection(struct mem_cgroup *root, @@@ -1147,12 -1147,11 +1147,12 @@@ static inline void memcg_memory_event_m { }
-static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, - struct mem_cgroup *memcg, - bool in_low_reclaim) +static inline void mem_cgroup_protection(struct mem_cgroup *root, + struct mem_cgroup *memcg, + unsigned long *min, + unsigned long *low) { - return 0; + *min = *low = 0; }
static inline void mem_cgroup_calculate_protection(struct mem_cgroup *root, @@@ -1582,7 -1581,8 +1582,8 @@@ static inline void mem_cgroup_flush_for #endif /* CONFIG_CGROUP_WRITEBACK */
struct sock; - bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages); + bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, + gfp_t gfp_mask); void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages); #ifdef CONFIG_MEMCG extern struct static_key_false memcg_sockets_enabled_key; diff --combined include/net/flow_offload.h index 1b9d75aedb22,5aa27acdb0b3..3961461d9c8b --- a/include/net/flow_offload.h +++ b/include/net/flow_offload.h @@@ -319,12 -319,14 +319,12 @@@ flow_action_mixed_hw_stats_check(const if (flow_offload_has_one_action(action)) return true;
- if (action) { - flow_action_for_each(i, action_entry, action) { - if (i && action_entry->hw_stats != last_hw_stats) { - NL_SET_ERR_MSG_MOD(extack, "Mixing HW stats types for actions is not supported"); - return false; - } - last_hw_stats = action_entry->hw_stats; + flow_action_for_each(i, action_entry, action) { + if (i && action_entry->hw_stats != last_hw_stats) { + NL_SET_ERR_MSG_MOD(extack, "Mixing HW stats types for actions is not supported"); + return false; } + last_hw_stats = action_entry->hw_stats; } return true; } @@@ -451,6 -453,7 +451,7 @@@ struct flow_block_offload struct list_head *driver_block_list; struct netlink_ext_ack *extack; struct Qdisc *sch; + struct list_head *cb_list_head; };
enum tc_setup_type; diff --combined init/main.c index 8d97aba78c3a,11cbbec309fa..daad6979f782 --- a/init/main.c +++ b/init/main.c @@@ -397,12 -397,6 +397,12 @@@ static int __init bootconfig_params(cha return 0; }
+static int __init warn_bootconfig(char *str) +{ + /* The 'bootconfig' has been handled by bootconfig_params(). */ + return 0; +} + static void __init setup_boot_config(void) { static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; @@@ -481,8 -475,9 +481,8 @@@ static int __init warn_bootconfig(char pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOT_CONFIG is not set.\n"); return 0; } -early_param("bootconfig", warn_bootconfig); - #endif +early_param("bootconfig", warn_bootconfig);
/* Change NUL term back to "=", to make "param" the whole string. */ static void __init repair_env_string(char *param, char *val) @@@ -1226,7 -1221,7 +1226,7 @@@ trace_initcall_start_cb(void *data, ini { ktime_t *calltime = (ktime_t *)data;
- printk(KERN_DEBUG "calling %pS @ %i\n", fn, task_pid_nr(current)); + printk(KERN_DEBUG "calling %pS @ %i irqs_disabled() %d\n", fn, task_pid_nr(current), irqs_disabled()); *calltime = ktime_get(); }
@@@ -1240,8 -1235,8 +1240,8 @@@ trace_initcall_finish_cb(void *data, in rettime = ktime_get(); delta = ktime_sub(rettime, *calltime); duration = (unsigned long long) ktime_to_ns(delta) >> 10; - printk(KERN_DEBUG "initcall %pS returned %d after %lld usecs\n", - fn, ret, duration); + printk(KERN_DEBUG "initcall %pS returned %d after %lld usecs, irqs_disabled() %d\n", + fn, ret, duration, irqs_disabled()); }
static ktime_t initcall_calltime; diff --combined kernel/bpf/helpers.c index 55f83ea09dae,32761be48143..04010a5e2ddb --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@@ -289,13 -289,18 +289,18 @@@ static inline void __bpf_spin_unlock(st
static DEFINE_PER_CPU(unsigned long, irqsave_flags);
- notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) + static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock) { unsigned long flags;
local_irq_save(flags); __bpf_spin_lock(lock); __this_cpu_write(irqsave_flags, flags); + } + + notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) + { + __bpf_spin_lock_irqsave(lock); return 0; }
@@@ -306,13 -311,18 +311,18 @@@ const struct bpf_func_proto bpf_spin_lo .arg1_type = ARG_PTR_TO_SPIN_LOCK, };
- notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) + static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock) { unsigned long flags;
flags = __this_cpu_read(irqsave_flags); __bpf_spin_unlock(lock); local_irq_restore(flags); + } + + notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) + { + __bpf_spin_unlock_irqrestore(lock); return 0; }
@@@ -333,9 -343,9 +343,9 @@@ void copy_map_value_locked(struct bpf_m else lock = dst + map->spin_lock_off; preempt_disable(); - ____bpf_spin_lock(lock); + __bpf_spin_lock_irqsave(lock); copy_map_value(map, dst, src); - ____bpf_spin_unlock(lock); + __bpf_spin_unlock_irqrestore(lock); preempt_enable(); }
@@@ -353,15 -363,9 +363,15 @@@ const struct bpf_func_proto bpf_jiffies #ifdef CONFIG_CGROUPS BPF_CALL_0(bpf_get_current_cgroup_id) { - struct cgroup *cgrp = task_dfl_cgroup(current); + struct cgroup *cgrp; + u64 cgrp_id;
- return cgroup_id(cgrp); + rcu_read_lock(); + cgrp = task_dfl_cgroup(current); + cgrp_id = cgroup_id(cgrp); + rcu_read_unlock(); + + return cgrp_id; }
const struct bpf_func_proto bpf_get_current_cgroup_id_proto = { @@@ -372,17 -376,13 +382,17 @@@
BPF_CALL_1(bpf_get_current_ancestor_cgroup_id, int, ancestor_level) { - struct cgroup *cgrp = task_dfl_cgroup(current); + struct cgroup *cgrp; struct cgroup *ancestor; + u64 cgrp_id;
+ rcu_read_lock(); + cgrp = task_dfl_cgroup(current); ancestor = cgroup_ancestor(cgrp, ancestor_level); - if (!ancestor) - return 0; - return cgroup_id(ancestor); + cgrp_id = ancestor ? cgroup_id(ancestor) : 0; + rcu_read_unlock(); + + return cgrp_id; }
const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = { @@@ -393,8 -393,6 +403,6 @@@ };
#ifdef CONFIG_CGROUP_BPF - DECLARE_PER_CPU(struct bpf_cgroup_storage_info, - bpf_cgroup_storage_info[BPF_CGROUP_STORAGE_NEST_MAX]);
BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags) { @@@ -403,17 -401,13 +411,13 @@@ * verifier checks that its value is correct. */ enum bpf_cgroup_storage_type stype = cgroup_storage_type(map); - struct bpf_cgroup_storage *storage = NULL; + struct bpf_cgroup_storage *storage; + struct bpf_cg_run_ctx *ctx; void *ptr; - int i;
- for (i = BPF_CGROUP_STORAGE_NEST_MAX - 1; i >= 0; i--) { - if (likely(this_cpu_read(bpf_cgroup_storage_info[i].task) != current)) - continue; - - storage = this_cpu_read(bpf_cgroup_storage_info[i].storage[stype]); - break; - } + /* get current cgroup storage from BPF run context */ + ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx); + storage = ctx->prog_item->cgroup_storage[stype];
if (stype == BPF_CGROUP_STORAGE_SHARED) ptr = &READ_ONCE(storage->buf)->data[0]; @@@ -999,6 -993,320 +1003,320 @@@ const struct bpf_func_proto bpf_snprint .arg5_type = ARG_CONST_SIZE_OR_ZERO, };
+ /* BPF map elements can contain 'struct bpf_timer'. + * Such map owns all of its BPF timers. + * 'struct bpf_timer' is allocated as part of map element allocation + * and it's zero initialized. + * That space is used to keep 'struct bpf_timer_kern'. + * bpf_timer_init() allocates 'struct bpf_hrtimer', inits hrtimer, and + * remembers 'struct bpf_map *' pointer it's part of. + * bpf_timer_set_callback() increments prog refcnt and assign bpf callback_fn. + * bpf_timer_start() arms the timer. + * If user space reference to a map goes to zero at this point + * ops->map_release_uref callback is responsible for cancelling the timers, + * freeing their memory, and decrementing prog's refcnts. + * bpf_timer_cancel() cancels the timer and decrements prog's refcnt. + * Inner maps can contain bpf timers as well. ops->map_release_uref is + * freeing the timers when inner map is replaced or deleted by user space. + */ + struct bpf_hrtimer { + struct hrtimer timer; + struct bpf_map *map; + struct bpf_prog *prog; + void __rcu *callback_fn; + void *value; + }; + + /* the actual struct hidden inside uapi struct bpf_timer */ + struct bpf_timer_kern { + struct bpf_hrtimer *timer; + /* bpf_spin_lock is used here instead of spinlock_t to make + * sure that it always fits into space resereved by struct bpf_timer + * regardless of LOCKDEP and spinlock debug flags. + */ + struct bpf_spin_lock lock; + } __attribute__((aligned(8))); + + static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running); + + static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer) + { + struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer); + struct bpf_map *map = t->map; + void *value = t->value; + void *callback_fn; + void *key; + u32 idx; + + callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held()); + if (!callback_fn) + goto out; + + /* bpf_timer_cb() runs in hrtimer_run_softirq. It doesn't migrate and + * cannot be preempted by another bpf_timer_cb() on the same cpu. + * Remember the timer this callback is servicing to prevent + * deadlock if callback_fn() calls bpf_timer_cancel() or + * bpf_map_delete_elem() on the same timer. + */ + this_cpu_write(hrtimer_running, t); + if (map->map_type == BPF_MAP_TYPE_ARRAY) { + struct bpf_array *array = container_of(map, struct bpf_array, map); + + /* compute the key */ + idx = ((char *)value - array->value) / array->elem_size; + key = &idx; + } else { /* hash or lru */ + key = value - round_up(map->key_size, 8); + } + + BPF_CAST_CALL(callback_fn)((u64)(long)map, (u64)(long)key, + (u64)(long)value, 0, 0); + /* The verifier checked that return value is zero. */ + + this_cpu_write(hrtimer_running, NULL); + out: + return HRTIMER_NORESTART; + } + + BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map, + u64, flags) + { + clockid_t clockid = flags & (MAX_CLOCKS - 1); + struct bpf_hrtimer *t; + int ret = 0; + + BUILD_BUG_ON(MAX_CLOCKS != 16); + BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer)); + BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer)); + + if (in_nmi()) + return -EOPNOTSUPP; + + if (flags >= MAX_CLOCKS || + /* similar to timerfd except _ALARM variants are not supported */ + (clockid != CLOCK_MONOTONIC && + clockid != CLOCK_REALTIME && + clockid != CLOCK_BOOTTIME)) + return -EINVAL; + __bpf_spin_lock_irqsave(&timer->lock); + t = timer->timer; + if (t) { + ret = -EBUSY; + goto out; + } + if (!atomic64_read(&map->usercnt)) { + /* maps with timers must be either held by user space + * or pinned in bpffs. + */ + ret = -EPERM; + goto out; + } + /* allocate hrtimer via map_kmalloc to use memcg accounting */ + t = bpf_map_kmalloc_node(map, sizeof(*t), GFP_ATOMIC, map->numa_node); + if (!t) { + ret = -ENOMEM; + goto out; + } + t->value = (void *)timer - map->timer_off; + t->map = map; + t->prog = NULL; + rcu_assign_pointer(t->callback_fn, NULL); + hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT); + t->timer.function = bpf_timer_cb; + timer->timer = t; + out: + __bpf_spin_unlock_irqrestore(&timer->lock); + return ret; + } + + static const struct bpf_func_proto bpf_timer_init_proto = { + .func = bpf_timer_init, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_TIMER, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_ANYTHING, + }; + + BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callback_fn, + struct bpf_prog_aux *, aux) + { + struct bpf_prog *prev, *prog = aux->prog; + struct bpf_hrtimer *t; + int ret = 0; + + if (in_nmi()) + return -EOPNOTSUPP; + __bpf_spin_lock_irqsave(&timer->lock); + t = timer->timer; + if (!t) { + ret = -EINVAL; + goto out; + } + if (!atomic64_read(&t->map->usercnt)) { + /* maps with timers must be either held by user space + * or pinned in bpffs. Otherwise timer might still be + * running even when bpf prog is detached and user space + * is gone, since map_release_uref won't ever be called. + */ + ret = -EPERM; + goto out; + } + prev = t->prog; + if (prev != prog) { + /* Bump prog refcnt once. Every bpf_timer_set_callback() + * can pick different callback_fn-s within the same prog. + */ + prog = bpf_prog_inc_not_zero(prog); + if (IS_ERR(prog)) { + ret = PTR_ERR(prog); + goto out; + } + if (prev) + /* Drop prev prog refcnt when swapping with new prog */ + bpf_prog_put(prev); + t->prog = prog; + } + rcu_assign_pointer(t->callback_fn, callback_fn); + out: + __bpf_spin_unlock_irqrestore(&timer->lock); + return ret; + } + + static const struct bpf_func_proto bpf_timer_set_callback_proto = { + .func = bpf_timer_set_callback, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_TIMER, + .arg2_type = ARG_PTR_TO_FUNC, + }; + + BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, flags) + { + struct bpf_hrtimer *t; + int ret = 0; + + if (in_nmi()) + return -EOPNOTSUPP; + if (flags) + return -EINVAL; + __bpf_spin_lock_irqsave(&timer->lock); + t = timer->timer; + if (!t || !t->prog) { + ret = -EINVAL; + goto out; + } + hrtimer_start(&t->timer, ns_to_ktime(nsecs), HRTIMER_MODE_REL_SOFT); + out: + __bpf_spin_unlock_irqrestore(&timer->lock); + return ret; + } + + static const struct bpf_func_proto bpf_timer_start_proto = { + .func = bpf_timer_start, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_TIMER, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + }; + + static void drop_prog_refcnt(struct bpf_hrtimer *t) + { + struct bpf_prog *prog = t->prog; + + if (prog) { + bpf_prog_put(prog); + t->prog = NULL; + rcu_assign_pointer(t->callback_fn, NULL); + } + } + + BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer) + { + struct bpf_hrtimer *t; + int ret = 0; + + if (in_nmi()) + return -EOPNOTSUPP; + __bpf_spin_lock_irqsave(&timer->lock); + t = timer->timer; + if (!t) { + ret = -EINVAL; + goto out; + } + if (this_cpu_read(hrtimer_running) == t) { + /* If bpf callback_fn is trying to bpf_timer_cancel() + * its own timer the hrtimer_cancel() will deadlock + * since it waits for callback_fn to finish + */ + ret = -EDEADLK; + goto out; + } + drop_prog_refcnt(t); + out: + __bpf_spin_unlock_irqrestore(&timer->lock); + /* Cancel the timer and wait for associated callback to finish + * if it was running. + */ + ret = ret ?: hrtimer_cancel(&t->timer); + return ret; + } + + static const struct bpf_func_proto bpf_timer_cancel_proto = { + .func = bpf_timer_cancel, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_TIMER, + }; + + /* This function is called by map_delete/update_elem for individual element and + * by ops->map_release_uref when the user space reference to a map reaches zero. + */ + void bpf_timer_cancel_and_free(void *val) + { + struct bpf_timer_kern *timer = val; + struct bpf_hrtimer *t; + + /* Performance optimization: read timer->timer without lock first. */ + if (!READ_ONCE(timer->timer)) + return; + + __bpf_spin_lock_irqsave(&timer->lock); + /* re-read it under lock */ + t = timer->timer; + if (!t) + goto out; + drop_prog_refcnt(t); + /* The subsequent bpf_timer_start/cancel() helpers won't be able to use + * this timer, since it won't be initialized. + */ + timer->timer = NULL; + out: + __bpf_spin_unlock_irqrestore(&timer->lock); + if (!t) + return; + /* Cancel the timer and wait for callback to complete if it was running. + * If hrtimer_cancel() can be safely called it's safe to call kfree(t) + * right after for both preallocated and non-preallocated maps. + * The timer->timer = NULL was already done and no code path can + * see address 't' anymore. + * + * Check that bpf_map_delete/update_elem() wasn't called from timer + * callback_fn. In such case don't call hrtimer_cancel() (since it will + * deadlock) and don't call hrtimer_try_to_cancel() (since it will just + * return -1). Though callback_fn is still running on this cpu it's + * safe to do kfree(t) because bpf_timer_cb() read everything it needed + * from 't'. The bpf subprog callback_fn won't be able to access 't', + * since timer->timer = NULL was already done. The timer will be + * effectively cancelled because bpf_timer_cb() will return + * HRTIMER_NORESTART. + */ + if (this_cpu_read(hrtimer_running) != t) + hrtimer_cancel(&t->timer); + kfree(t); + } + const struct bpf_func_proto bpf_get_current_task_proto __weak; const struct bpf_func_proto bpf_probe_read_user_proto __weak; const struct bpf_func_proto bpf_probe_read_user_str_proto __weak; @@@ -1065,6 -1373,14 +1383,14 @@@ bpf_base_func_proto(enum bpf_func_id fu return &bpf_per_cpu_ptr_proto; case BPF_FUNC_this_cpu_ptr: return &bpf_this_cpu_ptr_proto; + case BPF_FUNC_timer_init: + return &bpf_timer_init_proto; + case BPF_FUNC_timer_set_callback: + return &bpf_timer_set_callback_proto; + case BPF_FUNC_timer_start: + return &bpf_timer_start_proto; + case BPF_FUNC_timer_cancel: + return &bpf_timer_cancel_proto; default: break; } diff --combined kernel/bpf/verifier.c index 381d3d6f24bc,5ea2238a6656..e5f2b23bb7c9 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@@ -255,6 -255,7 +255,7 @@@ struct bpf_call_arg_meta int mem_size; u64 msize_max_value; int ref_obj_id; + int map_uid; int func_id; struct btf *btf; u32 btf_id; @@@ -734,6 -735,10 +735,10 @@@ static void print_verifier_state(struc if (state->refs[i].id) verbose(env, ",%d", state->refs[i].id); } + if (state->in_callback_fn) + verbose(env, " cb"); + if (state->in_async_callback_fn) + verbose(env, " async_cb"); verbose(env, "\n"); }
@@@ -1135,6 -1140,10 +1140,10 @@@ static void mark_ptr_not_null_reg(struc if (map->inner_map_meta) { reg->type = CONST_PTR_TO_MAP; reg->map_ptr = map->inner_map_meta; + /* transfer reg's id which is unique for every map_lookup_elem + * as UID of the inner map. + */ + reg->map_uid = reg->id; } else if (map->map_type == BPF_MAP_TYPE_XSKMAP) { reg->type = PTR_TO_XDP_SOCK; } else if (map->map_type == BPF_MAP_TYPE_SOCKMAP || @@@ -1522,6 -1531,54 +1531,54 @@@ static void init_func_state(struct bpf_ init_reg_state(env, state); }
+ /* Similar to push_stack(), but for async callbacks */ + static struct bpf_verifier_state *push_async_cb(struct bpf_verifier_env *env, + int insn_idx, int prev_insn_idx, + int subprog) + { + struct bpf_verifier_stack_elem *elem; + struct bpf_func_state *frame; + + elem = kzalloc(sizeof(struct bpf_verifier_stack_elem), GFP_KERNEL); + if (!elem) + goto err; + + elem->insn_idx = insn_idx; + elem->prev_insn_idx = prev_insn_idx; + elem->next = env->head; + elem->log_pos = env->log.len_used; + env->head = elem; + env->stack_size++; + if (env->stack_size > BPF_COMPLEXITY_LIMIT_JMP_SEQ) { + verbose(env, + "The sequence of %d jumps is too complex for async cb.\n", + env->stack_size); + goto err; + } + /* Unlike push_stack() do not copy_verifier_state(). + * The caller state doesn't matter. + * This is async callback. It starts in a fresh stack. + * Initialize it similar to do_check_common(). + */ + elem->st.branches = 1; + frame = kzalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) + goto err; + init_func_state(env, frame, + BPF_MAIN_FUNC /* callsite */, + 0 /* frameno within this callchain */, + subprog /* subprog number within this prog */); + elem->st.frame[0] = frame; + return &elem->st; + err: + free_verifier_state(env->cur_state, true); + env->cur_state = NULL; + /* pop all elements and return */ + while (!pop_stack(env, NULL, NULL, false)); + return NULL; + } + + enum reg_arg_type { SRC_OP, /* register is used as source operand */ DST_OP, /* register is used as destination operand */ @@@ -3217,6 -3274,15 +3274,15 @@@ static int check_map_access(struct bpf_ return -EACCES; } } + if (map_value_has_timer(map)) { + u32 t = map->timer_off; + + if (reg->smin_value + off < t + sizeof(struct bpf_timer) && + t < reg->umax_value + off + size) { + verbose(env, "bpf_timer cannot be accessed directly by load/store\n"); + return -EACCES; + } + } return err; }
@@@ -3619,6 -3685,8 +3685,8 @@@ process_func continue_func: subprog_end = subprog[idx + 1].start; for (; i < subprog_end; i++) { + int next_insn; + if (!bpf_pseudo_call(insn + i) && !bpf_pseudo_func(insn + i)) continue; /* remember insn and function to return to */ @@@ -3626,13 -3694,22 +3694,22 @@@ ret_prog[frame] = idx;
/* find the callee */ - i = i + insn[i].imm + 1; - idx = find_subprog(env, i); + next_insn = i + insn[i].imm + 1; + idx = find_subprog(env, next_insn); if (idx < 0) { WARN_ONCE(1, "verifier bug. No program starts at insn %d\n", - i); + next_insn); return -EFAULT; } + if (subprog[idx].is_async_cb) { + if (subprog[idx].has_tail_call) { + verbose(env, "verifier bug. subprog has tail_call and async cb\n"); + return -EFAULT; + } + /* async callbacks don't increase bpf prog stack size */ + continue; + } + i = next_insn;
if (subprog[idx].has_tail_call) tail_call_reachable = true; @@@ -4634,6 -4711,54 +4711,54 @@@ static int process_spin_lock(struct bpf return 0; }
+ static int process_timer_func(struct bpf_verifier_env *env, int regno, + struct bpf_call_arg_meta *meta) + { + struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; + bool is_const = tnum_is_const(reg->var_off); + struct bpf_map *map = reg->map_ptr; + u64 val = reg->var_off.value; + + if (!is_const) { + verbose(env, + "R%d doesn't have constant offset. bpf_timer 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_timer\n", + map->name); + return -EINVAL; + } + if (!map_value_has_timer(map)) { + if (map->timer_off == -E2BIG) + verbose(env, + "map '%s' has more than one 'struct bpf_timer'\n", + map->name); + else if (map->timer_off == -ENOENT) + verbose(env, + "map '%s' doesn't have 'struct bpf_timer'\n", + map->name); + else + verbose(env, + "map '%s' is not a struct type or bpf_timer is mangled\n", + map->name); + return -EINVAL; + } + if (map->timer_off != val + reg->off) { + verbose(env, "off %lld doesn't point to 'struct bpf_timer' that is at %d\n", + val + reg->off, map->timer_off); + return -EINVAL; + } + if (meta->map_ptr) { + verbose(env, "verifier bug. Two map pointers in a timer helper\n"); + return -EFAULT; + } + meta->map_uid = reg->map_uid; + meta->map_ptr = map; + return 0; + } + static bool arg_type_is_mem_ptr(enum bpf_arg_type type) { return type == ARG_PTR_TO_MEM || @@@ -4766,6 -4891,7 +4891,7 @@@ static const struct bpf_reg_types percp static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } }; static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } }; static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } }; + static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };
static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, @@@ -4797,6 -4923,7 +4923,7 @@@ [ARG_PTR_TO_FUNC] = &func_ptr_types, [ARG_PTR_TO_STACK_OR_NULL] = &stack_ptr_types, [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types, + [ARG_PTR_TO_TIMER] = &timer_types, };
static int check_reg_type(struct bpf_verifier_env *env, u32 regno, @@@ -4926,7 -5053,29 +5053,29 @@@ skip_type_check
if (arg_type == ARG_CONST_MAP_PTR) { /* bpf_map_xxx(map_ptr) call: remember that map_ptr */ + if (meta->map_ptr) { + /* Use map_uid (which is unique id of inner map) to reject: + * inner_map1 = bpf_map_lookup_elem(outer_map, key1) + * inner_map2 = bpf_map_lookup_elem(outer_map, key2) + * if (inner_map1 && inner_map2) { + * timer = bpf_map_lookup_elem(inner_map1); + * if (timer) + * // mismatch would have been allowed + * bpf_timer_init(timer, inner_map2); + * } + * + * Comparing map_ptr is enough to distinguish normal and outer maps. + */ + if (meta->map_ptr != reg->map_ptr || + meta->map_uid != reg->map_uid) { + verbose(env, + "timer pointer in R1 map_uid=%d doesn't match map pointer in R2 map_uid=%d\n", + meta->map_uid, reg->map_uid); + return -EINVAL; + } + } meta->map_ptr = reg->map_ptr; + meta->map_uid = reg->map_uid; } else if (arg_type == ARG_PTR_TO_MAP_KEY) { /* bpf_map_xxx(..., map_ptr, ..., key) call: * check that [key, key + map->key_size) are within @@@ -4978,6 -5127,9 +5127,9 @@@ verbose(env, "verifier internal error\n"); return -EFAULT; } + } else if (arg_type == ARG_PTR_TO_TIMER) { + if (process_timer_func(env, regno, meta)) + return -EACCES; } else if (arg_type == ARG_PTR_TO_FUNC) { meta->subprogno = reg->subprogno; } else if (arg_type_is_mem_ptr(arg_type)) { @@@ -5593,6 -5745,31 +5745,31 @@@ static int __check_func_call(struct bpf } }
+ if (insn->code == (BPF_JMP | BPF_CALL) && + insn->imm == BPF_FUNC_timer_set_callback) { + struct bpf_verifier_state *async_cb; + + /* there is no real recursion here. timer callbacks are async */ + env->subprog_info[subprog].is_async_cb = true; + async_cb = push_async_cb(env, env->subprog_info[subprog].start, + *insn_idx, subprog); + if (!async_cb) + return -EFAULT; + callee = async_cb->frame[0]; + callee->async_entry_cnt = caller->async_entry_cnt + 1; + + /* Convert bpf_timer_set_callback() args into timer callback args */ + err = set_callee_state_cb(env, caller, callee, *insn_idx); + if (err) + return err; + + clear_caller_saved_regs(env, caller->regs); + mark_reg_unknown(env, caller->regs, BPF_REG_0); + caller->regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG; + /* continue with next insn after call */ + return 0; + } + callee = kzalloc(sizeof(*callee), GFP_KERNEL); if (!callee) return -ENOMEM; @@@ -5720,6 -5897,35 +5897,35 @@@ static int set_map_elem_callback_state( return 0; }
+ static int set_timer_callback_state(struct bpf_verifier_env *env, + struct bpf_func_state *caller, + struct bpf_func_state *callee, + int insn_idx) + { + struct bpf_map *map_ptr = caller->regs[BPF_REG_1].map_ptr; + + /* bpf_timer_set_callback(struct bpf_timer *timer, void *callback_fn); + * callback_fn(struct bpf_map *map, void *key, void *value); + */ + callee->regs[BPF_REG_1].type = CONST_PTR_TO_MAP; + __mark_reg_known_zero(&callee->regs[BPF_REG_1]); + callee->regs[BPF_REG_1].map_ptr = map_ptr; + + callee->regs[BPF_REG_2].type = PTR_TO_MAP_KEY; + __mark_reg_known_zero(&callee->regs[BPF_REG_2]); + callee->regs[BPF_REG_2].map_ptr = map_ptr; + + callee->regs[BPF_REG_3].type = PTR_TO_MAP_VALUE; + __mark_reg_known_zero(&callee->regs[BPF_REG_3]); + callee->regs[BPF_REG_3].map_ptr = map_ptr; + + /* unused */ + __mark_reg_not_init(env, &callee->regs[BPF_REG_4]); + __mark_reg_not_init(env, &callee->regs[BPF_REG_5]); + callee->in_async_callback_fn = true; + return 0; + } + static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx) { struct bpf_verifier_state *state = env->cur_state; @@@ -5933,6 -6139,29 +6139,29 @@@ static int check_bpf_snprintf_call(stru return err; }
+ static int check_get_func_ip(struct bpf_verifier_env *env) + { + enum bpf_attach_type eatype = env->prog->expected_attach_type; + enum bpf_prog_type type = resolve_prog_type(env->prog); + int func_id = BPF_FUNC_get_func_ip; + + if (type == BPF_PROG_TYPE_TRACING) { + if (eatype != BPF_TRACE_FENTRY && eatype != BPF_TRACE_FEXIT && + eatype != BPF_MODIFY_RETURN) { + verbose(env, "func %s#%d supported only for fentry/fexit/fmod_ret programs\n", + func_id_name(func_id), func_id); + return -ENOTSUPP; + } + return 0; + } else if (type == BPF_PROG_TYPE_KPROBE) { + return 0; + } + + verbose(env, "func %s#%d not supported for program type %d\n", + func_id_name(func_id), func_id, type); + return -ENOTSUPP; + } + static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx_p) { @@@ -6047,6 -6276,13 +6276,13 @@@ return -EINVAL; }
+ if (func_id == BPF_FUNC_timer_set_callback) { + err = __check_func_call(env, insn, insn_idx_p, meta.subprogno, + set_timer_callback_state); + if (err < 0) + return -EINVAL; + } + if (func_id == BPF_FUNC_snprintf) { err = check_bpf_snprintf_call(env, regs); if (err < 0) @@@ -6082,6 -6318,7 +6318,7 @@@ return -EINVAL; } regs[BPF_REG_0].map_ptr = meta.map_ptr; + regs[BPF_REG_0].map_uid = meta.map_uid; 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)) @@@ -6203,6 -6440,12 +6440,12 @@@ if (func_id == BPF_FUNC_get_stackid || func_id == BPF_FUNC_get_stack) env->prog->call_get_stack = true;
+ if (func_id == BPF_FUNC_get_func_ip) { + if (check_get_func_ip(env)) + return -ENOTSUPP; + env->prog->call_get_func_ip = true; + } + if (changes_data) clear_all_pkt_pointers(env); return 0; @@@ -9083,7 -9326,8 +9326,8 @@@ static int check_return_code(struct bpf struct tnum range = tnum_range(0, 1); enum bpf_prog_type prog_type = resolve_prog_type(env->prog); int err; - const bool is_subprog = env->cur_state->frame[0]->subprogno; + struct bpf_func_state *frame = env->cur_state->frame[0]; + const bool is_subprog = frame->subprogno;
/* LSM and struct_ops func-ptr's return type could be "void" */ if (!is_subprog && @@@ -9108,6 -9352,22 +9352,22 @@@ }
reg = cur_regs(env) + BPF_REG_0; + + if (frame->in_async_callback_fn) { + /* enforce return zero from async callbacks like timer */ + if (reg->type != SCALAR_VALUE) { + verbose(env, "In async callback the register R0 is not a known value (%s)\n", + reg_type_str[reg->type]); + return -EINVAL; + } + + if (!tnum_in(tnum_const(0), reg->var_off)) { + verbose_invalid_scalar(env, reg, &range, "async callback", "R0"); + return -EINVAL; + } + return 0; + } + if (is_subprog) { if (reg->type != SCALAR_VALUE) { verbose(env, "At subprogram exit the register R0 is not a scalar value (%s)\n", @@@ -9322,8 -9582,12 +9582,12 @@@ static int visit_func_call_insn(int t, init_explored_state(env, t + 1); if (visit_callee) { init_explored_state(env, t); - ret = push_insn(t, t + insns[t].imm + 1, BRANCH, - env, false); + ret = push_insn(t, t + insns[t].imm + 1, BRANCH, env, + /* It's ok to allow recursion from CFG point of + * view. __check_func_call() will do the actual + * check. + */ + bpf_pseudo_func(insns + t)); } return ret; } @@@ -9351,6 -9615,13 +9615,13 @@@ static int visit_insn(int t, int insn_c return DONE_EXPLORING;
case BPF_CALL: + if (insns[t].imm == BPF_FUNC_timer_set_callback) + /* Mark this call insn to trigger is_state_visited() check + * before call itself is processed by __check_func_call(). + * Otherwise new async state will be pushed for further + * exploration. + */ + init_explored_state(env, t); return visit_func_call_insn(t, insn_cnt, insns, env, insns[t].src_reg == BPF_PSEUDO_CALL);
@@@ -10359,9 -10630,25 +10630,25 @@@ static int is_state_visited(struct bpf_ states_cnt++; if (sl->state.insn_idx != insn_idx) goto next; + if (sl->state.branches) { - if (states_maybe_looping(&sl->state, cur) && - states_equal(env, &sl->state, cur)) { + struct bpf_func_state *frame = sl->state.frame[sl->state.curframe]; + + if (frame->in_async_callback_fn && + frame->async_entry_cnt != cur->frame[cur->curframe]->async_entry_cnt) { + /* Different async_entry_cnt means that the verifier is + * processing another entry into async callback. + * Seeing the same state is not an indication of infinite + * loop or infinite recursion. + * But finding the same state doesn't mean that it's safe + * to stop processing the current state. The previous state + * hasn't yet reached bpf_exit, since state.branches > 0. + * Checking in_async_callback_fn alone is not enough either. + * Since the verifier still needs to catch infinite loops + * inside async callbacks. + */ + } else if (states_maybe_looping(&sl->state, cur) && + states_equal(env, &sl->state, cur)) { verbose_linfo(env, insn_idx, "; "); verbose(env, "infinite loop detected at insn %d\n", insn_idx); return -EINVAL; @@@ -11410,10 -11697,11 +11697,11 @@@ static void convert_pseudo_ld_imm64(str * insni[off, off + cnt). Adjust corresponding insn_aux_data by copying * [0, off) and [off, end) to new locations, so the patched range stays zero */ - static int adjust_insn_aux_data(struct bpf_verifier_env *env, - struct bpf_prog *new_prog, u32 off, u32 cnt) + static void adjust_insn_aux_data(struct bpf_verifier_env *env, + struct bpf_insn_aux_data *new_data, + struct bpf_prog *new_prog, u32 off, u32 cnt) { - struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data; + struct bpf_insn_aux_data *old_data = env->insn_aux_data; struct bpf_insn *insn = new_prog->insnsi; u32 old_seen = old_data[off].seen; u32 prog_len; @@@ -11426,12 -11714,9 +11714,9 @@@ old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
if (cnt == 1) - return 0; + return; prog_len = new_prog->len; - new_data = vzalloc(array_size(prog_len, - sizeof(struct bpf_insn_aux_data))); - if (!new_data) - return -ENOMEM; + memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off); memcpy(new_data + off + cnt - 1, old_data + off, sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1)); @@@ -11442,7 -11727,6 +11727,6 @@@ } env->insn_aux_data = new_data; vfree(old_data); - return 0; }
static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len) @@@ -11477,6 -11761,14 +11761,14 @@@ static struct bpf_prog *bpf_patch_insn_ const struct bpf_insn *patch, u32 len) { struct bpf_prog *new_prog; + struct bpf_insn_aux_data *new_data = NULL; + + if (len > 1) { + new_data = vzalloc(array_size(env->prog->len + len - 1, + sizeof(struct bpf_insn_aux_data))); + if (!new_data) + return NULL; + }
new_prog = bpf_patch_insn_single(env->prog, off, patch, len); if (IS_ERR(new_prog)) { @@@ -11484,10 -11776,10 +11776,10 @@@ verbose(env, "insn %d cannot be patched due to 16-bit range\n", env->insn_aux_data[off].orig_idx); + vfree(new_data); return NULL; } - if (adjust_insn_aux_data(env, new_prog, off, len)) - return NULL; + adjust_insn_aux_data(env, new_data, new_prog, off, len); adjust_subprog_starts(env, off, len); adjust_poke_descs(new_prog, off, len); return new_prog; @@@ -11663,7 -11955,6 +11955,7 @@@ static void sanitize_dead_code(struct b if (aux_data[i].seen) continue; memcpy(insn + i, &trap, sizeof(trap)); + aux_data[i].zext_dst = false; } }
@@@ -12338,6 -12629,7 +12630,7 @@@ static int do_misc_fixups(struct bpf_ve { struct bpf_prog *prog = env->prog; bool expect_blinding = bpf_jit_blinding_enabled(prog); + enum bpf_prog_type prog_type = resolve_prog_type(prog); struct bpf_insn *insn = prog->insnsi; const struct bpf_func_proto *fn; const int insn_cnt = prog->len; @@@ -12555,6 -12847,39 +12848,39 @@@ continue; }
+ if (insn->imm == BPF_FUNC_timer_set_callback) { + /* The verifier will process callback_fn as many times as necessary + * with different maps and the register states prepared by + * set_timer_callback_state will be accurate. + * + * The following use case is valid: + * map1 is shared by prog1, prog2, prog3. + * prog1 calls bpf_timer_init for some map1 elements + * prog2 calls bpf_timer_set_callback for some map1 elements. + * Those that were not bpf_timer_init-ed will return -EINVAL. + * prog3 calls bpf_timer_start for some map1 elements. + * Those that were not both bpf_timer_init-ed and + * bpf_timer_set_callback-ed will return -EINVAL. + */ + struct bpf_insn ld_addrs[2] = { + BPF_LD_IMM64(BPF_REG_3, (long)prog->aux), + }; + + insn_buf[0] = ld_addrs[0]; + insn_buf[1] = ld_addrs[1]; + insn_buf[2] = *insn; + cnt = 3; + + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); + if (!new_prog) + return -ENOMEM; + + delta += cnt - 1; + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; + goto patch_call_imm; + } + /* BPF_EMIT_CALL() assumptions in some of the map_gen_lookup * and other inlining handlers are currently limited to 64 bit * only. @@@ -12671,6 -12996,21 +12997,21 @@@ patch_map_ops_generic continue; }
+ /* Implement bpf_get_func_ip inline. */ + if (prog_type == BPF_PROG_TYPE_TRACING && + insn->imm == BPF_FUNC_get_func_ip) { + /* Load IP address from ctx - 8 */ + insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); + + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, 1); + if (!new_prog) + return -ENOMEM; + + env->prog = prog = new_prog; + insn = new_prog->insnsi + i + delta; + continue; + } + patch_call_imm: fn = env->ops->get_func_proto(insn->imm, env->prog); /* all functions that have prototype and verifier allowed diff --combined mm/memcontrol.c index 702a81dfe72d,be585ceaba98..389b5766e74f --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@@ -968,7 -968,7 +968,7 @@@ static __always_inline bool memcg_kmem_ return false;
/* Memcg to charge can't be determined. */ - if (in_interrupt() || !current->mm || (current->flags & PF_KTHREAD)) + if (!in_task() || !current->mm || (current->flags & PF_KTHREAD)) return true;
return false; @@@ -3106,15 -3106,13 +3106,15 @@@ void mod_objcg_state(struct obj_cgroup stock->cached_pgdat = pgdat; } else if (stock->cached_pgdat != pgdat) { /* Flush the existing cached vmstat data */ + struct pglist_data *oldpg = stock->cached_pgdat; + if (stock->nr_slab_reclaimable_b) { - mod_objcg_mlstate(objcg, pgdat, NR_SLAB_RECLAIMABLE_B, + mod_objcg_mlstate(objcg, oldpg, NR_SLAB_RECLAIMABLE_B, stock->nr_slab_reclaimable_b); stock->nr_slab_reclaimable_b = 0; } if (stock->nr_slab_unreclaimable_b) { - mod_objcg_mlstate(objcg, pgdat, NR_SLAB_UNRECLAIMABLE_B, + mod_objcg_mlstate(objcg, oldpg, NR_SLAB_UNRECLAIMABLE_B, stock->nr_slab_unreclaimable_b); stock->nr_slab_unreclaimable_b = 0; } @@@ -7050,14 -7048,14 +7050,14 @@@ void mem_cgroup_sk_free(struct sock *sk * mem_cgroup_charge_skmem - charge socket memory * @memcg: memcg to charge * @nr_pages: number of pages to charge + * @gfp_mask: reclaim mode * * Charges @nr_pages to @memcg. Returns %true if the charge fit within - * @memcg's configured limit, %false if the charge had to be forced. + * @memcg's configured limit, %false if it doesn't. */ - bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages) + bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, + gfp_t gfp_mask) { - gfp_t gfp_mask = GFP_KERNEL; - if (!cgroup_subsys_on_dfl(memory_cgrp_subsys)) { struct page_counter *fail;
@@@ -7065,21 -7063,19 +7065,19 @@@ memcg->tcpmem_pressure = 0; return true; } - page_counter_charge(&memcg->tcpmem, nr_pages); memcg->tcpmem_pressure = 1; + if (gfp_mask & __GFP_NOFAIL) { + page_counter_charge(&memcg->tcpmem, nr_pages); + return true; + } return false; }
- /* Don't block in the packet receive path */ - if (in_softirq()) - gfp_mask = GFP_NOWAIT; - - mod_memcg_state(memcg, MEMCG_SOCK, nr_pages); - - if (try_charge(memcg, gfp_mask, nr_pages) == 0) + if (try_charge(memcg, gfp_mask, nr_pages) == 0) { + mod_memcg_state(memcg, MEMCG_SOCK, nr_pages); return true; + }
- try_charge(memcg, gfp_mask|__GFP_NOFAIL, nr_pages); return false; }
diff --combined net/ipv4/ip_gre.c index 95419b7adf5c,6ebf05859acb..177d26d8fb9c --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@@ -473,8 -473,6 +473,8 @@@ static void __gre_xmit(struct sk_buff *
static int gre_handle_offloads(struct sk_buff *skb, bool csum) { + if (csum && skb_checksum_start(skb) < skb->data) + return -EINVAL; return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); }
@@@ -925,7 -923,7 +925,7 @@@ static const struct net_device_ops ipgr .ndo_stop = ipgre_close, #endif .ndo_start_xmit = ipgre_xmit, - .ndo_do_ioctl = ip_tunnel_ioctl, + .ndo_siocdevprivate = ip_tunnel_siocdevprivate, .ndo_change_mtu = ip_tunnel_change_mtu, .ndo_get_stats64 = dev_get_tstats64, .ndo_get_iflink = ip_tunnel_get_iflink, diff --combined net/ipv6/ip6_gre.c index 7a5e90e09363,3ad201d372d8..7baf41d160f5 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@@ -629,8 -629,6 +629,8 @@@ drop
static int gre_handle_offloads(struct sk_buff *skb, bool csum) { + if (csum && skb_checksum_start(skb) < skb->data) + return -EINVAL; return iptunnel_handle_offloads(skb, csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); } @@@ -1246,8 -1244,9 +1246,9 @@@ static void ip6gre_tnl_parm_to_user(str memcpy(u->name, p->name, sizeof(u->name)); }
- static int ip6gre_tunnel_ioctl(struct net_device *dev, - struct ifreq *ifr, int cmd) + static int ip6gre_tunnel_siocdevprivate(struct net_device *dev, + struct ifreq *ifr, void __user *data, + int cmd) { int err = 0; struct ip6_tnl_parm2 p; @@@ -1261,7 -1260,7 +1262,7 @@@ switch (cmd) { case SIOCGETTUNNEL: if (dev == ign->fb_tunnel_dev) { - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { + if (copy_from_user(&p, data, sizeof(p))) { err = -EFAULT; break; } @@@ -1272,7 -1271,7 +1273,7 @@@ } memset(&p, 0, sizeof(p)); ip6gre_tnl_parm_to_user(&p, &t->parms); - if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) + if (copy_to_user(data, &p, sizeof(p))) err = -EFAULT; break;
@@@ -1283,7 -1282,7 +1284,7 @@@ goto done;
err = -EFAULT; - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + if (copy_from_user(&p, data, sizeof(p))) goto done;
err = -EINVAL; @@@ -1320,7 -1319,7 +1321,7 @@@
memset(&p, 0, sizeof(p)); ip6gre_tnl_parm_to_user(&p, &t->parms); - if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) + if (copy_to_user(data, &p, sizeof(p))) err = -EFAULT; } else err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); @@@ -1333,7 -1332,7 +1334,7 @@@
if (dev == ign->fb_tunnel_dev) { err = -EFAULT; - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + if (copy_from_user(&p, data, sizeof(p))) goto done; err = -ENOENT; ip6gre_tnl_parm_from_user(&p1, &p); @@@ -1400,7 -1399,7 +1401,7 @@@ static const struct net_device_ops ip6g .ndo_init = ip6gre_tunnel_init, .ndo_uninit = ip6gre_tunnel_uninit, .ndo_start_xmit = ip6gre_tunnel_xmit, - .ndo_do_ioctl = ip6gre_tunnel_ioctl, + .ndo_siocdevprivate = ip6gre_tunnel_siocdevprivate, .ndo_change_mtu = ip6_tnl_change_mtu, .ndo_get_stats64 = dev_get_tstats64, .ndo_get_iflink = ip6_tnl_get_iflink, diff --combined net/mptcp/options.c index 7adcbc1f7d49,e37b6f2fb514..bebb759f470e --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@@ -885,16 -885,20 +885,16 @@@ static bool check_fully_established(str return subflow->mp_capable; }
- if (mp_opt->dss && mp_opt->use_ack) { + if ((mp_opt->dss && mp_opt->use_ack) || + (mp_opt->add_addr && !mp_opt->echo)) { /* subflows are fully established as soon as we get any - * additional ack. + * additional ack, including ADD_ADDR. */ subflow->fully_established = 1; WRITE_ONCE(msk->fully_established, true); goto fully_established; }
- if (mp_opt->add_addr) { - WRITE_ONCE(msk->fully_established, true); - return true; - } - /* If the first established packet does not contain MP_CAPABLE + data * then fallback to TCP. Fallback scenarios requires a reset for * MP_JOIN subflows. @@@ -971,9 -975,11 +971,11 @@@ static void ack_update_msk(struct mptcp old_snd_una = msk->snd_una; new_snd_una = mptcp_expand_seq(old_snd_una, mp_opt->data_ack, mp_opt->ack64);
- /* ACK for data not even sent yet? Ignore. */ - if (after64(new_snd_una, snd_nxt)) - new_snd_una = old_snd_una; + /* ACK for data not even sent yet and even above recovery bound? Ignore.*/ + if (unlikely(after64(new_snd_una, snd_nxt))) { + if (!msk->recovery || after64(new_snd_una, msk->recovery_snd_nxt)) + new_snd_una = old_snd_una; + }
new_wnd_end = new_snd_una + tcp_sk(ssk)->snd_wnd;
diff --combined net/mptcp/pm_netlink.c index 7b3794459783,6e3df62a87d2..480f43ec1bfb --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@@ -46,6 -46,7 +46,7 @@@ struct pm_nl_pernet spinlock_t lock; struct list_head local_addr_list; unsigned int addrs; + unsigned int stale_loss_cnt; unsigned int add_addr_signal_max; unsigned int add_addr_accept_max; unsigned int local_addr_max; @@@ -409,6 -410,55 +410,55 @@@ void mptcp_pm_free_anno_list(struct mpt } }
+ static bool lookup_address_in_vec(struct mptcp_addr_info *addrs, unsigned int nr, + struct mptcp_addr_info *addr) + { + int i; + + for (i = 0; i < nr; i++) { + if (addresses_equal(&addrs[i], addr, addr->port)) + return true; + } + + return false; + } + + /* Fill all the remote addresses into the array addrs[], + * and return the array size. + */ + static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, bool fullmesh, + struct mptcp_addr_info *addrs) + { + struct sock *sk = (struct sock *)msk, *ssk; + struct mptcp_subflow_context *subflow; + struct mptcp_addr_info remote = { 0 }; + unsigned int subflows_max; + int i = 0; + + subflows_max = mptcp_pm_get_subflows_max(msk); + + /* Non-fullmesh endpoint, fill in the single entry + * corresponding to the primary MPC subflow remote address + */ + if (!fullmesh) { + remote_address((struct sock_common *)sk, &remote); + msk->pm.subflows++; + addrs[i++] = remote; + } else { + mptcp_for_each_subflow(msk, subflow) { + ssk = mptcp_subflow_tcp_sock(subflow); + remote_address((struct sock_common *)ssk, &remote); + if (!lookup_address_in_vec(addrs, i, &remote) && + msk->pm.subflows < subflows_max) { + msk->pm.subflows++; + addrs[i++] = remote; + } + } + } + + return i; + } + static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) { struct sock *sk = (struct sock *)msk; @@@ -454,15 -504,16 +504,16 @@@ !READ_ONCE(msk->pm.remote_deny_join_id0)) { local = select_local_address(pernet, msk); if (local) { - struct mptcp_addr_info remote = { 0 }; + bool fullmesh = !!(local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH); + struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX]; + int i, nr;
msk->pm.local_addr_used++; - msk->pm.subflows++; check_work_pending(msk); - remote_address((struct sock_common *)sk, &remote); + nr = fill_remote_addresses_vec(msk, fullmesh, addrs); spin_unlock_bh(&msk->pm.lock); - __mptcp_subflow_connect(sk, &local->addr, &remote, - local->flags, local->ifindex); + for (i = 0; i < nr; i++) + __mptcp_subflow_connect(sk, &local->addr, &addrs[i]); spin_lock_bh(&msk->pm.lock); return; } @@@ -483,13 -534,67 +534,67 @@@ static void mptcp_pm_nl_subflow_establi mptcp_pm_create_subflow_or_signal_addr(msk); }
+ /* Fill all the local addresses into the array addrs[], + * and return the array size. + */ + static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk, + struct mptcp_addr_info *addrs) + { + struct sock *sk = (struct sock *)msk; + struct mptcp_pm_addr_entry *entry; + struct mptcp_addr_info local; + struct pm_nl_pernet *pernet; + unsigned int subflows_max; + int i = 0; + + pernet = net_generic(sock_net(sk), pm_nl_pernet_id); + subflows_max = mptcp_pm_get_subflows_max(msk); + + rcu_read_lock(); + __mptcp_flush_join_list(msk); + list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { + if (!(entry->flags & MPTCP_PM_ADDR_FLAG_FULLMESH)) + continue; + + if (entry->addr.family != sk->sk_family) { + #if IS_ENABLED(CONFIG_MPTCP_IPV6) + if ((entry->addr.family == AF_INET && + !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) || + (sk->sk_family == AF_INET && + !ipv6_addr_v4mapped(&entry->addr.addr6))) + #endif + continue; + } + + if (msk->pm.subflows < subflows_max) { + msk->pm.subflows++; + addrs[i++] = entry->addr; + } + } + rcu_read_unlock(); + + /* If the array is empty, fill in the single + * 'IPADDRANY' local address + */ + if (!i) { + memset(&local, 0, sizeof(local)); + local.family = msk->pm.remote.family; + + msk->pm.subflows++; + addrs[i++] = local; + } + + return i; + } + static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk) { + struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX]; struct sock *sk = (struct sock *)msk; unsigned int add_addr_accept_max; struct mptcp_addr_info remote; - struct mptcp_addr_info local; unsigned int subflows_max; + int i, nr;
add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk); subflows_max = mptcp_pm_get_subflows_max(msk); @@@ -501,23 -606,22 +606,22 @@@ if (lookup_subflow_by_daddr(&msk->conn_list, &msk->pm.remote)) goto add_addr_echo;
- msk->pm.add_addr_accepted++; - msk->pm.subflows++; - if (msk->pm.add_addr_accepted >= add_addr_accept_max || - msk->pm.subflows >= subflows_max) - WRITE_ONCE(msk->pm.accept_addr, false); - /* connect to the specified remote address, using whatever * local address the routing configuration will pick. */ remote = msk->pm.remote; if (!remote.port) remote.port = sk->sk_dport; - memset(&local, 0, sizeof(local)); - local.family = remote.family; + nr = fill_local_addresses_vec(msk, addrs); + + msk->pm.add_addr_accepted++; + if (msk->pm.add_addr_accepted >= add_addr_accept_max || + msk->pm.subflows >= subflows_max) + WRITE_ONCE(msk->pm.accept_addr, false);
spin_unlock_bh(&msk->pm.lock); - __mptcp_subflow_connect(sk, &local, &remote, 0, 0); + for (i = 0; i < nr; i++) + __mptcp_subflow_connect(sk, &addrs[i], &remote); spin_lock_bh(&msk->pm.lock);
add_addr_echo: @@@ -899,6 -1003,43 +1003,43 @@@ static const struct nla_policy mptcp_pm [MPTCP_PM_ATTR_SUBFLOWS] = { .type = NLA_U32, }, };
+ void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk) + { + struct mptcp_subflow_context *iter, *subflow = mptcp_subflow_ctx(ssk); + struct sock *sk = (struct sock *)msk; + unsigned int active_max_loss_cnt; + struct net *net = sock_net(sk); + unsigned int stale_loss_cnt; + bool slow; + + stale_loss_cnt = mptcp_stale_loss_cnt(net); + if (subflow->stale || !stale_loss_cnt || subflow->stale_count <= stale_loss_cnt) + return; + + /* look for another available subflow not in loss state */ + active_max_loss_cnt = max_t(int, stale_loss_cnt - 1, 1); + mptcp_for_each_subflow(msk, iter) { + if (iter != subflow && mptcp_subflow_active(iter) && + iter->stale_count < active_max_loss_cnt) { + /* we have some alternatives, try to mark this subflow as idle ...*/ + slow = lock_sock_fast(ssk); + if (!tcp_rtx_and_write_queues_empty(ssk)) { + subflow->stale = 1; + __mptcp_retransmit_pending_data(sk); + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_SUBFLOWSTALE); + } + unlock_sock_fast(ssk, slow); + + /* always try to push the pending data regarless of re-injections: + * we can possibly use backup subflows now, and subflow selection + * is cheap under the msk socket lock + */ + __mptcp_push_pending(sk, 0); + return; + } + } + } + static int mptcp_pm_family_to_addr(int family) { #if IS_ENABLED(CONFIG_MPTCP_IPV6) @@@ -1067,6 -1208,27 +1208,27 @@@ __lookup_addr_by_id(struct pm_nl_perne return NULL; }
+ int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id, + u8 *flags, int *ifindex) + { + struct mptcp_pm_addr_entry *entry; + + *flags = 0; + *ifindex = 0; + + if (id) { + rcu_read_lock(); + entry = __lookup_addr_by_id(net_generic(net, pm_nl_pernet_id), id); + if (entry) { + *flags = entry->flags; + *ifindex = entry->ifindex; + } + rcu_read_unlock(); + } + + return 0; + } + static bool remove_anno_list_by_saddr(struct mptcp_sock *msk, struct mptcp_addr_info *addr) { @@@ -1135,12 -1297,36 +1297,12 @@@ next return 0; }
-struct addr_entry_release_work { - struct rcu_work rwork; - struct mptcp_pm_addr_entry *entry; -}; - -static void mptcp_pm_release_addr_entry(struct work_struct *work) +/* caller must ensure the RCU grace period is already elapsed */ +static void __mptcp_pm_release_addr_entry(struct mptcp_pm_addr_entry *entry) { - struct addr_entry_release_work *w; - struct mptcp_pm_addr_entry *entry; - - w = container_of(to_rcu_work(work), struct addr_entry_release_work, rwork); - entry = w->entry; - if (entry) { - if (entry->lsk) - sock_release(entry->lsk); - kfree(entry); - } - kfree(w); -} - -static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry) -{ - struct addr_entry_release_work *w; - - w = kmalloc(sizeof(*w), GFP_ATOMIC); - if (w) { - INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry); - w->entry = entry; - queue_rcu_work(system_wq, &w->rwork); - } + if (entry->lsk) + sock_release(entry->lsk); + kfree(entry); }
static int mptcp_nl_remove_id_zero_address(struct net *net, @@@ -1220,8 -1406,7 +1382,8 @@@ static int mptcp_nl_cmd_del_addr(struc spin_unlock_bh(&pernet->lock);
mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr); - mptcp_pm_free_addr_entry(entry); + synchronize_rcu(); + __mptcp_pm_release_addr_entry(entry);
return ret; } @@@ -1274,7 -1459,6 +1436,7 @@@ static void mptcp_nl_remove_addrs_list( } }
+/* caller must ensure the RCU grace period is already elapsed */ static void __flush_addrs(struct list_head *list) { while (!list_empty(list)) { @@@ -1283,7 -1467,7 +1445,7 @@@ cur = list_entry(list->next, struct mptcp_pm_addr_entry, list); list_del_rcu(&cur->list); - mptcp_pm_free_addr_entry(cur); + __mptcp_pm_release_addr_entry(cur); } }
@@@ -1307,7 -1491,6 +1469,7 @@@ static int mptcp_nl_cmd_flush_addrs(str bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1); spin_unlock_bh(&pernet->lock); mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list); + synchronize_rcu(); __flush_addrs(&free_list); return 0; } @@@ -1901,6 -2084,7 +2063,7 @@@ static int __net_init pm_nl_init_net(st
INIT_LIST_HEAD_RCU(&pernet->local_addr_list); pernet->next_id = 1; + pernet->stale_loss_cnt = 4; spin_lock_init(&pernet->lock);
/* No need to initialize other pernet fields, the struct is zeroed at @@@ -1918,8 -2102,7 +2081,8 @@@ static void __net_exit pm_nl_exit_net(s struct pm_nl_pernet *pernet = net_generic(net, pm_nl_pernet_id);
/* net is removed from namespace list, can't race with - * other modifiers + * other modifiers, also netns core already waited for a + * RCU grace period. */ __flush_addrs(&pernet->local_addr_list); } diff --combined net/qrtr/qrtr.c index 0c30908628ba,6c61b7b1838f..b8508e35d20e --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@@ -493,7 -493,7 +493,7 @@@ int qrtr_endpoint_post(struct qrtr_endp goto err; }
- if (len != ALIGN(size, 4) + hdrlen) + if (!size || len != ALIGN(size, 4) + hdrlen) goto err;
if (cb->dst_port != QRTR_PORT_CTRL && cb->type != QRTR_TYPE_DATA && @@@ -1157,14 -1157,14 +1157,14 @@@ static int qrtr_ioctl(struct socket *so rc = put_user(len, (int __user *)argp); break; case SIOCGIFADDR: - if (copy_from_user(&ifr, argp, sizeof(ifr))) { + if (get_user_ifreq(&ifr, NULL, argp)) { rc = -EFAULT; break; }
sq = (struct sockaddr_qrtr *)&ifr.ifr_addr; *sq = ipc->us; - if (copy_to_user(argp, &ifr, sizeof(ifr))) { + if (put_user_ifreq(&ifr, argp)) { rc = -EFAULT; break; } diff --combined net/sched/sch_cake.c index 28af8b1e1bb1,ecc5c4d93779..3c2300d14468 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@@ -720,7 -720,7 +720,7 @@@ static u32 cake_hash(struct cake_tin_da skip_hash: if (flow_override) flow_hash = flow_override - 1; - else if (use_skbhash) + else if (use_skbhash && (flow_mode & CAKE_FLOW_FLOWS)) flow_hash = skb->hash; if (host_override) { dsthost_hash = host_override - 1; @@@ -1665,7 -1665,7 +1665,7 @@@ static u32 cake_classify(struct Qdisc * goto hash;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; - result = tcf_classify(skb, filter, &res, false); + result = tcf_classify(skb, NULL, filter, &res, false);
if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT diff --combined net/tipc/socket.c index 8754bd885169,b15b2b1b2f38..e3105ba407c7 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@@ -1518,7 -1518,7 +1518,7 @@@ static int __tipc_sendmsg(struct socke
if (unlikely(syn && !rc)) { tipc_set_sk_state(sk, TIPC_CONNECTING); - if (timeout) { + if (dlen && timeout) { timeout = msecs_to_jiffies(timeout); tipc_wait_for_connect(sock, &timeout); } @@@ -1886,6 -1886,7 +1886,7 @@@ static int tipc_recvmsg(struct socket * bool connected = !tipc_sk_type_connectionless(sk); struct tipc_sock *tsk = tipc_sk(sk); int rc, err, hlen, dlen, copy; + struct tipc_skb_cb *skb_cb; struct sk_buff_head xmitq; struct tipc_msg *hdr; struct sk_buff *skb; @@@ -1909,6 -1910,7 +1910,7 @@@ if (unlikely(rc)) goto exit; skb = skb_peek(&sk->sk_receive_queue); + skb_cb = TIPC_SKB_CB(skb); hdr = buf_msg(skb); dlen = msg_data_sz(hdr); hlen = msg_hdr_sz(hdr); @@@ -1928,18 -1930,33 +1930,33 @@@
/* Capture data if non-error msg, otherwise just set return value */ if (likely(!err)) { - copy = min_t(int, dlen, buflen); - if (unlikely(copy != dlen)) - m->msg_flags |= MSG_TRUNC; - rc = skb_copy_datagram_msg(skb, hlen, m, copy); + int offset = skb_cb->bytes_read; + + copy = min_t(int, dlen - offset, buflen); + rc = skb_copy_datagram_msg(skb, hlen + offset, m, copy); + if (unlikely(rc)) + goto exit; + if (unlikely(offset + copy < dlen)) { + if (flags & MSG_EOR) { + if (!(flags & MSG_PEEK)) + skb_cb->bytes_read = offset + copy; + } else { + m->msg_flags |= MSG_TRUNC; + skb_cb->bytes_read = 0; + } + } else { + if (flags & MSG_EOR) + m->msg_flags |= MSG_EOR; + skb_cb->bytes_read = 0; + } } else { copy = 0; rc = 0; - if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control) + if (err != TIPC_CONN_SHUTDOWN && connected && !m->msg_control) { rc = -ECONNRESET; + goto exit; + } } - if (unlikely(rc)) - goto exit;
/* Mark message as group event if applicable */ if (unlikely(grp_evt)) { @@@ -1962,6 -1979,9 +1979,9 @@@ tipc_node_distr_xmit(sock_net(sk), &xmitq); }
+ if (skb_cb->bytes_read) + goto exit; + tsk_advance_rx_queue(sk);
if (likely(!connected)) diff --combined tools/testing/selftests/Makefile index dd0388eab94d,da9e8b699e42..c852eb40c4f7 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@@ -35,10 -35,10 +35,11 @@@ TARGETS += memory-hotplu TARGETS += mincore TARGETS += mount TARGETS += mount_setattr +TARGETS += move_mount_set_group TARGETS += mqueue TARGETS += nci TARGETS += net + TARGETS += net/af_unix TARGETS += net/forwarding TARGETS += net/mptcp TARGETS += netfilter
linux-merge@lists.open-mesh.org