The following commit has been merged in the master branch: commit e7abe3cdb14177b9af1c5efc7bb59c9fdeea0965 Merge: b144450dbf7358dfbeffd73108f6eeecfcc622eb 938049e18dca57bcd2f93986fc1cbb5a83cdf027 Author: Stephen Rothwell sfr@canb.auug.org.au Date: Fri Aug 21 12:33:04 2015 +1000
Merge remote-tracking branch 'net-next/master'
diff --combined MAINTAINERS index e67ffa2,7b528b8..41b0296 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -158,6 -158,7 +158,7 @@@ L: linux-wpan@vger.kernel.or S: Maintained F: net/6lowpan/ F: include/net/6lowpan.h + F: Documentation/networking/6lowpan.txt
6PACK NETWORK DRIVER FOR AX.25 M: Andreas Koensgen ajk@comnets.uni-bremen.de @@@ -799,13 -800,11 +800,13 @@@ F: arch/arm/include/asm/floppy. ARM PMU PROFILING AND DEBUGGING M: Will Deacon will.deacon@arm.com S: Maintained -F: arch/arm/kernel/perf_event* +F: arch/arm/kernel/perf_* F: arch/arm/oprofile/common.c -F: arch/arm/include/asm/pmu.h F: arch/arm/kernel/hw_breakpoint.c F: arch/arm/include/asm/hw_breakpoint.h +F: arch/arm/include/asm/perf_event.h +F: drivers/perf/arm_pmu.c +F: include/linux/perf/arm_pmu.h
ARM PORT M: Russell King linux@arm.linux.org.uk @@@ -1467,7 -1466,9 +1468,7 @@@ F: arch/arm/boot/dts/emev2 F: arch/arm/boot/dts/r7s* F: arch/arm/boot/dts/r8a* F: arch/arm/boot/dts/sh* -F: arch/arm/configs/armadillo800eva_defconfig F: arch/arm/configs/bockw_defconfig -F: arch/arm/configs/kzm9g_defconfig F: arch/arm/configs/marzen_defconfig F: arch/arm/configs/shmobile_defconfig F: arch/arm/include/debug/renesas-scif.S @@@ -1506,7 -1507,6 +1507,7 @@@ F: arch/arm/boot/dts/sti F: drivers/clocksource/arm_global_timer.c F: drivers/i2c/busses/i2c-st.c F: drivers/media/rc/st_rc.c +F: drivers/media/platform/sti/c8sectpfe/ F: drivers/mmc/host/sdhci-st.c F: drivers/phy/phy-miphy28lp.c F: drivers/phy/phy-miphy365x.c @@@ -1580,10 -1580,7 +1581,10 @@@ ARM/UNIPHIER ARCHITECTUR M: Masahiro Yamada yamada.masahiro@socionext.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: arch/arm/boot/dts/uniphier* F: arch/arm/mach-uniphier/ +F: drivers/pinctrl/uniphier/ +F: drivers/tty/serial/8250/8250_uniphier.c N: uniphier
ARM/Ux500 ARM ARCHITECTURE @@@ -1678,7 -1675,7 +1679,7 @@@ M: Michal Simek <michal.simek@xilinx.co R: Sören Brinkmann soren.brinkmann@xilinx.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://wiki.xilinx.com -T: git git://git.xilinx.com/linux-xlnx.git +T: git https://github.com/Xilinx/linux-xlnx.git S: Supported F: arch/arm/mach-zynq/ F: drivers/cpuidle/cpuidle-zynq.c @@@ -2222,9 -2219,7 +2223,9 @@@ F: drivers/clocksource/bcm_kona_timer. BROADCOM BCM2835 ARM ARCHITECTURE M: Stephen Warren swarren@wwwdotorg.org M: Lee Jones lee@kernel.org +M: Eric Anholt eric@anholt.net L: linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) T: git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git S: Maintained N: bcm2835 @@@ -3593,15 -3588,6 +3594,15 @@@ S: Maintaine F: drivers/gpu/drm/rockchip/ F: Documentation/devicetree/bindings/video/rockchip*
+DRM DRIVERS FOR STI +M: Benjamin Gaignard benjamin.gaignard@linaro.org +M: Vincent Abriou vincent.abriou@st.com +L: dri-devel@lists.freedesktop.org +T: git http://git.linaro.org/people/benjamin.gaignard/kernel.git +S: Maintained +F: drivers/gpu/drm/sti +F: Documentation/devicetree/bindings/gpu/st,stih4xx.txt + DSBR100 USB FM RADIO DRIVER M: Alexey Klimov klimov.linux@gmail.com L: linux-media@vger.kernel.org @@@ -4074,6 -4060,15 +4075,6 @@@ F: Documentation/filesystems/ext2.tx F: fs/ext2/ F: include/linux/ext2*
-EXT3 FILE SYSTEM -M: Jan Kara jack@suse.com -M: Andrew Morton akpm@linux-foundation.org -M: Andreas Dilger adilger.kernel@dilger.ca -L: linux-ext4@vger.kernel.org -S: Maintained -F: Documentation/filesystems/ext3.txt -F: fs/ext3/ - EXT4 FILE SYSTEM M: "Theodore Ts'o" tytso@mit.edu M: Andreas Dilger adilger.kernel@dilger.ca @@@ -4412,7 -4407,6 +4413,7 @@@ F: include/linux/fscache*. F2FS FILE SYSTEM M: Jaegeuk Kim jaegeuk@kernel.org M: Changman Lee cm224.lee@samsung.com +R: Chao Yu chao2.yu@samsung.com L: linux-f2fs-devel@lists.sourceforge.net W: http://en.wikipedia.org/wiki/F2FS T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git @@@ -4421,7 -4415,6 +4422,7 @@@ F: Documentation/filesystems/f2fs.tx F: Documentation/ABI/testing/sysfs-fs-f2fs F: fs/f2fs/ F: include/linux/f2fs_fs.h +F: include/trace/events/f2fs.h
FUJITSU FR-V (FRV) PORT M: David Howells dhowells@redhat.com @@@ -5763,20 -5756,21 +5764,20 @@@ S: Maintaine F: fs/jffs2/ F: include/uapi/linux/jffs2.h
-JOURNALLING LAYER FOR BLOCK DEVICES (JBD) -M: Andrew Morton akpm@linux-foundation.org -M: Jan Kara jack@suse.com -L: linux-ext4@vger.kernel.org -S: Maintained -F: fs/jbd/ -F: include/linux/jbd.h - JOURNALLING LAYER FOR BLOCK DEVICES (JBD2) M: "Theodore Ts'o" tytso@mit.edu +M: Jan Kara jack@suse.com L: linux-ext4@vger.kernel.org S: Maintained F: fs/jbd2/ F: include/linux/jbd2.h
+JPU V4L2 MEM2MEM DRIVER FOR RENESAS +M: Mikhail Ulyanov mikhail.ulyanov@cogentembedded.com +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/rcar_jpu.c + JSM Neo PCI based serial card M: Thadeu Lima de Souza Cascardo cascardo@linux.vnet.ibm.com L: linux-serial@vger.kernel.org @@@ -5903,6 -5897,7 +5904,6 @@@ F: arch/powerpc/kvm KERNEL VIRTUAL MACHINE for s390 (KVM/s390) M: Christian Borntraeger borntraeger@de.ibm.com M: Cornelia Huck cornelia.huck@de.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -6516,7 -6511,7 +6517,7 @@@ F: drivers/net/ethernet/marvell/mvneta.
MARVELL MWIFIEX WIRELESS DRIVER M: Amitkumar Karwar akarwar@marvell.com - M: Avinash Patil patila@marvell.com + M: Nishant Sarmukadam nishants@marvell.com L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/mwifiex/ @@@ -6545,13 -6540,6 +6546,13 @@@ S: Maintaine F: Documentation/hwmon/max16065 F: drivers/hwmon/max16065.c
+MAX20751 HARDWARE MONITOR DRIVER +M: Guenter Roeck linux@roeck-us.net +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/max20751 +F: drivers/hwmon/max20751.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: "Hans J. Koch" hjk@hansjkoch.de L: lm-sensors@lm-sensors.org @@@ -6612,51 -6600,6 +6613,51 @@@ S: Supporte F: Documentation/devicetree/bindings/media/renesas,vsp1.txt F: drivers/media/platform/vsp1/
+MEDIA DRIVERS FOR ASCOT2E +M: Sergey Kozlov serjk@netup.ru +L: linux-media@vger.kernel.org +W: http://linuxtv.org +W: http://netup.tv/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/ascot2e* + +MEDIA DRIVERS FOR CXD2841ER +M: Sergey Kozlov serjk@netup.ru +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://netup.tv/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/cxd2841er* + +MEDIA DRIVERS FOR HORUS3A +M: Sergey Kozlov serjk@netup.ru +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://netup.tv/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/horus3a* + +MEDIA DRIVERS FOR LNBH25 +M: Sergey Kozlov serjk@netup.ru +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://netup.tv/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/dvb-frontends/lnbh25* + +MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices +M: Sergey Kozlov serjk@netup.ru +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://netup.tv/ +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/pci/netup_unidvb/* + MEDIA INPUT INFRASTRUCTURE (V4L/DVB) M: Mauro Carvalho Chehab mchehab@osg.samsung.com P: LinuxTV.org Project @@@ -6706,6 -6649,15 +6707,15 @@@ W: http://www.mellanox.co Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlx4/en_*
+ MELLANOX ETHERNET SWITCH DRIVERS + M: Jiri Pirko jiri@mellanox.com + M: Ido Schimmel idosch@mellanox.com + L: netdev@vger.kernel.org + S: Supported + W: http://www.mellanox.com + Q: http://patchwork.ozlabs.org/project/netdev/list/ + F: drivers/net/ethernet/mellanox/mlxsw/ + MEMORY MANAGEMENT L: linux-mm@kvack.org W: http://www.linux-mm.org @@@ -8133,15 -8085,6 +8143,15 @@@ S: Maintaine F: include/linux/power_supply.h F: drivers/power/
+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 +S: Maintained +F: drivers/firmware/psci.c +F: include/linux/psci.h +F: include/uapi/linux/psci.h + PNP SUPPORT M: "Rafael J. Wysocki" rafael.j.wysocki@intel.com S: Maintained @@@ -8765,6 -8708,7 +8775,6 @@@ F: drivers/video/fbdev/savage S390 M: Martin Schwidefsky schwidefsky@de.ibm.com M: Heiko Carstens heiko.carstens@de.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -8792,6 -8736,7 +8802,6 @@@ F: block/partitions/ibm.
S390 NETWORK DRIVERS M: Ursula Braun ursula.braun@de.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -8808,6 -8753,7 +8818,6 @@@ F: drivers/pci/hotplug/s390_pci_hpc.
S390 ZCRYPT DRIVER M: Ingo Tuchscherer ingo.tuchscherer@de.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -8815,6 -8761,7 +8825,6 @@@ F: drivers/s390/crypto
S390 ZFCP DRIVER M: Steffen Maier maier@linux.vnet.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -8822,6 -8769,7 +8832,6 @@@ F: drivers/s390/scsi/zfcp_
S390 IUCV NETWORK LAYER M: Ursula Braun ursula.braun@de.ibm.com -M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@@ -8974,6 -8922,13 +8984,13 @@@ F: include/linux/dma/dw. F: include/linux/platform_data/dma-dw.h F: drivers/dma/dw/
+ SYNOPSYS DESIGNWARE ETHERNET QOS 4.10a driver + M: Lars Persson lars.persson@axis.com + L: netdev@vger.kernel.org + S: Supported + F: Documentation/devicetree/bindings/net/snps,dwc-qos-ethernet.txt + F: drivers/net/ethernet/synopsys/dwc_eth_qos.c + SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER M: Seungwon Jeon tgih.jun@samsung.com M: Jaehoon Chung jh80.chung@samsung.com @@@ -9938,7 -9893,6 +9955,7 @@@ S: Supporte F: arch/arc/ F: Documentation/devicetree/bindings/arc/ F: drivers/tty/serial/arc_uart.c +T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
SYNOPSYS ARC SDP platform support M: Alexey Brodkin abrodkin@synopsys.com @@@ -10393,13 -10347,6 +10410,13 @@@ F: drivers/char/toshiba. F: include/linux/toshiba.h F: include/uapi/linux/toshiba.h
+TOSHIBA TC358743 DRIVER +M: Mats Randgaard matrandg@cisco.com +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/tc358743* +F: include/media/tc358743.h + TMIO MMC DRIVER M: Ian Molton ian@mnementh.co.uk L: linux-mmc@vger.kernel.org diff --combined arch/arm/boot/dts/am33xx.dtsi index 01a2d94,8b59c86..b222306 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@@ -103,15 -103,6 +103,15 @@@ #size-cells = <1>; ranges = <0 0x44c00000 0x280000>;
+ wkup_m3: wkup_m3@100000 { + compatible = "ti,am3352-wkup-m3"; + reg = <0x100000 0x4000>, + <0x180000 0x2000>; + reg-names = "umem", "dmem"; + ti,hwmods = "wkup_m3"; + ti,pm-firmware = "am335x-pm-firmware.elf"; + }; + prcm: prcm@200000 { compatible = "ti,am3-prcm"; reg = <0x200000 0x4000>; @@@ -153,14 -144,6 +153,14 @@@ }; };
+ wkup_m3_ipc: wkup_m3_ipc@1324 { + compatible = "ti,am3352-wkup-m3-ipc"; + reg = <0x1324 0x24>; + interrupts = <78>; + ti,rproc = <&wkup_m3>; + mboxes = <&mailbox &mbox_wkupm3>; + }; + scm_clockdomains: clockdomains { }; }; @@@ -717,7 -700,7 +717,7 @@@ };
mac: ethernet@4a100000 { - compatible = "ti,cpsw"; + compatible = "ti,am335x-cpsw","ti,cpsw"; ti,hwmods = "cpgmac0"; clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>; clock-names = "fck", "cpts"; @@@ -779,6 -762,14 +779,6 @@@ reg = <0x40300000 0x10000>; /* 64k */ };
- wkup_m3: wkup_m3@44d00000 { - compatible = "ti,am3353-wkup-m3"; - reg = <0x44d00000 0x4000 /* M3 UMEM */ - 0x44d80000 0x2000>; /* M3 DMEM */ - ti,hwmods = "wkup_m3"; - ti,no-reset-on-init; - }; - elm: elm@48080000 { compatible = "ti,am3352-elm"; reg = <0x48080000 0x2000>; diff --combined arch/arm/boot/dts/dra7.dtsi index e4c4380,0001e95..007e16b --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@@ -116,7 -116,7 +116,7 @@@ ranges = <0 0x2000 0x2000>;
scm_conf: scm_conf@0 { - compatible = "syscon"; + compatible = "syscon", "simple-bus"; reg = <0x0 0x1400>; #address-cells = <1>; #size-cells = <1>; @@@ -141,7 -141,7 +141,7 @@@ dra7_pmx_core: pinmux@1400 { compatible = "ti,dra7-padconf", "pinctrl-single"; - reg = <0x1400 0x0464>; + reg = <0x1400 0x0468>; #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; @@@ -149,11 -149,6 +149,11 @@@ pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0x3fffffff>; }; + + scm_conf1: scm_conf@1c04 { + compatible = "syscon"; + reg = <0x1c04 0x0020>; + }; };
cm_core_aon: cm_core_aon@5000 { @@@ -216,7 -211,7 +216,7 @@@ #address-cells = <1>; ranges = <0x51000000 0x51000000 0x3000 0x0 0x20000000 0x10000000>; - pcie@51000000 { + pcie1: pcie@51000000 { compatible = "ti,dra7-pcie"; reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; reg-names = "rc_dbics", "ti_conf", "config"; @@@ -291,6 -286,16 +291,6 @@@ #thermal-sensor-cells = <1>; };
- dra7_ctrl_core: ctrl_core@4a002000 { - compatible = "syscon"; - reg = <0x4a002000 0x6d0>; - }; - - dra7_ctrl_general: tisyscon@4a002e00 { - compatible = "syscon"; - reg = <0x4a002e00 0x7c>; - }; - sdma: dma-controller@4a056000 { compatible = "ti,omap4430-sdma"; reg = <0x4a056000 0x1000>; @@@ -303,15 -308,6 +303,15 @@@ dma-requests = <127>; };
+ sdma_xbar: dma-router@4a002b78 { + compatible = "ti,dra7-dma-crossbar"; + reg = <0x4a002b78 0xfc>; + #dma-cells = <1>; + dma-requests = <205>; + ti,dma-safe-map = <0>; + dma-masters = <&sdma>; + }; + gpio1: gpio@4ae10000 { compatible = "ti,omap4-gpio"; reg = <0x4ae10000 0x200>; @@@ -407,7 -403,7 +407,7 @@@ ti,hwmods = "uart1"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 49>, <&sdma 50>; + dmas = <&sdma_xbar 49>, <&sdma_xbar 50>; dma-names = "tx", "rx"; };
@@@ -418,7 -414,7 +418,7 @@@ ti,hwmods = "uart2"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 51>, <&sdma 52>; + dmas = <&sdma_xbar 51>, <&sdma_xbar 52>; dma-names = "tx", "rx"; };
@@@ -429,7 -425,7 +429,7 @@@ ti,hwmods = "uart3"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 53>, <&sdma 54>; + dmas = <&sdma_xbar 53>, <&sdma_xbar 54>; dma-names = "tx", "rx"; };
@@@ -440,7 -436,7 +440,7 @@@ ti,hwmods = "uart4"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 55>, <&sdma 56>; + dmas = <&sdma_xbar 55>, <&sdma_xbar 56>; dma-names = "tx", "rx"; };
@@@ -451,7 -447,7 +451,7 @@@ ti,hwmods = "uart5"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 63>, <&sdma 64>; + dmas = <&sdma_xbar 63>, <&sdma_xbar 64>; dma-names = "tx", "rx"; };
@@@ -462,7 -458,7 +462,7 @@@ ti,hwmods = "uart6"; clock-frequency = <48000000>; status = "disabled"; - dmas = <&sdma 79>, <&sdma 80>; + dmas = <&sdma_xbar 79>, <&sdma_xbar 80>; dma-names = "tx", "rx"; };
@@@ -871,7 -867,7 +871,7 @@@ ti,hwmods = "mmc1"; ti,dual-volt; ti,needs-special-reset; - dmas = <&sdma 61>, <&sdma 62>; + dmas = <&sdma_xbar 61>, <&sdma_xbar 62>; dma-names = "tx", "rx"; status = "disabled"; pbias-supply = <&pbias_mmc_reg>; @@@ -883,7 -879,7 +883,7 @@@ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc2"; ti,needs-special-reset; - dmas = <&sdma 47>, <&sdma 48>; + dmas = <&sdma_xbar 47>, <&sdma_xbar 48>; dma-names = "tx", "rx"; status = "disabled"; }; @@@ -894,7 -890,7 +894,7 @@@ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc3"; ti,needs-special-reset; - dmas = <&sdma 77>, <&sdma 78>; + dmas = <&sdma_xbar 77>, <&sdma_xbar 78>; dma-names = "tx", "rx"; status = "disabled"; }; @@@ -905,7 -901,7 +905,7 @@@ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; ti,hwmods = "mmc4"; ti,needs-special-reset; - dmas = <&sdma 57>, <&sdma 58>; + dmas = <&sdma_xbar 57>, <&sdma_xbar 58>; dma-names = "tx", "rx"; status = "disabled"; }; @@@ -1050,14 -1046,14 +1050,14 @@@ #size-cells = <0>; ti,hwmods = "mcspi1"; ti,spi-num-cs = <4>; - dmas = <&sdma 35>, - <&sdma 36>, - <&sdma 37>, - <&sdma 38>, - <&sdma 39>, - <&sdma 40>, - <&sdma 41>, - <&sdma 42>; + dmas = <&sdma_xbar 35>, + <&sdma_xbar 36>, + <&sdma_xbar 37>, + <&sdma_xbar 38>, + <&sdma_xbar 39>, + <&sdma_xbar 40>, + <&sdma_xbar 41>, + <&sdma_xbar 42>; dma-names = "tx0", "rx0", "tx1", "rx1", "tx2", "rx2", "tx3", "rx3"; status = "disabled"; @@@ -1071,10 -1067,10 +1071,10 @@@ #size-cells = <0>; ti,hwmods = "mcspi2"; ti,spi-num-cs = <2>; - dmas = <&sdma 43>, - <&sdma 44>, - <&sdma 45>, - <&sdma 46>; + dmas = <&sdma_xbar 43>, + <&sdma_xbar 44>, + <&sdma_xbar 45>, + <&sdma_xbar 46>; dma-names = "tx0", "rx0", "tx1", "rx1"; status = "disabled"; }; @@@ -1087,7 -1083,7 +1087,7 @@@ #size-cells = <0>; ti,hwmods = "mcspi3"; ti,spi-num-cs = <2>; - dmas = <&sdma 15>, <&sdma 16>; + dmas = <&sdma_xbar 15>, <&sdma_xbar 16>; dma-names = "tx0", "rx0"; status = "disabled"; }; @@@ -1100,7 -1096,7 +1100,7 @@@ #size-cells = <0>; ti,hwmods = "mcspi4"; ti,spi-num-cs = <1>; - dmas = <&sdma 70>, <&sdma 71>; + dmas = <&sdma_xbar 70>, <&sdma_xbar 71>; dma-names = "tx0", "rx0"; status = "disabled"; }; @@@ -1300,12 -1296,7 +1300,12 @@@ usb1: usb@48890000 { compatible = "snps,dwc3"; reg = <0x48890000 0x17000>; - interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "peripheral", + "host", + "otg"; phys = <&usb2_phy1>, <&usb3_phy1>; phy-names = "usb2-phy", "usb3-phy"; tx-fifo-resize; @@@ -1328,12 -1319,7 +1328,12 @@@ usb2: usb@488d0000 { compatible = "snps,dwc3"; reg = <0x488d0000 0x17000>; - interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "peripheral", + "host", + "otg"; phys = <&usb2_phy2>; phy-names = "usb2-phy"; tx-fifo-resize; @@@ -1358,12 -1344,7 +1358,12 @@@ usb3: usb@48910000 { compatible = "snps,dwc3"; reg = <0x48910000 0x17000>; - interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "peripheral", + "host", + "otg"; tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; @@@ -1418,7 -1399,7 +1418,7 @@@ };
mac: ethernet@4a100000 { - compatible = "ti,cpsw"; + compatible = "ti,dra7-cpsw","ti,cpsw"; ti,hwmods = "gmac"; clocks = <&dpll_gmac_ck>, <&gmac_gmii_ref_clk_div>; clock-names = "fck", "cpts"; diff --combined drivers/base/property.c index 37a7bb7,4c20828..287704d --- a/drivers/base/property.c +++ b/drivers/base/property.c @@@ -16,6 -16,8 +16,8 @@@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/property.h> + #include <linux/etherdevice.h> + #include <linux/phy.h>
/** * device_add_property_set - Add a collection of properties to a device object. @@@ -27,10 -29,9 +29,10 @@@ */ void device_add_property_set(struct device *dev, struct property_set *pset) { - if (pset) - pset->fwnode.type = FWNODE_PDATA; + if (!pset) + return;
+ pset->fwnode.type = FWNODE_PDATA; set_secondary_fwnode(dev, &pset->fwnode); } EXPORT_SYMBOL_GPL(device_add_property_set); @@@ -534,3 -535,79 +536,79 @@@ bool device_dma_is_coherent(struct devi return coherent; } EXPORT_SYMBOL_GPL(device_dma_is_coherent); + + /** + * device_get_phy_mode - Get phy mode for given device + * @dev: Pointer to the given device + * + * The function gets phy interface string from property 'phy-mode' or + * 'phy-connection-type', and return its index in phy_modes table, or errno in + * error case. + */ + int device_get_phy_mode(struct device *dev) + { + const char *pm; + int err, i; + + err = device_property_read_string(dev, "phy-mode", &pm); + if (err < 0) + err = device_property_read_string(dev, + "phy-connection-type", &pm); + if (err < 0) + return err; + + for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) + if (!strcasecmp(pm, phy_modes(i))) + return i; + + return -ENODEV; + } + EXPORT_SYMBOL_GPL(device_get_phy_mode); + + static void *device_get_mac_addr(struct device *dev, + const char *name, char *addr, + int alen) + { + int ret = device_property_read_u8_array(dev, name, addr, alen); + + if (ret == 0 && alen == ETH_ALEN && is_valid_ether_addr(addr)) + return addr; + return NULL; + } + + /** + * device_get_mac_address - Get the MAC for a given device + * @dev: Pointer to the device + * @addr: Address of buffer to store the MAC in + * @alen: Length of the buffer pointed to by addr, should be ETH_ALEN + * + * Search the firmware node for the best MAC address to use. 'mac-address' is + * checked first, because that is supposed to contain to "most recent" MAC + * address. If that isn't set, then 'local-mac-address' is checked next, + * because that is the default address. If that isn't set, then the obsolete + * 'address' is checked, just in case we're using an old device tree. + * + * Note that the 'address' property is supposed to contain a virtual address of + * the register set, but some DTS files have redefined that property to be the + * MAC address. + * + * All-zero MAC addresses are rejected, because those could be properties that + * exist in the firmware tables, but were not updated by the firmware. For + * example, the DTS could define 'mac-address' and 'local-mac-address', with + * zero MAC addresses. Some older U-Boots only initialized 'local-mac-address'. + * In this case, the real MAC is in 'local-mac-address', and 'mac-address' + * exists but is all zeros. + */ + void *device_get_mac_address(struct device *dev, char *addr, int alen) + { + addr = device_get_mac_addr(dev, "mac-address", addr, alen); + if (addr) + return addr; + + addr = device_get_mac_addr(dev, "local-mac-address", addr, alen); + if (addr) + return addr; + + return device_get_mac_addr(dev, "address", addr, alen); + } + EXPORT_SYMBOL(device_get_mac_address); diff --combined drivers/net/ethernet/emulex/benet/be_main.c index 6ca693b,15cc3a1..12687bf --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@@ -681,11 -681,14 +681,14 @@@ void be_link_status_update(struct be_ad static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb) { struct be_tx_stats *stats = tx_stats(txo); + u64 tx_pkts = skb_shinfo(skb)->gso_segs ? : 1;
u64_stats_update_begin(&stats->sync); stats->tx_reqs++; stats->tx_bytes += skb->len; - stats->tx_pkts += (skb_shinfo(skb)->gso_segs ? : 1); + stats->tx_pkts += tx_pkts; + if (skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) + stats->tx_vxlan_offload_pkts += tx_pkts; u64_stats_update_end(&stats->sync); }
@@@ -1258,7 -1261,7 +1261,7 @@@ static bool be_send_pkt_to_bmc(struct b if (is_udp_pkt((*skb))) { struct udphdr *udp = udp_hdr((*skb));
- switch (udp->dest) { + switch (ntohs(udp->dest)) { case DHCP_CLIENT_PORT: os2bmc = is_dhcp_client_filt_enabled(adapter); goto done; @@@ -1961,6 -1964,8 +1964,8 @@@ static void be_rx_stats_update(struct b stats->rx_compl++; stats->rx_bytes += rxcp->pkt_size; stats->rx_pkts++; + if (rxcp->tunneled) + stats->rx_vxlan_offload_pkts++; if (rxcp->pkt_type == BE_MULTICAST_PACKET) stats->rx_mcast_pkts++; if (rxcp->err) @@@ -3610,15 -3615,15 +3615,15 @@@ err
static int be_setup_wol(struct be_adapter *adapter, bool enable) { + struct device *dev = &adapter->pdev->dev; struct be_dma_mem cmd; - int status = 0; u8 mac[ETH_ALEN]; + int status;
eth_zero_addr(mac);
cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_KERNEL); + cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL); if (!cmd.va) return -ENOMEM;
@@@ -3627,24 -3632,18 +3632,18 @@@ PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK); if (status) { - dev_err(&adapter->pdev->dev, - "Could not enable Wake-on-lan\n"); - dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, - cmd.dma); - return status; + dev_err(dev, "Could not enable Wake-on-lan\n"); + goto err; } - status = be_cmd_enable_magic_wol(adapter, - adapter->netdev->dev_addr, - &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 1); - pci_enable_wake(adapter->pdev, PCI_D3cold, 1); } else { - status = be_cmd_enable_magic_wol(adapter, mac, &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 0); - pci_enable_wake(adapter->pdev, PCI_D3cold, 0); + ether_addr_copy(mac, adapter->netdev->dev_addr); }
- dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); + status = be_cmd_enable_magic_wol(adapter, mac, &cmd); + pci_enable_wake(adapter->pdev, PCI_D3hot, enable); + pci_enable_wake(adapter->pdev, PCI_D3cold, enable); + err: + dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma); return status; }
@@@ -4977,7 -4976,7 +4976,7 @@@ static bool be_check_ufi_compatibility( { if (!fhdr) { dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); - return -1; + return false; }
/* First letter of the build version is used to identify @@@ -5132,9 -5131,6 +5131,6 @@@ static int be_ndo_bridge_getlink(struc int status = 0; u8 hsw_mode;
- if (!sriov_enabled(adapter)) - return 0; - /* BE and Lancer chips support VEB mode only */ if (BEx_chip(adapter) || lancer_chip(adapter)) { hsw_mode = PORT_FWD_TYPE_VEB; @@@ -5144,6 -5140,9 +5140,9 @@@ NULL); if (status) return 0; + + if (hsw_mode == PORT_FWD_TYPE_PASSTHRU) + return 0; }
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, @@@ -5174,7 -5173,7 +5173,7 @@@ static void be_add_vxlan_port(struct ne struct device *dev = &adapter->pdev->dev; int status;
- if (lancer_chip(adapter) || BEx_chip(adapter)) + if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter)) return;
if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) { @@@ -5221,7 -5220,7 +5220,7 @@@ static void be_del_vxlan_port(struct ne { struct be_adapter *adapter = netdev_priv(netdev);
- if (lancer_chip(adapter) || BEx_chip(adapter)) + if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter)) return;
if (adapter->vxlan_port != port) @@@ -5278,6 -5277,27 +5277,27 @@@ static netdev_features_t be_features_ch } #endif
+ static int be_get_phys_port_id(struct net_device *dev, + struct netdev_phys_item_id *ppid) + { + int i, id_len = CNTL_SERIAL_NUM_WORDS * CNTL_SERIAL_NUM_WORD_SZ + 1; + struct be_adapter *adapter = netdev_priv(dev); + u8 *id; + + if (MAX_PHYS_ITEM_ID_LEN < id_len) + return -ENOSPC; + + ppid->id[0] = adapter->hba_port_num + 1; + id = &ppid->id[1]; + for (i = CNTL_SERIAL_NUM_WORDS - 1; i >= 0; + i--, id += CNTL_SERIAL_NUM_WORD_SZ) + memcpy(id, &adapter->serial_num[i], CNTL_SERIAL_NUM_WORD_SZ); + + ppid->id_len = id_len; + + return 0; + } + static const struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@@ -5308,6 -5328,7 +5328,7 @@@ .ndo_del_vxlan_port = be_del_vxlan_port, .ndo_features_check = be_features_check, #endif + .ndo_get_phys_port_id = be_get_phys_port_id, };
static void be_netdev_init(struct net_device *netdev) @@@ -5866,7 -5887,6 +5887,6 @@@ static int be_pci_resume(struct pci_de if (status) return status;
- pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev);
status = be_resume(adapter); @@@ -5946,7 -5966,6 +5966,6 @@@ static pci_ers_result_t be_eeh_reset(st return PCI_ERS_RESULT_DISCONNECT;
pci_set_master(pdev); - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev);
/* Check if card is ok and fw is ready */ diff --combined drivers/net/ethernet/freescale/gianfar.c index 10b3bbbb,087ffcd..4b69d061 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@@ -109,15 -109,15 +109,15 @@@
#define TX_TIMEOUT (1*HZ)
- const char gfar_driver_version[] = "1.3"; + const char gfar_driver_version[] = "2.0";
static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); - static struct sk_buff *gfar_new_skb(struct net_device *dev, - dma_addr_t *bufaddr); + static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id); @@@ -141,8 -141,7 +141,7 @@@ static void gfar_netpoll(struct net_dev #endif int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); - static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi); + static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb); static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, @@@ -169,17 -168,15 +168,15 @@@ static void gfar_init_rxbdp(struct gfar bdp->lstatus = cpu_to_be32(lstatus); }
- static int gfar_init_bds(struct net_device *ndev) + static void gfar_init_bds(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); struct gfar __iomem *regs = priv->gfargrp[0].regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; - struct rxbd8 *rxbdp; u32 __iomem *rfbptr; int i, j; - dma_addr_t bufaddr;
for (i = 0; i < priv->num_tx_queues; i++) { tx_queue = priv->tx_queue[i]; @@@ -207,40 -204,26 +204,26 @@@ rfbptr = ®s->rfbptr0; for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->cur_rx = rx_queue->rx_bd_base; - rx_queue->skb_currx = 0; - rxbdp = rx_queue->rx_bd_base;
- for (j = 0; j < rx_queue->rx_ring_size; j++) { - struct sk_buff *skb = rx_queue->rx_skbuff[j]; + rx_queue->next_to_clean = 0; + rx_queue->next_to_use = 0; + rx_queue->next_to_alloc = 0;
- if (skb) { - bufaddr = be32_to_cpu(rxbdp->bufPtr); - } else { - skb = gfar_new_skb(ndev, &bufaddr); - if (!skb) { - netdev_err(ndev, "Can't allocate RX buffers\n"); - return -ENOMEM; - } - rx_queue->rx_skbuff[j] = skb; - } - - gfar_init_rxbdp(rx_queue, rxbdp, bufaddr); - rxbdp++; - } + /* make sure next_to_clean != next_to_use after this + * by leaving at least 1 unused descriptor + */ + gfar_alloc_rx_buffs(rx_queue, gfar_rxbd_unused(rx_queue));
rx_queue->rfbptr = rfbptr; rfbptr += 2; } - - return 0; }
static int gfar_alloc_skb_resources(struct net_device *ndev) { void *vaddr; dma_addr_t addr; - int i, j, k; + int i, j; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = priv->dev; struct gfar_priv_tx_q *tx_queue = NULL; @@@ -279,7 -262,8 +262,8 @@@ rx_queue = priv->rx_queue[i]; rx_queue->rx_bd_base = vaddr; rx_queue->rx_bd_dma_base = addr; - rx_queue->dev = ndev; + rx_queue->ndev = ndev; + rx_queue->dev = dev; addr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; } @@@ -294,25 -278,20 +278,20 @@@ if (!tx_queue->tx_skbuff) goto cleanup;
- for (k = 0; k < tx_queue->tx_ring_size; k++) - tx_queue->tx_skbuff[k] = NULL; + for (j = 0; j < tx_queue->tx_ring_size; j++) + tx_queue->tx_skbuff[j] = NULL; }
for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->rx_skbuff = - kmalloc_array(rx_queue->rx_ring_size, - sizeof(*rx_queue->rx_skbuff), - GFP_KERNEL); - if (!rx_queue->rx_skbuff) + rx_queue->rx_buff = kcalloc(rx_queue->rx_ring_size, + sizeof(*rx_queue->rx_buff), + GFP_KERNEL); + if (!rx_queue->rx_buff) goto cleanup; - - for (j = 0; j < rx_queue->rx_ring_size; j++) - rx_queue->rx_skbuff[j] = NULL; }
- if (gfar_init_bds(ndev)) - goto cleanup; + gfar_init_bds(ndev);
return 0;
@@@ -354,10 -333,8 +333,8 @@@ static void gfar_init_rqprm(struct gfar } }
- static void gfar_rx_buff_size_config(struct gfar_private *priv) + static void gfar_rx_offload_en(struct gfar_private *priv) { - int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN; - /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0;
@@@ -366,16 -343,6 +343,6 @@@
if (priv->hwts_rx_en) priv->uses_rxfcb = 1; - - if (priv->uses_rxfcb) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - - frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + - INCREMENTAL_BUFFER_SIZE; - - priv->rx_buffer_size = frame_size; }
static void gfar_mac_rx_config(struct gfar_private *priv) @@@ -593,9 -560,8 +560,8 @@@ static int gfar_alloc_rx_queues(struct if (!priv->rx_queue[i]) return -ENOMEM;
- priv->rx_queue[i]->rx_skbuff = NULL; priv->rx_queue[i]->qindex = i; - priv->rx_queue[i]->dev = priv->ndev; + priv->rx_queue[i]->ndev = priv->ndev; } return 0; } @@@ -1187,12 -1153,11 +1153,11 @@@ void gfar_mac_reset(struct gfar_privat
udelay(3);
- /* Compute rx_buff_size based on config flags */ - gfar_rx_buff_size_config(priv); + gfar_rx_offload_en(priv);
/* Initialize the max receive frame/buffer lengths */ - gfar_write(®s->maxfrm, priv->rx_buffer_size); - gfar_write(®s->mrblr, priv->rx_buffer_size); + gfar_write(®s->maxfrm, GFAR_JUMBO_FRAME_SIZE); + gfar_write(®s->mrblr, GFAR_RXB_SIZE);
/* Initialize the Minimum Frame Length Register */ gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); @@@ -1200,12 -1165,11 +1165,11 @@@ /* Initialize MACCFG2. */ tempval = MACCFG2_INIT_SETTINGS;
- /* If the mtu is larger than the max size for standard - * ethernet frames (ie, a jumbo frame), then set maccfg2 - * to allow huge frames, and to check the length + /* eTSEC74 erratum: Rx frames of length MAXFRM or MAXFRM-1 + * are marked as truncated. Avoid this by MACCFG2[Huge Frame]=1, + * and by checking RxBD[LG] and discarding larger than MAXFRM. */ - if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || - gfar_has_errata(priv, GFAR_ERRATA_74)) + if (gfar_has_errata(priv, GFAR_ERRATA_74)) tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
gfar_write(®s->maccfg2, tempval); @@@ -1415,8 -1379,6 +1379,6 @@@ static int gfar_probe(struct platform_d priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) dev->needed_headroom = GMAC_FCB_LEN;
- priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; - /* Initializing some of the rx/tx queue level parameters */ for (i = 0; i < priv->num_tx_queues; i++) { priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE; @@@ -1599,10 -1561,7 +1561,7 @@@ static int gfar_restore(struct device * return 0; }
- if (gfar_init_bds(ndev)) { - free_skb_resources(priv); - return -ENOMEM; - } + gfar_init_bds(ndev);
gfar_mac_reset(priv);
@@@ -1893,26 -1852,32 +1852,32 @@@ static void free_skb_tx_queue(struct gf
static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) { - struct rxbd8 *rxbdp; - struct gfar_private *priv = netdev_priv(rx_queue->dev); int i;
- rxbdp = rx_queue->rx_bd_base; + struct rxbd8 *rxbdp = rx_queue->rx_bd_base; + + if (rx_queue->skb) + dev_kfree_skb(rx_queue->skb);
for (i = 0; i < rx_queue->rx_ring_size; i++) { - if (rx_queue->rx_skbuff[i]) { - dma_unmap_single(priv->dev, be32_to_cpu(rxbdp->bufPtr), - priv->rx_buffer_size, - DMA_FROM_DEVICE); - dev_kfree_skb_any(rx_queue->rx_skbuff[i]); - rx_queue->rx_skbuff[i] = NULL; - } + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[i]; + rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; + + if (!rxb->page) + continue; + + dma_unmap_single(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(rxb->page); + + rxb->page = NULL; } - kfree(rx_queue->rx_skbuff); - rx_queue->rx_skbuff = NULL; + + kfree(rx_queue->rx_buff); + rx_queue->rx_buff = NULL; }
/* If there are any tx skbs or rx skbs still around, free them. @@@ -1937,7 -1902,7 +1902,7 @@@ static void free_skb_resources(struct g
for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - if (rx_queue->rx_skbuff) + if (rx_queue->rx_buff) free_skb_rx_queue(rx_queue); }
@@@ -2102,11 -2067,6 +2067,11 @@@ int startup_gfar(struct net_device *nde /* Start Rx/Tx DMA and enable the interrupts */ gfar_start(priv);
+ /* force link state update after mac reset */ + priv->oldlink = 0; + priv->oldspeed = 0; + priv->oldduplex = -1; + phy_start(priv->phydev);
enable_napi(priv); @@@ -2500,7 -2460,7 +2465,7 @@@ static int gfar_change_mtu(struct net_d struct gfar_private *priv = netdev_priv(dev); int frame_size = new_mtu + ETH_HLEN;
- if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { + if ((frame_size < 64) || (frame_size > GFAR_JUMBO_FRAME_SIZE)) { netif_err(priv, drv, dev, "Invalid MTU setting\n"); return -EINVAL; } @@@ -2554,15 -2514,6 +2519,6 @@@ static void gfar_timeout(struct net_dev schedule_work(&priv->reset_task); }
- static void gfar_align_skb(struct sk_buff *skb) - { - /* We need the data buffer to be aligned properly. We will reserve - * as many bytes as needed to align the data properly - */ - skb_reserve(skb, RXBUF_ALIGNMENT - - (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1))); - } - /* Interrupt Handler for Transmit complete */ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) { @@@ -2620,7 -2571,8 +2576,8 @@@
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { struct skb_shared_hwtstamps shhwtstamps; - u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7); + u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) & + ~0x7UL);
memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(*ns); @@@ -2669,49 -2621,85 +2626,85 @@@ netdev_tx_completed_queue(txq, howmany, bytes_sent); }
- static struct sk_buff *gfar_alloc_skb(struct net_device *dev) + static bool gfar_new_page(struct gfar_priv_rx_q *rxq, struct gfar_rx_buff *rxb) { - struct gfar_private *priv = netdev_priv(dev); - struct sk_buff *skb; + struct page *page; + dma_addr_t addr;
- skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (!skb) - return NULL; + page = dev_alloc_page(); + if (unlikely(!page)) + return false;
- gfar_align_skb(skb); + addr = dma_map_page(rxq->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(rxq->dev, addr))) { + __free_page(page);
- return skb; + return false; + } + + rxb->dma = addr; + rxb->page = page; + rxb->page_offset = 0; + + return true; }
- static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) + static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) { - struct gfar_private *priv = netdev_priv(dev); - struct sk_buff *skb; - dma_addr_t addr; + struct gfar_private *priv = netdev_priv(rx_queue->ndev); + struct gfar_extra_stats *estats = &priv->extra_stats;
- skb = gfar_alloc_skb(dev); - if (!skb) - return NULL; + netdev_err(rx_queue->ndev, "Can't alloc RX buffers\n"); + atomic64_inc(&estats->rx_alloc_err); + }
- addr = dma_map_single(priv->dev, skb->data, - priv->rx_buffer_size, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(priv->dev, addr))) { - dev_kfree_skb_any(skb); - return NULL; + static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt) + { + struct rxbd8 *bdp; + struct gfar_rx_buff *rxb; + int i; + + i = rx_queue->next_to_use; + bdp = &rx_queue->rx_bd_base[i]; + rxb = &rx_queue->rx_buff[i]; + + while (alloc_cnt--) { + /* try reuse page */ + if (unlikely(!rxb->page)) { + if (unlikely(!gfar_new_page(rx_queue, rxb))) { + gfar_rx_alloc_err(rx_queue); + break; + } + } + + /* Setup the new RxBD */ + gfar_init_rxbdp(rx_queue, bdp, + rxb->dma + rxb->page_offset + RXBUF_ALIGNMENT); + + /* Update to the next pointer */ + bdp++; + rxb++; + + if (unlikely(++i == rx_queue->rx_ring_size)) { + i = 0; + bdp = rx_queue->rx_bd_base; + rxb = rx_queue->rx_buff; + } }
- *bufaddr = addr; - return skb; + rx_queue->next_to_use = i; + rx_queue->next_to_alloc = i; }
- static inline void count_errors(unsigned short status, struct net_device *dev) + static void count_errors(u32 lstatus, struct net_device *ndev) { - struct gfar_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; + struct gfar_private *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; struct gfar_extra_stats *estats = &priv->extra_stats;
/* If the packet was truncated, none of the other errors matter */ - if (status & RXBD_TRUNCATED) { + if (lstatus & BD_LFLAG(RXBD_TRUNCATED)) { stats->rx_length_errors++;
atomic64_inc(&estats->rx_trunc); @@@ -2719,25 -2707,25 +2712,25 @@@ return; } /* Count the errors, if there were any */ - if (status & (RXBD_LARGE | RXBD_SHORT)) { + if (lstatus & BD_LFLAG(RXBD_LARGE | RXBD_SHORT)) { stats->rx_length_errors++;
- if (status & RXBD_LARGE) + if (lstatus & BD_LFLAG(RXBD_LARGE)) atomic64_inc(&estats->rx_large); else atomic64_inc(&estats->rx_short); } - if (status & RXBD_NONOCTET) { + if (lstatus & BD_LFLAG(RXBD_NONOCTET)) { stats->rx_frame_errors++; atomic64_inc(&estats->rx_nonoctet); } - if (status & RXBD_CRCERR) { + if (lstatus & BD_LFLAG(RXBD_CRCERR)) { atomic64_inc(&estats->rx_crcerr); stats->rx_crc_errors++; } - if (status & RXBD_OVERRUN) { + if (lstatus & BD_LFLAG(RXBD_OVERRUN)) { atomic64_inc(&estats->rx_overrun); - stats->rx_crc_errors++; + stats->rx_over_errors++; } }
@@@ -2788,6 -2776,93 +2781,93 @@@ static irqreturn_t gfar_transmit(int ir return IRQ_HANDLED; }
+ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + struct sk_buff *skb, bool first) + { + unsigned int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; + + /* Remove the FCS from the packet length */ + if (likely(lstatus & BD_LFLAG(RXBD_LAST))) + size -= ETH_FCS_LEN; + + if (likely(first)) + skb_put(skb, size); + else + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); + + /* try reuse page */ + if (unlikely(page_count(page) != 1)) + return false; + + /* change offset to the other half */ + rxb->page_offset ^= GFAR_RXB_TRUESIZE; + + atomic_inc(&page->_count); + + return true; + } + + static void gfar_reuse_rx_page(struct gfar_priv_rx_q *rxq, + struct gfar_rx_buff *old_rxb) + { + struct gfar_rx_buff *new_rxb; + u16 nta = rxq->next_to_alloc; + + new_rxb = &rxq->rx_buff[nta]; + + /* find next buf that can reuse a page */ + nta++; + rxq->next_to_alloc = (nta < rxq->rx_ring_size) ? nta : 0; + + /* copy page reference */ + *new_rxb = *old_rxb; + + /* sync for use by the device */ + dma_sync_single_range_for_device(rxq->dev, old_rxb->dma, + old_rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); + } + + static struct sk_buff *gfar_get_next_rxbuff(struct gfar_priv_rx_q *rx_queue, + u32 lstatus, struct sk_buff *skb) + { + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[rx_queue->next_to_clean]; + struct page *page = rxb->page; + bool first = false; + + if (likely(!skb)) { + void *buff_addr = page_address(page) + rxb->page_offset; + + skb = build_skb(buff_addr, GFAR_SKBFRAG_SIZE); + if (unlikely(!skb)) { + gfar_rx_alloc_err(rx_queue); + return NULL; + } + skb_reserve(skb, RXBUF_ALIGNMENT); + first = true; + } + + dma_sync_single_range_for_cpu(rx_queue->dev, rxb->dma, rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); + + if (gfar_add_rx_frag(rxb, lstatus, skb, first)) { + /* reuse the free half of the page */ + gfar_reuse_rx_page(rx_queue, rxb); + } else { + /* page cannot be reused, unmap it */ + dma_unmap_page(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + } + + /* clear rxb content */ + rxb->page = NULL; + + return skb; + } + static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) { /* If valid headers were found, and valid sums @@@ -2802,10 -2877,9 +2882,9 @@@ }
/* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ - static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi) + static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); struct rxfcb *fcb = NULL;
/* fcb is at the beginning if exists */ @@@ -2814,10 -2888,8 +2893,8 @@@ /* Remove the FCB from the skb * Remove the padded bytes, if there are any */ - if (amount_pull) { - skb_record_rx_queue(skb, fcb->rq); - skb_pull(skb, amount_pull); - } + if (priv->uses_rxfcb) + skb_pull(skb, GMAC_FCB_LEN);
/* Get receive timestamp from the skb */ if (priv->hwts_rx_en) { @@@ -2831,24 -2903,20 +2908,20 @@@ if (priv->padding) skb_pull(skb, priv->padding);
- if (dev->features & NETIF_F_RXCSUM) + if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb);
/* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + skb->protocol = eth_type_trans(skb, ndev);
/* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. * Even if vlan rx accel is disabled, on some chips * RXFCB_VLN is pseudo randomly set. */ - if (dev->features & NETIF_F_HW_VLAN_CTAG_RX && + if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX && be16_to_cpu(fcb->flags) & RXFCB_VLN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(fcb->vlctl)); - - /* Send the packet up the stack */ - napi_gro_receive(napi, skb); - }
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring @@@ -2857,91 -2925,89 +2930,89 @@@ */ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { - struct net_device *dev = rx_queue->dev; - struct rxbd8 *bdp, *base; - struct sk_buff *skb; - int pkt_len; - int amount_pull; - int howmany = 0; - struct gfar_private *priv = netdev_priv(dev); + struct net_device *ndev = rx_queue->ndev; + struct gfar_private *priv = netdev_priv(ndev); + struct rxbd8 *bdp; + int i, howmany = 0; + struct sk_buff *skb = rx_queue->skb; + int cleaned_cnt = gfar_rxbd_unused(rx_queue); + unsigned int total_bytes = 0, total_pkts = 0;
/* Get the first full descriptor */ - bdp = rx_queue->cur_rx; - base = rx_queue->rx_bd_base; + i = rx_queue->next_to_clean;
- amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0; + while (rx_work_limit--) { + u32 lstatus; + + if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) { + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); + cleaned_cnt = 0; + }
- while (!(be16_to_cpu(bdp->status) & RXBD_EMPTY) && rx_work_limit--) { - struct sk_buff *newskb; - dma_addr_t bufaddr; + bdp = &rx_queue->rx_bd_base[i]; + lstatus = be32_to_cpu(bdp->lstatus); + if (lstatus & BD_LFLAG(RXBD_EMPTY)) + break;
+ /* order rx buffer descriptor reads */ rmb();
- /* Add another skb for the future */ - newskb = gfar_new_skb(dev, &bufaddr); + /* fetch next to clean buffer from the ring */ + skb = gfar_get_next_rxbuff(rx_queue, lstatus, skb); + if (unlikely(!skb)) + break;
- skb = rx_queue->rx_skbuff[rx_queue->skb_currx]; + cleaned_cnt++; + howmany++;
- dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), - priv->rx_buffer_size, DMA_FROM_DEVICE); - - if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_ERR) && - be16_to_cpu(bdp->length) > priv->rx_buffer_size)) - bdp->status = cpu_to_be16(RXBD_LARGE); - - /* We drop the frame if we failed to allocate a new buffer */ - if (unlikely(!newskb || - !(be16_to_cpu(bdp->status) & RXBD_LAST) || - be16_to_cpu(bdp->status) & RXBD_ERR)) { - count_errors(be16_to_cpu(bdp->status), dev); - - if (unlikely(!newskb)) { - newskb = skb; - bufaddr = be32_to_cpu(bdp->bufPtr); - } else if (skb) - dev_kfree_skb(skb); - } else { - /* Increment the number of packets */ - rx_queue->stats.rx_packets++; - howmany++; - - if (likely(skb)) { - pkt_len = be16_to_cpu(bdp->length) - - ETH_FCS_LEN; - /* Remove the FCS from the packet length */ - skb_put(skb, pkt_len); - rx_queue->stats.rx_bytes += pkt_len; - skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(dev, skb, amount_pull, - &rx_queue->grp->napi_rx); + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0;
- } else { - netif_warn(priv, rx_err, dev, "Missing skb!\n"); - rx_queue->stats.rx_dropped++; - atomic64_inc(&priv->extra_stats.rx_skbmissing); - } + rx_queue->next_to_clean = i; + + /* fetch next buffer if not the last in frame */ + if (!(lstatus & BD_LFLAG(RXBD_LAST))) + continue; + + if (unlikely(lstatus & BD_LFLAG(RXBD_ERR))) { + count_errors(lstatus, ndev);
+ /* discard faulty buffer */ + dev_kfree_skb(skb); + skb = NULL; + rx_queue->stats.rx_dropped++; + continue; }
- rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb; + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len;
- /* Setup the new bdp */ - gfar_init_rxbdp(rx_queue, bdp, bufaddr); + skb_record_rx_queue(skb, rx_queue->qindex);
- /* Update Last Free RxBD pointer for LFC */ - if (unlikely(rx_queue->rfbptr && priv->tx_actual_en)) - gfar_write(rx_queue->rfbptr, (u32)bdp); + gfar_process_frame(ndev, skb);
- /* Update to the next pointer */ - bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb);
- /* update to point at the next skb */ - rx_queue->skb_currx = (rx_queue->skb_currx + 1) & - RX_RING_MOD_MASK(rx_queue->rx_ring_size); + skb = NULL; }
- /* Update the current rxbd pointer to be the next one */ - rx_queue->cur_rx = bdp; + /* Store incomplete frames for completion */ + rx_queue->skb = skb; + + rx_queue->stats.rx_packets += total_pkts; + rx_queue->stats.rx_bytes += total_bytes; + + if (cleaned_cnt) + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); + + /* Update Last Free RxBD pointer for LFC */ + if (unlikely(priv->tx_actual_en)) { + u32 bdp_dma = gfar_rxbd_dma_lastfree(rx_queue); + + gfar_write(rx_queue->rfbptr, bdp_dma); + }
return howmany; } @@@ -3459,7 -3525,6 +3530,6 @@@ static noinline void gfar_update_link_s struct phy_device *phydev = priv->phydev; struct gfar_priv_rx_q *rx_queue = NULL; int i; - struct rxbd8 *bdp;
if (unlikely(test_bit(GFAR_RESETTING, &priv->state))) return; @@@ -3516,15 -3581,11 +3586,11 @@@ /* Turn last free buffer recording on */ if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) { for (i = 0; i < priv->num_rx_queues; i++) { + u32 bdp_dma; + rx_queue = priv->rx_queue[i]; - bdp = rx_queue->cur_rx; - /* skip to previous bd */ - bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1, - rx_queue->rx_bd_base, - rx_queue->rx_ring_size); - - if (rx_queue->rfbptr) - gfar_write(rx_queue->rfbptr, (u32)bdp); + bdp_dma = gfar_rxbd_dma_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, bdp_dma); }
priv->tx_actual_en = 1; diff --combined drivers/net/phy/phy.c index 1e1fbb0,84b1fba..d972851 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@@ -353,6 -353,8 +353,8 @@@ int phy_ethtool_sset(struct phy_device
phydev->duplex = cmd->duplex;
+ phydev->mdix = cmd->eth_tp_mdix_ctrl; + /* Restart the PHY */ phy_start_aneg(phydev);
@@@ -377,6 -379,7 +379,7 @@@ int phy_ethtool_gset(struct phy_device cmd->transceiver = phy_is_internal(phydev) ? XCVR_INTERNAL : XCVR_EXTERNAL; cmd->autoneg = phydev->autoneg; + cmd->eth_tp_mdix_ctrl = phydev->mdix;
return 0; } @@@ -811,7 -814,6 +814,7 @@@ void phy_state_machine(struct work_stru bool needs_aneg = false, do_suspend = false; enum phy_state old_state; int err = 0; + int old_link;
mutex_lock(&phydev->lock);
@@@ -897,18 -899,11 +900,18 @@@ phydev->adjust_link(phydev->attached_dev); break; case PHY_RUNNING: - /* Only register a CHANGE if we are - * polling or ignoring interrupts + /* Only register a CHANGE if we are polling or ignoring + * interrupts and link changed since latest checking. */ - if (!phy_interrupt_is_valid(phydev)) - phydev->state = PHY_CHANGELINK; + if (!phy_interrupt_is_valid(phydev)) { + old_link = phydev->link; + err = phy_read_status(phydev); + if (err) + break; + + if (old_link != phydev->link) + phydev->state = PHY_CHANGELINK; + } break; case PHY_CHANGELINK: err = phy_read_status(phydev); diff --combined drivers/net/usb/qmi_wwan.c index 64a60af,1f7a7cd..6392ae3 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@@ -785,7 -785,7 +785,8 @@@ static const struct usb_device_id produ {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
/* 4. Gobi 1000 devices */ diff --combined include/net/lwtunnel.h index 0000000,cfee539..b3faea9 mode 000000,100644..100644 --- a/include/net/lwtunnel.h +++ b/include/net/lwtunnel.h @@@ -1,0 -1,184 +1,179 @@@ + #ifndef __NET_LWTUNNEL_H + #define __NET_LWTUNNEL_H 1 + + #include <linux/lwtunnel.h> + #include <linux/netdevice.h> + #include <linux/skbuff.h> + #include <linux/types.h> + #include <net/route.h> + + #define LWTUNNEL_HASH_BITS 7 + #define LWTUNNEL_HASH_SIZE (1 << LWTUNNEL_HASH_BITS) + + /* lw tunnel state flags */ + #define LWTUNNEL_STATE_OUTPUT_REDIRECT BIT(0) + #define LWTUNNEL_STATE_INPUT_REDIRECT BIT(1) + + struct lwtunnel_state { + __u16 type; + __u16 flags; + atomic_t refcnt; + int (*orig_output)(struct sock *sk, struct sk_buff *skb); + int (*orig_input)(struct sk_buff *); + int len; + __u8 data[0]; + }; + + struct lwtunnel_encap_ops { + int (*build_state)(struct net_device *dev, struct nlattr *encap, + struct lwtunnel_state **ts); + int (*output)(struct sock *sk, struct sk_buff *skb); + int (*input)(struct sk_buff *skb); + int (*fill_encap)(struct sk_buff *skb, + struct lwtunnel_state *lwtstate); + int (*get_encap_size)(struct lwtunnel_state *lwtstate); + int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b); + }; + + #ifdef CONFIG_LWTUNNEL -static inline void lwtstate_free(struct lwtunnel_state *lws) -{ - kfree(lws); -} - + static inline struct lwtunnel_state * + lwtstate_get(struct lwtunnel_state *lws) + { + if (lws) + atomic_inc(&lws->refcnt); + + return lws; + } + + static inline void lwtstate_put(struct lwtunnel_state *lws) + { + if (!lws) + return; + + if (atomic_dec_and_test(&lws->refcnt)) - lwtstate_free(lws); ++ kfree(lws); + } + + static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) + { + if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT)) + return true; + + return false; + } + + static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate) + { + if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_INPUT_REDIRECT)) + return true; + + return false; + } + int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); + int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); + int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + struct lwtunnel_state **lws); + int lwtunnel_fill_encap(struct sk_buff *skb, + struct lwtunnel_state *lwtstate); + int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate); + struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len); + int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b); + int lwtunnel_output(struct sock *sk, struct sk_buff *skb); + int lwtunnel_output6(struct sock *sk, struct sk_buff *skb); + int lwtunnel_input(struct sk_buff *skb); + int lwtunnel_input6(struct sk_buff *skb); + + #else + + static inline void lwtstate_free(struct lwtunnel_state *lws) + { + } + + static inline struct lwtunnel_state * + lwtstate_get(struct lwtunnel_state *lws) + { + return lws; + } + + static inline void lwtstate_put(struct lwtunnel_state *lws) + { + } + + static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) + { + return false; + } + + static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate) + { + return false; + } + + static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, + unsigned int num) + { + return -EOPNOTSUPP; + + } + + static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + unsigned int num) + { + return -EOPNOTSUPP; + } + + static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + struct lwtunnel_state **lws) + { + return -EOPNOTSUPP; + } + + static inline int lwtunnel_fill_encap(struct sk_buff *skb, + struct lwtunnel_state *lwtstate) + { + return 0; + } + + static inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) + { + return 0; + } + + static inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len) + { + return NULL; + } + + static inline int lwtunnel_cmp_encap(struct lwtunnel_state *a, + struct lwtunnel_state *b) + { + return 0; + } + + static inline int lwtunnel_output(struct sock *sk, struct sk_buff *skb) + { + return -EOPNOTSUPP; + } + + static inline int lwtunnel_output6(struct sock *sk, struct sk_buff *skb) + { + return -EOPNOTSUPP; + } + + static inline int lwtunnel_input(struct sk_buff *skb) + { + return -EOPNOTSUPP; + } + + static inline int lwtunnel_input6(struct sk_buff *skb) + { + return -EOPNOTSUPP; + } + + #endif + + #endif /* __NET_LWTUNNEL_H */ diff --combined kernel/events/core.c index e6feb51,e2c6a88..a1339b1 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@@ -1868,6 -1868,8 +1868,6 @@@ event_sched_in(struct perf_event *event
perf_pmu_disable(event->pmu);
- event->tstamp_running += tstamp - event->tstamp_stopped; - perf_set_shadow_time(event, ctx, tstamp);
perf_log_itrace_start(event); @@@ -1879,8 -1881,6 +1879,8 @@@ goto out; }
+ event->tstamp_running += tstamp - event->tstamp_stopped; + if (!is_software_event(event)) cpuctx->active_oncpu++; if (!ctx->nr_active++) @@@ -3212,6 -3212,59 +3212,59 @@@ static inline u64 perf_event_count(stru return __perf_event_count(event); }
+ /* + * NMI-safe method to read a local event, that is an event that + * is: + * - either for the current task, or for this CPU + * - does not have inherit set, for inherited task events + * will not be local and we cannot read them atomically + * - must not have a pmu::count method + */ + u64 perf_event_read_local(struct perf_event *event) + { + unsigned long flags; + u64 val; + + /* + * Disabling interrupts avoids all counter scheduling (context + * switches, timer based rotation and IPIs). + */ + local_irq_save(flags); + + /* If this is a per-task event, it must be for current */ + WARN_ON_ONCE((event->attach_state & PERF_ATTACH_TASK) && + event->hw.target != current); + + /* If this is a per-CPU event, it must be for this CPU */ + WARN_ON_ONCE(!(event->attach_state & PERF_ATTACH_TASK) && + event->cpu != smp_processor_id()); + + /* + * It must not be an event with inherit set, we cannot read + * all child counters from atomic context. + */ + WARN_ON_ONCE(event->attr.inherit); + + /* + * It must not have a pmu::count method, those are not + * NMI safe. + */ + WARN_ON_ONCE(event->pmu->count); + + /* + * If the event is currently on this CPU, its either a per-task event, + * or local to this CPU. Furthermore it means its ACTIVE (otherwise + * oncpu == -1). + */ + if (event->oncpu == smp_processor_id()) + event->pmu->read(event); + + val = local64_read(&event->count); + local_irq_restore(flags); + + return val; + } + static u64 perf_event_read(struct perf_event *event) { /* @@@ -3958,21 -4011,28 +4011,21 @@@ static void perf_event_for_each(struct perf_event_for_each_child(sibling, func); }
-static int perf_event_period(struct perf_event *event, u64 __user *arg) -{ - struct perf_event_context *ctx = event->ctx; - int ret = 0, active; +struct period_event { + struct perf_event *event; u64 value; +};
- if (!is_sampling_event(event)) - return -EINVAL; - - if (copy_from_user(&value, arg, sizeof(value))) - return -EFAULT; - - if (!value) - return -EINVAL; +static int __perf_event_period(void *info) +{ + struct period_event *pe = info; + struct perf_event *event = pe->event; + struct perf_event_context *ctx = event->ctx; + u64 value = pe->value; + bool active;
- raw_spin_lock_irq(&ctx->lock); + raw_spin_lock(&ctx->lock); if (event->attr.freq) { - if (value > sysctl_perf_event_sample_rate) { - ret = -EINVAL; - goto unlock; - } - event->attr.sample_freq = value; } else { event->attr.sample_period = value; @@@ -3991,53 -4051,11 +4044,53 @@@ event->pmu->start(event, PERF_EF_RELOAD); perf_pmu_enable(ctx->pmu); } + raw_spin_unlock(&ctx->lock);
-unlock: + return 0; +} + +static int perf_event_period(struct perf_event *event, u64 __user *arg) +{ + struct period_event pe = { .event = event, }; + struct perf_event_context *ctx = event->ctx; + struct task_struct *task; + u64 value; + + if (!is_sampling_event(event)) + return -EINVAL; + + if (copy_from_user(&value, arg, sizeof(value))) + return -EFAULT; + + if (!value) + return -EINVAL; + + if (event->attr.freq && value > sysctl_perf_event_sample_rate) + return -EINVAL; + + task = ctx->task; + pe.value = value; + + if (!task) { + cpu_function_call(event->cpu, __perf_event_period, &pe); + return 0; + } + +retry: + if (!task_function_call(task, __perf_event_period, &pe)) + return 0; + + raw_spin_lock_irq(&ctx->lock); + if (ctx->is_active) { + raw_spin_unlock_irq(&ctx->lock); + task = ctx->task; + goto retry; + } + + __perf_event_period(&pe); raw_spin_unlock_irq(&ctx->lock);
- return ret; + return 0; }
static const struct file_operations perf_fops; @@@ -4775,20 -4793,12 +4828,20 @@@ static const struct file_operations per * to user-space before waking everybody up. */
+static inline struct fasync_struct **perf_event_fasync(struct perf_event *event) +{ + /* only the parent has fasync state */ + if (event->parent) + event = event->parent; + return &event->fasync; +} + void perf_event_wakeup(struct perf_event *event) { ring_buffer_wakeup(event);
if (event->pending_kill) { - kill_fasync(&event->fasync, SIGIO, event->pending_kill); + kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill); event->pending_kill = 0; } } @@@ -6167,7 -6177,7 +6220,7 @@@ static int __perf_event_overflow(struc else perf_event_output(event, data, regs);
- if (event->fasync && event->pending_kill) { + if (*perf_event_fasync(event) && event->pending_kill) { event->pending_wakeup = 1; irq_work_queue(&event->pending); } @@@ -8617,6 -8627,31 +8670,31 @@@ void perf_event_delayed_put(struct task WARN_ON_ONCE(task->perf_event_ctxp[ctxn]); }
+ struct perf_event *perf_event_get(unsigned int fd) + { + int err; + struct fd f; + struct perf_event *event; + + err = perf_fget_light(fd, &f); + if (err) + return ERR_PTR(err); + + event = f.file->private_data; + atomic_long_inc(&event->refcount); + fdput(f); + + return event; + } + + const struct perf_event_attr *perf_event_attrs(struct perf_event *event) + { + if (!event) + return ERR_PTR(-EINVAL); + + return &event->attr; + } + /* * inherit a event from parent task to child task: */ diff --combined net/batman-adv/translation-table.c index 5809b39,db06de2..c1eb7b7 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@@ -19,6 -19,7 +19,7 @@@ #include "main.h"
#include <linux/atomic.h> + #include <linux/bitops.h> #include <linux/bug.h> #include <linux/byteorder/generic.h> #include <linux/compiler.h> @@@ -595,11 -596,8 +596,11 @@@ bool batadv_tt_local_add(struct net_dev /* increase the refcounter of the related vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", - addr, BATADV_PRINT_VID(vid))) + addr, BATADV_PRINT_VID(vid))) { + kfree(tt_local); + tt_local = NULL; goto out; + }
batadv_dbg(BATADV_DBG_TT, bat_priv, "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", @@@ -1882,7 -1880,7 +1883,7 @@@ void batadv_tt_global_del_orig(struct b } spin_unlock_bh(list_lock); } - orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT; + clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); }
static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, @@@ -2215,7 -2213,7 +2216,7 @@@ static void batadv_tt_req_list_free(str spin_lock_bh(&bat_priv->tt.req_list_lock);
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { - list_del(&node->list); + list_del_init(&node->list); kfree(node); }
@@@ -2251,7 -2249,7 +2252,7 @@@ static void batadv_tt_req_purge(struct list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (batadv_has_timed_out(node->issued_at, BATADV_TT_REQUEST_TIMEOUT)) { - list_del(&node->list); + list_del_init(&node->list); kfree(node); } } @@@ -2533,7 -2531,8 +2534,8 @@@ out batadv_hardif_free_ref(primary_if); if (ret && tt_req_node) { spin_lock_bh(&bat_priv->tt.req_list_lock); - list_del(&tt_req_node->list); + /* list_del_init() verifies tt_req_node still is in the list */ + list_del_init(&tt_req_node->list); spin_unlock_bh(&bat_priv->tt.req_list_lock); kfree(tt_req_node); } @@@ -2841,7 -2840,7 +2843,7 @@@ static void _batadv_tt_update_changes(s return; } } - orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT; + set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized); }
static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, @@@ -2970,7 -2969,7 +2972,7 @@@ static void batadv_handle_tt_response(s list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (!batadv_compare_eth(node->addr, resp_src)) continue; - list_del(&node->list); + list_del_init(&node->list); kfree(node); }
@@@ -3343,7 -3342,8 +3345,8 @@@ static void batadv_tt_update_orig(struc bool has_tt_init;
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; - has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT; + has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT, + &orig_node->capa_initialized);
/* orig table not initialised AND first diff is in the OGM OR the ttvn * increased by one -> we can apply the attached changes diff --combined net/bridge/br_multicast.c index 1285eaf,0752796..66efdc2 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@@ -283,6 -283,8 +283,8 @@@ static void br_multicast_del_pg(struct rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); + br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB, + p->state); call_rcu_bh(&p->rcu, br_multicast_free_pg);
if (!mp->ports && !mp->mglist && @@@ -704,7 -706,7 +706,7 @@@ static int br_multicast_add_group(struc if (unlikely(!p)) goto err; rcu_assign_pointer(*pp, p); - br_mdb_notify(br->dev, port, group, RTM_NEWMDB); + br_mdb_notify(br->dev, port, group, RTM_NEWMDB, MDB_TEMPORARY);
found: mod_timer(&p->timer, now + br->multicast_membership_interval); @@@ -764,6 -766,7 +766,7 @@@ static void br_multicast_router_expired goto out;
hlist_del_init_rcu(&port->rlist); + br_rtr_notify(br->dev, port, RTM_DELMDB);
out: spin_unlock(&br->multicast_lock); @@@ -924,6 -927,15 +927,15 @@@ void br_multicast_add_port(struct net_b
void br_multicast_del_port(struct net_bridge_port *port) { + struct net_bridge *br = port->br; + struct net_bridge_port_group *pg; + struct hlist_node *n; + + /* Take care of the remaining groups, only perm ones should be left */ + spin_lock_bh(&br->multicast_lock); + hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) + br_multicast_del_pg(br, pg); + spin_unlock_bh(&br->multicast_lock); del_timer_sync(&port->multicast_router_timer); }
@@@ -963,10 -975,13 +975,13 @@@ void br_multicast_disable_port(struct n
spin_lock(&br->multicast_lock); hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) - br_multicast_del_pg(br, pg); + if (pg->state == MDB_TEMPORARY) + br_multicast_del_pg(br, pg);
- if (!hlist_unhashed(&port->rlist)) + if (!hlist_unhashed(&port->rlist)) { hlist_del_init_rcu(&port->rlist); + br_rtr_notify(br->dev, port, RTM_DELMDB); + } del_timer(&port->multicast_router_timer); del_timer(&port->ip4_own_query.timer); #if IS_ENABLED(CONFIG_IPV6) @@@ -1204,6 -1219,7 +1219,7 @@@ static void br_multicast_add_router(str hlist_add_behind_rcu(&port->rlist, slot); else hlist_add_head_rcu(&port->rlist, &br->router_list); + br_rtr_notify(br->dev, port, RTM_NEWMDB); }
static void br_multicast_mark_router(struct net_bridge *br, @@@ -1437,7 -1453,8 +1453,8 @@@ br_multicast_leave_group(struct net_bri hlist_del_init(&p->mglist); del_timer(&p->timer); call_rcu_bh(&p->rcu, br_multicast_free_pg); - br_mdb_notify(br->dev, port, group, RTM_DELMDB); + br_mdb_notify(br->dev, port, group, RTM_DELMDB, + p->state);
if (!mp->ports && !mp->mglist && netif_running(br->dev)) @@@ -1591,7 -1608,7 +1608,7 @@@ static int br_multicast_ipv4_rcv(struc break; }
- if (skb_trimmed) + if (skb_trimmed && skb_trimmed != skb) kfree_skb(skb_trimmed);
return err; @@@ -1636,7 -1653,7 +1653,7 @@@ static int br_multicast_ipv6_rcv(struc break; }
- if (skb_trimmed) + if (skb_trimmed && skb_trimmed != skb) kfree_skb(skb_trimmed);
return err; @@@ -1754,12 -1771,6 +1771,6 @@@ void br_multicast_open(struct net_bridg
void br_multicast_stop(struct net_bridge *br) { - struct net_bridge_mdb_htable *mdb; - struct net_bridge_mdb_entry *mp; - struct hlist_node *n; - u32 ver; - int i; - del_timer_sync(&br->multicast_router_timer); del_timer_sync(&br->ip4_other_query.timer); del_timer_sync(&br->ip4_own_query.timer); @@@ -1767,6 -1778,15 +1778,15 @@@ del_timer_sync(&br->ip6_other_query.timer); del_timer_sync(&br->ip6_own_query.timer); #endif + } + + void br_multicast_dev_del(struct net_bridge *br) + { + struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; + struct hlist_node *n; + u32 ver; + int i;
spin_lock_bh(&br->multicast_lock); mdb = mlock_dereference(br->mdb, br); @@@ -1834,8 -1854,10 +1854,10 @@@ int br_multicast_set_port_router(struc p->multicast_router = val; err = 0;
- if (val < 2 && !hlist_unhashed(&p->rlist)) + if (val < 2 && !hlist_unhashed(&p->rlist)) { hlist_del_init_rcu(&p->rlist); + br_rtr_notify(br->dev, p, RTM_DELMDB); + }
if (val == 1) break; diff --combined net/ipv4/fib_semantics.c index 3a06586,01f1c7d..95c9b86 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@@ -42,6 -42,7 +42,7 @@@ #include <net/ip_fib.h> #include <net/netlink.h> #include <net/nexthop.h> + #include <net/lwtunnel.h>
#include "fib_lookup.h"
@@@ -208,6 -209,7 +209,7 @@@ static void free_fib_info_rcu(struct rc change_nexthops(fi) { if (nexthop_nh->nh_dev) dev_put(nexthop_nh->nh_dev); + lwtstate_put(nexthop_nh->nh_lwtstate); free_nh_exceptions(nexthop_nh); rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); rt_fibinfo_free(&nexthop_nh->nh_rth_input); @@@ -266,6 -268,7 +268,7 @@@ static inline int nh_comp(const struct #ifdef CONFIG_IP_ROUTE_CLASSID nh->nh_tclassid != onh->nh_tclassid || #endif + lwtunnel_cmp_encap(nh->nh_lwtstate, onh->nh_lwtstate) || ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK)) return -1; onh++; @@@ -366,6 -369,7 +369,7 @@@ static inline size_t fib_nlmsg_size(str payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
if (fi->fib_nhs) { + size_t nh_encapsize = 0; /* Also handles the special case fib_nhs == 1 */
/* each nexthop is packed in an attribute */ @@@ -374,8 -378,21 +378,21 @@@ /* may contain flow and gateway attribute */ nhsize += 2 * nla_total_size(4);
+ /* grab encap info */ + for_nexthops(fi) { + if (nh->nh_lwtstate) { + /* RTA_ENCAP_TYPE */ + nh_encapsize += lwtunnel_get_encap_size( + nh->nh_lwtstate); + /* RTA_ENCAP */ + nh_encapsize += nla_total_size(2); + } + } endfor_nexthops(fi); + /* all nexthops are packed in a nested attribute */ - payload += nla_total_size(fi->fib_nhs * nhsize); + payload += nla_total_size((fi->fib_nhs * nhsize) + + nh_encapsize); + }
return payload; @@@ -421,13 -438,15 +438,15 @@@ static int fib_detect_death(struct fib_ if (n) { state = n->nud_state; neigh_release(n); + } else { + return 0; } if (state == NUD_REACHABLE) return 0; if ((state & NUD_VALID) && order != dflt) return 0; if ((state & NUD_VALID) || - (*last_idx < 0 && order > dflt)) { + (*last_idx < 0 && order > dflt && state != NUD_INCOMPLETE)) { *last_resort = fi; *last_idx = order; } @@@ -452,6 -471,9 +471,9 @@@ static int fib_count_nexthops(struct rt static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, int remaining, struct fib_config *cfg) { + struct net *net = cfg->fc_nlinfo.nl_net; + int ret; + change_nexthops(fi) { int attrlen;
@@@ -475,18 -497,68 +497,66 @@@ if (nexthop_nh->nh_tclassid) fi->fib_net->ipv4.fib_num_tclassid_users++; #endif + nla = nla_find(attrs, attrlen, RTA_ENCAP); + if (nla) { + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; + struct nlattr *nla_entype; + + nla_entype = nla_find(attrs, attrlen, + RTA_ENCAP_TYPE); + if (!nla_entype) + goto err_inval; + if (cfg->fc_oif) + dev = __dev_get_by_index(net, cfg->fc_oif); + ret = lwtunnel_build_state(dev, nla_get_u16( + nla_entype), + nla, &lwtstate); + if (ret) + goto errout; + nexthop_nh->nh_lwtstate = + lwtstate_get(lwtstate); + } }
rtnh = rtnh_next(rtnh, &remaining); } endfor_nexthops(fi);
return 0; + + err_inval: + ret = -EINVAL; + + errout: + return ret; }
#endif
+ static int fib_encap_match(struct net *net, u16 encap_type, + struct nlattr *encap, + int oif, const struct fib_nh *nh) + { + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; - int ret, result = 0; ++ int ret; + + if (encap_type == LWTUNNEL_ENCAP_NONE) + return 0; + + if (oif) + dev = __dev_get_by_index(net, oif); + ret = lwtunnel_build_state(dev, encap_type, + encap, &lwtstate); - if (!ret) { - result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate); - lwtstate_free(lwtstate); - } ++ if (!ret) ++ return lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate); + - return result; ++ return 0; + } + int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) { + struct net *net = cfg->fc_nlinfo.nl_net; #ifdef CONFIG_IP_ROUTE_MULTIPATH struct rtnexthop *rtnh; int remaining; @@@ -496,6 -568,12 +566,12 @@@ return 1;
if (cfg->fc_oif || cfg->fc_gw) { + if (cfg->fc_encap) { + if (fib_encap_match(net, cfg->fc_encap_type, + cfg->fc_encap, cfg->fc_oif, + fi->fib_nh)) + return 1; + } if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) return 0; @@@ -594,16 -672,18 +670,18 @@@ static int fib_check_nh(struct fib_conf struct fib_result res;
if (nh->nh_flags & RTNH_F_ONLINK) { + unsigned int addr_type;
if (cfg->fc_scope >= RT_SCOPE_LINK) return -EINVAL; - if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST) - return -EINVAL; dev = __dev_get_by_index(net, nh->nh_oif); if (!dev) return -ENODEV; if (!(dev->flags & IFF_UP)) return -ENETDOWN; + addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw); + if (addr_type != RTN_UNICAST) + return -EINVAL; if (!netif_carrier_ok(dev)) nh->nh_flags |= RTNH_F_LINKDOWN; nh->nh_dev = dev; @@@ -613,6 -693,7 +691,7 @@@ } rcu_read_lock(); { + struct fib_table *tbl = NULL; struct flowi4 fl4 = { .daddr = nh->nh_gw, .flowi4_scope = cfg->fc_scope + 1, @@@ -623,8 -704,24 +702,24 @@@ /* It is not necessary, but requires a bit of thinking */ if (fl4.flowi4_scope < RT_SCOPE_LINK) fl4.flowi4_scope = RT_SCOPE_LINK; - err = fib_lookup(net, &fl4, &res, - FIB_LOOKUP_IGNORE_LINKSTATE); + + if (cfg->fc_table) + tbl = fib_get_table(net, cfg->fc_table); + + if (tbl) + err = fib_table_lookup(tbl, &fl4, &res, + FIB_LOOKUP_IGNORE_LINKSTATE | + FIB_LOOKUP_NOREF); + + /* on error or if no table given do full lookup. This + * is needed for example when nexthops are in the local + * table rather than the given table + */ + if (!tbl || err) { + err = fib_lookup(net, &fl4, &res, + FIB_LOOKUP_IGNORE_LINKSTATE); + } + if (err) { rcu_read_unlock(); return err; @@@ -760,6 -857,23 +855,23 @@@ __be32 fib_info_update_nh_saddr(struct return nh->nh_saddr; }
+ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) + { + if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || + fib_prefsrc != cfg->fc_dst) { + int tb_id = cfg->fc_table; + + if (tb_id == RT_TABLE_MAIN) + tb_id = RT_TABLE_LOCAL; + + if (inet_addr_type_table(cfg->fc_nlinfo.nl_net, + fib_prefsrc, tb_id) != RTN_LOCAL) { + return false; + } + } + return true; + } + struct fib_info *fib_create_info(struct fib_config *cfg) { int err; @@@ -882,6 -996,21 +994,21 @@@ } else { struct fib_nh *nh = fi->fib_nh;
+ if (cfg->fc_encap) { + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; + + if (cfg->fc_encap_type == LWTUNNEL_ENCAP_NONE) + goto err_inval; + if (cfg->fc_oif) + dev = __dev_get_by_index(net, cfg->fc_oif); + err = lwtunnel_build_state(dev, cfg->fc_encap_type, + cfg->fc_encap, &lwtstate); + if (err) + goto failure; + + nh->nh_lwtstate = lwtstate_get(lwtstate); + } nh->nh_oif = cfg->fc_oif; nh->nh_gw = cfg->fc_gw; nh->nh_flags = cfg->fc_flags; @@@ -940,12 -1069,8 +1067,8 @@@ fi->fib_flags |= RTNH_F_LINKDOWN; }
- if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || - fi->fib_prefsrc != cfg->fc_dst) - if (inet_addr_type(net, fi->fib_prefsrc) != RTN_LOCAL) - goto err_inval; - } + if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) + goto err_inval;
change_nexthops(fi) { fib_info_update_nh_saddr(net, nexthop_nh); @@@ -1055,6 -1180,8 +1178,8 @@@ int fib_dump_info(struct sk_buff *skb, nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) goto nla_put_failure; #endif + if (fi->fib_nh->nh_lwtstate) + lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate); } #ifdef CONFIG_IP_ROUTE_MULTIPATH if (fi->fib_nhs > 1) { @@@ -1090,6 -1217,8 +1215,8 @@@ nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) goto nla_put_failure; #endif + if (nh->nh_lwtstate) + lwtunnel_fill_encap(skb, nh->nh_lwtstate); /* length of rtnetlink header + attributes */ rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; } endfor_nexthops(fi); diff --combined net/ipv4/fib_trie.c index b0c6258,1243c79..5154f81 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@@ -1423,8 -1423,11 +1423,11 @@@ found nh->nh_flags & RTNH_F_LINKDOWN && !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE)) continue; - if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) - continue; + if (!(flp->flowi4_flags & FLOWI_FLAG_VRFSRC)) { + if (flp->flowi4_oif && + flp->flowi4_oif != nh->nh_oif) + continue; + }
if (!(fib_flags & FIB_LOOKUP_NOREF)) atomic_inc(&fi->fib_clntref); @@@ -2465,7 -2468,7 +2468,7 @@@ static struct key_vector *fib_route_get key = l->key + 1; iter->pos++;
- if (pos-- <= 0) + if (--pos <= 0) break;
l = NULL; diff --combined net/ipv6/ip6_fib.c index 548c623,5693b5e..20a1b85 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@@ -32,6 -32,7 +32,7 @@@ #include <net/ipv6.h> #include <net/ndisc.h> #include <net/addrconf.h> + #include <net/lwtunnel.h>
#include <net/ip6_fib.h> #include <net/ip6_route.h> @@@ -172,13 -173,12 +173,14 @@@ static void rt6_free_pcpu(struct rt6_in *ppcpu_rt = NULL; } } + + non_pcpu_rt->rt6i_pcpu = NULL; }
static void rt6_release(struct rt6_info *rt) { if (atomic_dec_and_test(&rt->rt6i_ref)) { + lwtstate_put(rt->rt6i_lwtstate); rt6_free_pcpu(rt); dst_free(&rt->dst); } diff --combined net/ipv6/route.c index d155864,c373304..8c985a1 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@@ -58,6 -58,7 +58,7 @@@ #include <net/netevent.h> #include <net/netlink.h> #include <net/nexthop.h> + #include <net/lwtunnel.h>
#include <asm/uaccess.h>
@@@ -318,7 -319,8 +319,7 @@@ static const struct rt6_info ip6_blk_ho /* allocate dst with ip6_dst_ops */ static struct rt6_info *__ip6_dst_alloc(struct net *net, struct net_device *dev, - int flags, - struct fib6_table *table) + int flags) { struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0, DST_OBSOLETE_FORCE_CHK, flags); @@@ -335,9 -337,10 +336,9 @@@
static struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev, - int flags, - struct fib6_table *table) + int flags) { - struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table); + struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
if (rt) { rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC); @@@ -542,6 -545,7 +543,7 @@@ static void rt6_probe_deferred(struct w
static void rt6_probe(struct rt6_info *rt) { + struct __rt6_probe_work *work; struct neighbour *neigh; /* * Okay, this does not seem to be appropriate @@@ -556,34 -560,33 +558,33 @@@ rcu_read_lock_bh(); neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); if (neigh) { - write_lock(&neigh->lock); if (neigh->nud_state & NUD_VALID) goto out; - } - - if (!neigh || - time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { - struct __rt6_probe_work *work;
+ work = NULL; + write_lock(&neigh->lock); + if (!(neigh->nud_state & NUD_VALID) && + time_after(jiffies, + neigh->updated + + rt->rt6i_idev->cnf.rtr_probe_interval)) { + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) + __neigh_set_probe_once(neigh); + } + write_unlock(&neigh->lock); + } else { work = kmalloc(sizeof(*work), GFP_ATOMIC); + }
- if (neigh && work) - __neigh_set_probe_once(neigh); - - if (neigh) - write_unlock(&neigh->lock); + if (work) { + INIT_WORK(&work->work, rt6_probe_deferred); + work->target = rt->rt6i_gateway; + dev_hold(rt->dst.dev); + work->dev = rt->dst.dev; + schedule_work(&work->work); + }
- if (work) { - INIT_WORK(&work->work, rt6_probe_deferred); - work->target = rt->rt6i_gateway; - dev_hold(rt->dst.dev); - work->dev = rt->dst.dev; - schedule_work(&work->work); - } - } else { out: - write_unlock(&neigh->lock); - } rcu_read_unlock_bh(); } #else @@@ -662,6 -665,12 +663,12 @@@ static struct rt6_info *find_match(stru { int m; bool match_do_rr = false; + struct inet6_dev *idev = rt->rt6i_idev; + struct net_device *dev = rt->dst.dev; + + if (dev && !netif_carrier_ok(dev) && + idev->cnf.ignore_routes_with_linkdown) + goto out;
if (rt6_check_expired(rt)) goto out; @@@ -948,7 -957,8 +955,7 @@@ static struct rt6_info *ip6_rt_cache_al if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) ort = (struct rt6_info *)ort->dst.from;
- rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, - 0, ort->rt6i_table); + rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
if (!rt) return NULL; @@@ -980,7 -990,8 +987,7 @@@ static struct rt6_info *ip6_rt_pcpu_all struct rt6_info *pcpu_rt;
pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev), - rt->dst.dev, rt->dst.flags, - rt->rt6i_table); + rt->dst.dev, rt->dst.flags);
if (!pcpu_rt) return NULL; @@@ -993,53 -1004,32 +1000,53 @@@ /* It should be called with read_lock_bh(&tb6_lock) acquired */ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) { - struct rt6_info *pcpu_rt, *prev, **p; + struct rt6_info *pcpu_rt, **p;
p = this_cpu_ptr(rt->rt6i_pcpu); pcpu_rt = *p;
- if (pcpu_rt) - goto done; + if (pcpu_rt) { + dst_hold(&pcpu_rt->dst); + rt6_dst_from_metrics_check(pcpu_rt); + } + return pcpu_rt; +} + +static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt) +{ + struct fib6_table *table = rt->rt6i_table; + struct rt6_info *pcpu_rt, *prev, **p;
pcpu_rt = ip6_rt_pcpu_alloc(rt); if (!pcpu_rt) { struct net *net = dev_net(rt->dst.dev);
- pcpu_rt = net->ipv6.ip6_null_entry; - goto done; + dst_hold(&net->ipv6.ip6_null_entry->dst); + return net->ipv6.ip6_null_entry; }
- prev = cmpxchg(p, NULL, pcpu_rt); - if (prev) { - /* If someone did it before us, return prev instead */ + read_lock_bh(&table->tb6_lock); + if (rt->rt6i_pcpu) { + p = this_cpu_ptr(rt->rt6i_pcpu); + prev = cmpxchg(p, NULL, pcpu_rt); + if (prev) { + /* If someone did it before us, return prev instead */ + dst_destroy(&pcpu_rt->dst); + pcpu_rt = prev; + } + } else { + /* rt has been removed from the fib6 tree + * before we have a chance to acquire the read_lock. + * In this case, don't brother to create a pcpu rt + * since rt is going away anyway. The next + * dst_check() will trigger a re-lookup. + */ dst_destroy(&pcpu_rt->dst); - pcpu_rt = prev; + pcpu_rt = rt; } - -done: dst_hold(&pcpu_rt->dst); rt6_dst_from_metrics_check(pcpu_rt); + read_unlock_bh(&table->tb6_lock); return pcpu_rt; }
@@@ -1114,22 -1104,9 +1121,22 @@@ redo_rt6_select rt->dst.lastuse = jiffies; rt->dst.__use++; pcpu_rt = rt6_get_pcpu_route(rt); - read_unlock_bh(&table->tb6_lock); + + if (pcpu_rt) { + read_unlock_bh(&table->tb6_lock); + } else { + /* We have to do the read_unlock first + * because rt6_make_pcpu_route() may trigger + * ip6_dst_gc() which will take the write_lock. + */ + dst_hold(&rt->dst); + read_unlock_bh(&table->tb6_lock); + pcpu_rt = rt6_make_pcpu_route(rt); + dst_release(&rt->dst); + }
return pcpu_rt; + } }
@@@ -1585,7 -1562,7 +1592,7 @@@ struct dst_entry *icmp6_dst_alloc(struc if (unlikely(!idev)) return ERR_PTR(-ENODEV);
- rt = ip6_dst_alloc(net, dev, 0, NULL); + rt = ip6_dst_alloc(net, dev, 0); if (unlikely(!rt)) { in6_dev_put(idev); dst = ERR_PTR(-ENOMEM); @@@ -1772,8 -1749,7 +1779,8 @@@ int ip6_route_add(struct fib6_config *c if (!table) goto out;
- rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table); + rt = ip6_dst_alloc(net, NULL, + (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
if (!rt) { err = -ENOMEM; @@@ -1801,6 -1777,24 +1808,24 @@@
rt->dst.output = ip6_output;
+ if (cfg->fc_encap) { + struct lwtunnel_state *lwtstate; + + err = lwtunnel_build_state(dev, cfg->fc_encap_type, + cfg->fc_encap, &lwtstate); + if (err) + goto out; + rt->rt6i_lwtstate = lwtstate_get(lwtstate); + if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) { + rt->rt6i_lwtstate->orig_output = rt->dst.output; + rt->dst.output = lwtunnel_output6; + } + if (lwtunnel_input_redirect(rt->rt6i_lwtstate)) { + rt->rt6i_lwtstate->orig_input = rt->dst.input; + rt->dst.input = lwtunnel_input6; + } + } + ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); rt->rt6i_dst.plen = cfg->fc_dst_len; if (rt->rt6i_dst.plen == 128) @@@ -2180,6 -2174,7 +2205,7 @@@ static void ip6_rt_copy_init(struct rt6 #endif rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_table = ort->rt6i_table; + rt->rt6i_lwtstate = lwtstate_get(ort->rt6i_lwtstate); }
#ifdef CONFIG_IPV6_ROUTE_INFO @@@ -2430,7 -2425,7 +2456,7 @@@ struct rt6_info *addrconf_dst_alloc(str { struct net *net = dev_net(idev->dev); struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, - DST_NOCOUNT, NULL); + DST_NOCOUNT); if (!rt) return ERR_PTR(-ENOMEM);
@@@ -2628,6 -2623,8 +2654,8 @@@ static const struct nla_policy rtm_ipv6 [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, [RTA_PREF] = { .type = NLA_U8 }, + [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, + [RTA_ENCAP] = { .type = NLA_NESTED }, };
static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@@ -2722,6 -2719,12 +2750,12 @@@ cfg->fc_flags |= RTF_PREF(pref); }
+ if (tb[RTA_ENCAP]) + cfg->fc_encap = tb[RTA_ENCAP]; + + if (tb[RTA_ENCAP_TYPE]) + cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); + err = 0; errout: return err; @@@ -2754,6 -2757,10 +2788,10 @@@ beginning r_cfg.fc_gateway = nla_get_in6_addr(nla); r_cfg.fc_flags |= RTF_GATEWAY; } + r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP); + nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE); + if (nla) + r_cfg.fc_encap_type = nla_get_u16(nla); } err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); if (err) { @@@ -2816,7 -2823,7 +2854,7 @@@ static int inet6_rtm_newroute(struct sk return ip6_route_add(&cfg); }
- static inline size_t rt6_nlmsg_size(void) + static inline size_t rt6_nlmsg_size(struct rt6_info *rt) { return NLMSG_ALIGN(sizeof(struct rtmsg)) + nla_total_size(16) /* RTA_SRC */ @@@ -2830,7 -2837,8 +2868,8 @@@ + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ + nla_total_size(sizeof(struct rta_cacheinfo)) + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ - + nla_total_size(1); /* RTA_PREF */ + + nla_total_size(1) /* RTA_PREF */ + + lwtunnel_get_encap_size(rt->rt6i_lwtstate); }
static int rt6_fill_node(struct net *net, @@@ -2891,6 -2899,11 +2930,11 @@@ else rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; + if (!netif_carrier_ok(rt->dst.dev)) { + rtm->rtm_flags |= RTNH_F_LINKDOWN; + if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) + rtm->rtm_flags |= RTNH_F_DEAD; + } rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_protocol = rt->rt6i_protocol; if (rt->rt6i_flags & RTF_DYNAMIC) @@@ -2978,6 -2991,8 +3022,8 @@@ if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) goto nla_put_failure;
+ lwtunnel_fill_encap(skb, rt->rt6i_lwtstate); + nlmsg_end(skb, nlh); return 0;
@@@ -3104,7 -3119,7 +3150,7 @@@ void inet6_rt_notify(int event, struct err = -ENOBUFS; seq = info->nlh ? info->nlh->nlmsg_seq : 0;
- skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); + skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); if (!skb) goto errout;