diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index 0f4a062c9d6fe3..72e70f9d4b4a27 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -50,7 +50,7 @@ properties: The 2nd cell contains the interrupt number for the interrupt type. SPI interrupts are in the range [0-987]. PPI interrupts are in the range [0-15]. Extended SPI interrupts are in the range [0-1023]. - Extended PPI interrupts are in the range [0-127]. + Extended PPI interrupts are in the range [0-63]. The 3rd cell is the flags, encoded as follows: bits[3:0] trigger type and level flags. diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml index 4d5f5cc6d031e2..155719453b7048 100644 --- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml @@ -129,8 +129,6 @@ allOf: else: properties: spi-cpha: false - required: - - spi-cpol unevaluatedProperties: false diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst index 4914fbf07966c5..a49115db18c763 100644 --- a/Documentation/mm/hugetlbfs_reserv.rst +++ b/Documentation/mm/hugetlbfs_reserv.rst @@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are, the global reservation count resv_huge_pages is adjusted something like the following:: - if (resv_needed <= (resv_huge_pages - free_huge_pages)) + if (resv_needed <= (free_huge_pages - resv_huge_pages) resv_huge_pages += resv_needed; Note that the global lock hugetlb_lock is held when checking and adjusting diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index e774b48de9f511..94ef39457a6220 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -193,6 +193,15 @@ ad_actor_sys_prio This parameter has effect only in 802.3ad mode and is available through SysFs interface. +actor_port_prio + + In an AD system, this specifies the port priority. The allowed range + is 1 - 65535. If the value is not specified, it takes 255 as the + default value. + + This parameter has effect only in 802.3ad mode and is available through + netlink interface. + ad_actor_system In an AD system, this specifies the mac-address for the actor in @@ -562,6 +571,12 @@ lacp_rate The default is slow. +broadcast_neighbor + + Option specifying whether to broadcast ARP/ND packets to all + active slaves. This option has no effect in modes other than + 802.3ad mode. The default is off (0). + max_bonds Specifies the number of bonding devices to create for this diff --git a/MAINTAINERS b/MAINTAINERS index e700dca4974b3a..8b1ee5b11eca26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3060,6 +3060,14 @@ S: Maintained F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml F: drivers/net/ethernet/asix/ax88796c_* +ASIX PHY DRIVER [RUST] +M: FUJITA Tomonori +R: Trevor Gross +L: netdev@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: drivers/net/phy/ax88796b_rust.rs + ASPEED CRYPTO DRIVER M: Neal Liu L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) diff --git a/Makefile b/Makefile index 870dd6c30c672c..b9916e8715fe7d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 6 -SUBLEVEL = 140 +SUBLEVEL = 141 EXTRAVERSION = NAME = Pinguïn Aangedreven diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi index 9c5a52ce9351aa..748f9b3668975e 100644 --- a/arch/arm/boot/dts/mediatek/mt7623.dtsi +++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi @@ -328,7 +328,7 @@ efuse: efuse@10206000 { compatible = "mediatek,mt7623-efuse", - "mediatek,mt8173-efuse"; + "mediatek,efuse"; reg = <0 0x10206000 0 0x1000>; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi index c7e92358487826..9f0e65526d5f97 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi @@ -106,7 +106,7 @@ compatible = "ns8250"; clocks = <&clk14745600>; fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; - interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; reg = <3 0x200000 0x1000>; reg-shift = <1>; reg-io-width = <1>; @@ -119,7 +119,7 @@ compatible = "ns8250"; clocks = <&clk14745600>; fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; - interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; reg = <3 0x400000 0x1000>; reg-shift = <1>; reg-io-width = <1>; @@ -132,7 +132,7 @@ compatible = "ns8250"; clocks = <&clk14745600>; fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; - interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; reg = <3 0x800000 0x1000>; reg-shift = <1>; reg-io-width = <1>; @@ -145,7 +145,7 @@ compatible = "ns8250"; clocks = <&clk14745600>; fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; - interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; reg = <3 0x1000000 0x1000>; reg-shift = <1>; reg-io-width = <1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts index d78793601306cf..c71f8029833048 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts @@ -76,7 +76,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_touch>; reg = <0>; - interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; spi-cpol; spi-max-frequency = <1500000>; ti,keep-vref-on; diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c index c58d200e4816b8..5203b047deac81 100644 --- a/arch/arm/mach-omap1/clock_data.c +++ b/arch/arm/mach-omap1/clock_data.c @@ -700,8 +700,8 @@ int __init omap1_clk_init(void) /* Make sure UART clocks are enabled early */ if (cpu_is_omap16xx()) omap_writel(omap_readl(MOD_CONF_CTRL_0) | - CONF_MOD_UART1_CLK_MODE_R | - CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); + (1 << CONF_MOD_UART1_CLK_MODE_R) | + (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); #endif /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 6a1c9fca5260b2..2292245cfe7a97 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -1594,6 +1594,9 @@ exit: { u64 val = (u32)imm | (u64)insn[1].imm << 32; + if (insn->src_reg == BPF_PSEUDO_FUNC) + goto notyet; + emit_a32_mov_i64(dst, val, ctx); return 1; @@ -1785,6 +1788,9 @@ go_jmp: const s8 *r5 = bpf2a32[BPF_REG_5]; const u32 func = (u32)__bpf_call_base + (u32)imm; + if (insn->src_reg == BPF_PSEUDO_CALL) + goto notyet; + emit_a32_mov_r64(true, r0, r1, ctx); emit_a32_mov_r64(true, r1, r2, ctx); emit_push_r64(r5, ctx); diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts index c1470416faade1..36e97ed585ae73 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts @@ -84,7 +84,8 @@ reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; interrupt-parent = <&gpio_intc>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; eee-broken-1000t; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi index c6d51f11629859..4802834e26a86a 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi @@ -21,6 +21,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <1>; gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; }; @@ -29,6 +30,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <1>; gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; }; @@ -37,6 +39,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <2>; gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; }; @@ -45,6 +48,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <2>; gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi index 40067ab8aa74bb..b28dd1cece8ab0 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi @@ -21,6 +21,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <1>; gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; }; @@ -29,6 +30,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <1>; gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; }; @@ -37,6 +39,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <2>; gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; }; @@ -45,6 +48,7 @@ color = ; default-state = "off"; function = LED_FUNCTION_STATUS; + function-enumerator = <2>; gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi index 67d22d3768aa8a..507d1824d99d99 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi @@ -60,7 +60,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pmic>; interrupt-parent = <&gpio1>; - interrupts = <3 IRQ_TYPE_EDGE_RISING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; regulators { buck1: BUCK1 { @@ -194,7 +194,7 @@ pinctrl_pmic: emtop-pmic-grp { fsl,pins = < - MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 + MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi index b4466a26d838a4..6d79447b8fa08c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi @@ -282,7 +282,7 @@ }; pinctrl_pmic: pmicgrp { - fsl,pins = ; + fsl,pins = ; }; pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi index 78aaa04ebbc086..ca02f7ff376459 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi @@ -284,7 +284,7 @@ }; pinctrl_pmic: pmicgrp { - fsl,pins = ; + fsl,pins = ; }; pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts index 678ecc9f81dbb7..816469fcd5d76b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts @@ -780,7 +780,7 @@ pinctrl_pmic: pmic-grp { fsl,pins = < /* PMIC_nINT */ - MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts index 267ceffc02d840..5525240ff351e0 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts @@ -395,7 +395,7 @@ pinctrl_pmic: pmicirqgrp { fsl,pins = < - MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts index 0b0c95432bdc4c..3ee28e9f998774 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts @@ -409,7 +409,7 @@ pinctrl_pmic: pmicgrp { fsl,pins = < - MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi index bc312aa1bfc8b4..ad3e22008b6974 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi @@ -219,7 +219,7 @@ pinctrl_pmic: pmicgrp { fsl,pins = < - MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi index 2ff47f6ec7979a..e1b2b1d4ff39fc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi @@ -902,7 +902,7 @@ pinctrl_pmic: dhcom-pmic-grp { fsl,pins = < /* PMIC_nINT */ - MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index 92f8cc05fe9da1..e29b6e9a702763 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -764,7 +764,7 @@ pinctrl_pcie0_reg: pcie0reggrp { fsl,pins = < - MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 + MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi index a6319824ea2eb1..69558ffefa9a67 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi @@ -132,7 +132,7 @@ pinctrl_pmic: pmicgrp { fsl,pins = < - MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 + MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index 7924b0969ad8ff..3814568e4ee505 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -161,9 +161,17 @@ usb_con1: connector { compatible = "usb-c-connector"; label = "USB-C"; - power-role = "source"; + power-role = "dual"; data-role = "dual"; + try-power-role = "sink"; source-pdos = ; + /* + * Set operational current to 0mA as we don't want EN_SNK + * enable 12V VBUS switch when it work as a sink. + */ + sink-pdos = ; + op-sink-microwatt = <0>; + self-powered; ports { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi index 597bce2fed7293..228c15b962ea0f 100644 --- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi @@ -353,7 +353,7 @@ ; gpio-controller; #gpio-cells = <2>; - gpio-ranges = <&pio 0 0 196>; + gpio-ranges = <&pio 0 0 197>; interrupt-controller; #interrupt-cells = <2>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 559990dcd1d179..05bd2938242fcf 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -187,7 +187,7 @@ "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; gpio-controller; #gpio-cells = <2>; - gpio-ranges = <&pio 0 0 100>; + gpio-ranges = <&pio 0 0 101>; interrupt-controller; interrupts = ; interrupt-parent = <&gic>; diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts index a5957e79b818c8..eaea9d843f2ff1 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts @@ -157,7 +157,7 @@ &pmi8950_wled { qcom,current-limit-microamp = <20000>; - qcom,num-strings = <2>; + qcom,num-strings = <3>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts index b0588f30f8f1a7..4318d11df322bc 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts @@ -169,7 +169,7 @@ &pmi8950_wled { qcom,current-limit-microamp = <20000>; - qcom,ovp-millivolt = <29600>; + qcom,ovp-millivolt = <29500>; qcom,num-strings = <2>; qcom,external-pfet; qcom,cabc; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi index 9d6faeb6562441..f0a185b559ec03 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi @@ -147,6 +147,7 @@ regulator-min-microvolt = <880000>; regulator-max-microvolt = <880000>; regulator-initial-mode = ; + regulator-boot-on; }; vreg_l5a_0p8: ldo5 { diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts index c010e86134ff93..606f7a6f417912 100644 --- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts @@ -533,12 +533,14 @@ * the Bluetooth module drives the pin in either * direction or leaves the pin fully unpowered. */ + /delete-property/ bias-disable; bias-bus-hold; }; &qup_uart1_rts { /* We'll drive RTS, so no pull */ drive-strength = <2>; + /delete-property/ bias-pull-down; bias-disable; }; @@ -549,12 +551,14 @@ * in tri-state (module powered off or not driving the * signal yet). */ + /delete-property/ bias-disable; bias-pull-up; }; &qup_uart1_tx { /* We'll drive TX, so no pull */ drive-strength = <2>; + /delete-property/ bias-pull-up; bias-disable; }; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index c9a7d1b75c658d..d8086dae6e4f8b 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -659,6 +659,11 @@ opp-hz = /bits/ 64 <2841600000>; opp-peak-kBps = <8368000 51609600>; }; + + cpu7_opp21: opp-3091200000 { + opp-hz = /bits/ 64 <3091200000>; + opp-peak-kBps = <8368000 51609600>; + }; }; firmware { diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index c1ed39cac8c5b7..c1c62c6d34bd1d 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -3947,7 +3947,7 @@ gic_its: msi-controller@17140000 { compatible = "arm,gic-v3-its"; - reg = <0x0 0x17140000 0x0 0x20000>; + reg = <0x0 0x17140000 0x0 0x40000>; msi-controller; #msi-cells = <1>; }; @@ -4279,9 +4279,6 @@ bus-width = <4>; dma-coherent; - /* Forbid SDR104/SDR50 - broken hw! */ - sdhci-caps-mask = <0x3 0x0>; - status = "disabled"; sdhc2_opp_table: opp-table { diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 2f0f1c2ab7391f..5a79adbe8da124 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -2521,7 +2521,7 @@ clocks = <&gcc GCC_SDCC2_AHB_CLK>, <&gcc GCC_SDCC2_APPS_CLK>, - <&rpmhcc RPMH_CXO_CLK>; + <&bi_tcxo_div2>; clock-names = "iface", "core", "xo"; iommus = <&apps_smmu 0x540 0>; qcom,dll-config = <0x0007642c>; @@ -2535,9 +2535,6 @@ bus-width = <4>; dma-coherent; - /* Forbid SDR104/SDR50 - broken hw! */ - sdhci-caps-mask = <0x3 0>; - status = "disabled"; sdhc2_opp_table: opp-table { @@ -3830,7 +3827,7 @@ gic_its: msi-controller@17140000 { compatible = "arm,gic-v3-its"; - reg = <0 0x17140000 0 0x20000>; + reg = <0 0x17140000 0 0x40000>; msi-controller; #msi-cells = <1>; }; diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h index befcd8a7abc98d..7c03207157196e 100644 --- a/arch/arm64/include/asm/xor.h +++ b/arch/arm64/include/asm/xor.h @@ -13,7 +13,7 @@ #ifdef CONFIG_KERNEL_MODE_NEON -extern struct xor_block_template const xor_block_inner_neon; +extern struct xor_block_template xor_block_inner_neon __ro_after_init; static void xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 4561c4a670afbd..5db25bfb854ff1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -453,7 +453,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { * We can instantiate multiple PMU instances with different levels * of support. */ - S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6), ARM64_FTR_END, }; @@ -597,7 +597,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = { static const struct arm64_ftr_bits ftr_id_dfr0[] = { /* [31:28] TraceFilt */ - S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0), diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 078910db77a41b..9307a1421d67e4 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -143,9 +143,6 @@ int machine_kexec_post_load(struct kimage *kimage) } /* Create a copy of the linear map */ - trans_pgd = kexec_page_alloc(kimage); - if (!trans_pgd) - return -ENOMEM; rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); if (rc) return rc; diff --git a/arch/arm64/kernel/patch-scs.c b/arch/arm64/kernel/patch-scs.c index 6d656179ea03b9..d6e8ad142f75c0 100644 --- a/arch/arm64/kernel/patch-scs.c +++ b/arch/arm64/kernel/patch-scs.c @@ -175,9 +175,9 @@ static int noinstr scs_handle_fde_frame(const struct eh_frame *frame, loc += *opcode++ * code_alignment_factor; loc += (*opcode++ << 8) * code_alignment_factor; loc += (*opcode++ << 16) * code_alignment_factor; - loc += (*opcode++ << 24) * code_alignment_factor; + loc += ((u64)*opcode++ << 24) * code_alignment_factor; size -= 4; - break; + break; case DW_CFA_def_cfa: case DW_CFA_offset_extended: diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index f11de7484ced86..9fd0b658e4602b 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -33,8 +33,8 @@ #define FP_BOTTOM (MAX_BPF_JIT_REG + 4) #define check_imm(bits, imm) do { \ - if ((((imm) > 0) && ((imm) >> (bits))) || \ - (((imm) < 0) && (~(imm) >> (bits)))) { \ + if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ + (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ pr_info("[%2d] imm=%d(0x%x) out of range\n", \ i, imm, imm); \ return -EINVAL; \ diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 7b71737ae24cc2..12cbfc9fce4519 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -773,7 +773,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) unsigned int i; phdr = (Elf64_Phdr *)(ehdr + 1); - for (i = 0; i < ehdr->e_phnum; i++) { + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { if (phdr->p_paddr == BACKUP_SRC_START) { phdr->p_offset = image->arch.backup_start; pr_debug("Backup region offset updated to 0x%lx\n", diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index bf0188dcb9184d..1fd975d99358a8 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -292,6 +292,8 @@ static int pika_dtm_thread(void __iomem *fpga) schedule_timeout(HZ); } + put_device(&client->dev); + return 0; } diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index fe4841104ed924..3b14140ac865c3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -3329,8 +3329,7 @@ static void aen_host_forward(unsigned long si) struct zpci_gaite *gaite; struct kvm *kvm; - gaite = (struct zpci_gaite *)aift->gait + - (si * sizeof(struct zpci_gaite)); + gaite = aift->gait + si; if (gaite->count == 0) return; if (gaite->aisb != 0) diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index ffa7739c7a284d..e5d3c0793f61b1 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -292,8 +292,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib, phys_to_virt(fib->fmt0.aibv)); spin_lock_irq(&aift->gait_lock); - gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * - sizeof(struct zpci_gaite)); + gaite = aift->gait + zdev->aisb; /* If assist not requested, host will get all alerts */ if (assist) @@ -359,8 +358,7 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force) if (zdev->kzdev->fib.fmt0.aibv == 0) goto out; spin_lock_irq(&aift->gait_lock); - gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * - sizeof(struct zpci_gaite)); + gaite = aift->gait + zdev->aisb; isc = gaite->gisc; gaite->count--; if (gaite->count == 0) { diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 5a64d34a37482b..491789420d7c0c 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -759,25 +759,34 @@ static int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp, } /* - * Sign-extend the register if necessary + * Sign- or zero-extend the register if necessary */ -static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) +static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) { - if (!(flags & BTF_FMODEL_SIGNED_ARG)) - return 0; - switch (size) { case 1: - /* lgbr %r,%r */ - EMIT4(0xb9060000, r, r); + if (flags & BTF_FMODEL_SIGNED_ARG) + /* lgbr %r,%r */ + EMIT4(0xb9060000, r, r); + else + /* llgcr %r,%r */ + EMIT4(0xb9840000, r, r); return 0; case 2: - /* lghr %r,%r */ - EMIT4(0xb9070000, r, r); + if (flags & BTF_FMODEL_SIGNED_ARG) + /* lghr %r,%r */ + EMIT4(0xb9070000, r, r); + else + /* llghr %r,%r */ + EMIT4(0xb9850000, r, r); return 0; case 4: - /* lgfr %r,%r */ - EMIT4(0xb9140000, r, r); + if (flags & BTF_FMODEL_SIGNED_ARG) + /* lgfr %r,%r */ + EMIT4(0xb9140000, r, r); + else + /* llgfr %r,%r */ + EMIT4(0xb9160000, r, r); return 0; case 8: return 0; @@ -1452,9 +1461,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, return -1; for (j = 0; j < m->nr_args; j++) { - if (sign_extend(jit, BPF_REG_1 + j, - m->arg_size[j], - m->arg_flags[j])) + if (sign_zero_extend(jit, BPF_REG_1 + j, + m->arg_size[j], + m->arg_flags[j])) return -1; } } @@ -2186,7 +2195,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, call_r1(jit); /* stg %r2,retval_off(%r15) */ if (save_ret) { - if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) + if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags)) return -1; EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, tjit->retval_off); diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index c6b4b1728006d5..192dbb6e89bbc5 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -140,7 +140,7 @@ TRACE_EVENT(kvm_xen_hypercall, __entry->a2 = a2; __entry->a3 = a3; __entry->a4 = a4; - __entry->a4 = a5; + __entry->a5 = a5; ), TP_printk("cpl %d nr 0x%lx a0 0x%lx a1 0x%lx a2 0x%lx a3 0x%lx a4 0x%lx a5 %lx", diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 75e9d5a9d707c4..4ac2f53e7f51f5 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -618,6 +619,8 @@ restart: q->root_blkg = NULL; spin_unlock_irq(&q->queue_lock); + + wake_up_var(&q->root_blkg); } static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) @@ -1459,6 +1462,18 @@ int blkcg_init_disk(struct gendisk *disk) bool preloaded; int ret; + /* + * If the queue is shared across disk rebind (e.g., SCSI), the + * previous disk's blkcg state is cleaned up asynchronously via + * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to + * finish (indicated by root_blkg becoming NULL) before setting up + * new blkcg state. Otherwise, we may overwrite q->root_blkg while + * the old one is still alive, and radix_tree_insert() in + * blkg_create() will fail with -EEXIST because the old entries + * still occupy the same queue id slot in blkcg->blkg_tree. + */ + wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); if (!new_blkg) return -ENOMEM; @@ -1978,6 +1993,7 @@ void blkcg_maybe_throttle_current(void) return; out: rcu_read_unlock(); + put_disk(disk); } /** diff --git a/block/disk-events.c b/block/disk-events.c index 13c3372c465a39..6987e4dd8d4171 100644 --- a/block/disk-events.c +++ b/block/disk-events.c @@ -294,13 +294,14 @@ EXPORT_SYMBOL(disk_check_media_change); * Should be called when the media changes for @disk. Generates a uevent * and attempts to free all dentries and inodes and invalidates all block * device page cache entries in that case. + * + * Callers that need a partition re-scan should arrange for one explicitly. */ void disk_force_media_change(struct gendisk *disk) { disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE); inc_diskseq(disk); bdev_mark_dead(disk->part0, true); - set_bit(GD_NEED_PART_SCAN, &disk->state); } EXPORT_SYMBOL_GPL(disk_force_media_change); diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ce58738ce00d88..8785a2dba9ab29 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -585,6 +585,8 @@ static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) return -EINVAL; con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg); + if (con->aead_assoclen >= 0x80000000u) + return -EINVAL; break; default: diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c index dd05faf00571f3..8ae5245081f6ad 100644 --- a/crypto/jitterentropy-kcapi.c +++ b/crypto/jitterentropy-kcapi.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -182,7 +183,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len) ***************************************************************************/ struct jitterentropy { - spinlock_t jent_lock; + struct mutex jent_lock; struct rand_data *entropy_collector; struct crypto_shash *tfm; struct shash_desc *sdesc; @@ -192,7 +193,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) { struct jitterentropy *rng = crypto_tfm_ctx(tfm); - spin_lock(&rng->jent_lock); + mutex_lock(&rng->jent_lock); if (rng->sdesc) { shash_desc_zero(rng->sdesc); @@ -207,7 +208,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) if (rng->entropy_collector) jent_entropy_collector_free(rng->entropy_collector); rng->entropy_collector = NULL; - spin_unlock(&rng->jent_lock); + mutex_unlock(&rng->jent_lock); } static int jent_kcapi_init(struct crypto_tfm *tfm) @@ -217,7 +218,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) struct shash_desc *sdesc; int size, ret = 0; - spin_lock_init(&rng->jent_lock); + mutex_init(&rng->jent_lock); /* * Use SHA3-256 as conditioner. We allocate only the generic @@ -252,7 +253,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) goto err; } - spin_lock_init(&rng->jent_lock); return 0; err: @@ -267,7 +267,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, struct jitterentropy *rng = crypto_rng_ctx(tfm); int ret = 0; - spin_lock(&rng->jent_lock); + mutex_lock(&rng->jent_lock); ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); @@ -293,7 +293,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, ret = -EINVAL; } - spin_unlock(&rng->jent_lock); + mutex_unlock(&rng->jent_lock); return ret; } diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c index 9b55d1593d160c..594753203fdf03 100644 --- a/drivers/acpi/acpi_cmos_rtc.c +++ b/drivers/acpi/acpi_cmos_rtc.c @@ -24,72 +24,91 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { {} }; -static acpi_status -acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, - u32 bits, u64 *value64, - void *handler_context, void *region_context) +static bool cmos_rtc_space_handler_present __read_mostly; + +static acpi_status acpi_cmos_rtc_space_handler(u32 function, + acpi_physical_address address, + u32 bits, u64 *value64, + void *handler_context, + void *region_context) { - int i; + unsigned int i, bytes = DIV_ROUND_UP(bits, 8); u8 *value = (u8 *)value64; if (address > 0xff || !value64) return AE_BAD_PARAMETER; - if (function != ACPI_WRITE && function != ACPI_READ) - return AE_BAD_PARAMETER; + guard(spinlock_irq)(&rtc_lock); + + if (function == ACPI_WRITE) { + for (i = 0; i < bytes; i++, address++, value++) + CMOS_WRITE(*value, address); - spin_lock_irq(&rtc_lock); + return AE_OK; + } - for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) - if (function == ACPI_READ) + if (function == ACPI_READ) { + for (i = 0; i < bytes; i++, address++, value++) *value = CMOS_READ(address); - else - CMOS_WRITE(*value, address); - spin_unlock_irq(&rtc_lock); + return AE_OK; + } - return AE_OK; + return AE_BAD_PARAMETER; } int acpi_install_cmos_rtc_space_handler(acpi_handle handle) { acpi_status status; + if (cmos_rtc_space_handler_present) + return 0; + status = acpi_install_address_space_handler(handle, - ACPI_ADR_SPACE_CMOS, - &acpi_cmos_rtc_space_handler, - NULL, NULL); + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, + NULL, NULL); if (ACPI_FAILURE(status)) { - pr_err("Error installing CMOS-RTC region handler\n"); + pr_err("Failed to install CMOS-RTC address space handler\n"); return -ENODEV; } + cmos_rtc_space_handler_present = true; + return 1; } EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) { - if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, - ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) - pr_err("Error removing CMOS-RTC region handler\n"); + acpi_status status; + + if (cmos_rtc_space_handler_present) + return; + + status = acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler); + if (ACPI_FAILURE(status)) + pr_err("Failed to remove CMOS-RTC address space handler\n"); } EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); -static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) +static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) { - return acpi_install_cmos_rtc_space_handler(adev->handle); -} + int ret; -static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) -{ - acpi_remove_cmos_rtc_space_handler(adev->handle); + ret = acpi_install_cmos_rtc_space_handler(adev->handle); + if (ret < 0) + return ret; + + return 1; } static struct acpi_scan_handler cmos_rtc_handler = { .ids = acpi_cmos_rtc_ids, - .attach = acpi_cmos_rtc_attach_handler, - .detach = acpi_cmos_rtc_detach_handler, + .attach = acpi_cmos_rtc_attach, }; void __init acpi_cmos_rtc_init(void) diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c index 8b3c7d42b41bc5..419a9f6c0a8270 100644 --- a/drivers/acpi/arm64/agdi.c +++ b/drivers/acpi/arm64/agdi.c @@ -32,7 +32,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); if (err) { - dev_err(&pdev->dev, "Failed to register for SDEI event %d", + dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", adata->sdei_event); return err; } diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 8a0f000221271f..8069b7ca26fbcc 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -913,6 +913,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) if (!new_dr) return NULL; + set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); + /* * The spinlock protects the linked list against concurrent * modifications but not the resource itself. diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index d1dae47f3534b8..5bee0a89750037 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2676,6 +2676,7 @@ static struct bus_type genpd_bus_type = { static void genpd_dev_pm_detach(struct device *dev, bool power_off) { struct generic_pm_domain *pd; + bool is_virt_dev; unsigned int i; int ret = 0; @@ -2685,6 +2686,13 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) dev_dbg(dev, "removing from PM domain %s\n", pd->name); + /* Check if the device was created by genpd at attach. */ + is_virt_dev = dev->bus == &genpd_bus_type; + + /* Disable runtime PM if we enabled it at attach. */ + if (is_virt_dev) + pm_runtime_disable(dev); + /* Drop the default performance state */ if (dev_gpd_data(dev)->default_pstate) { dev_pm_genpd_set_performance_state(dev, 0); @@ -2710,7 +2718,7 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) genpd_queue_power_off_work(pd); /* Unregister the device if it was created by genpd. */ - if (dev->bus == &genpd_bus_type) + if (is_virt_dev) device_unregister(dev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index d3538bd83fb3ba..1ba81a5e77215e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -3368,8 +3368,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) if (resource_filter) { retcode = ERR_RES_NOT_KNOWN; resource = drbd_find_resource(nla_data(resource_filter)); - if (!resource) + if (!resource) { + rcu_read_lock(); goto put_result; + } cb->args[0] = (long)resource; } } @@ -3618,8 +3620,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) if (resource_filter) { retcode = ERR_RES_NOT_KNOWN; resource = drbd_find_resource(nla_data(resource_filter)); - if (!resource) + if (!resource) { + rcu_read_lock(); goto put_result; + } } cb->args[0] = (long)resource; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e38f3c4458c90a..85baba91aaa974 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -689,6 +689,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); + percpu_down_write(&hu->proto_lock); + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); + percpu_up_write(&hu->proto_lock); hu->proto->close(hu); hu->hdev = NULL; hci_free_dev(hdev); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 54b80911f3e286..2283fd91ff5f87 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -634,6 +634,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) WARN_ON(!cdo->generic_packet); + /* + * Propagate the drive's write support to the block layer so BLKROGET + * reflects actual write capability. Drivers that use GET CONFIGURATION + * features (CDC_MRW_W, CDC_RAM) must have called + * cdrom_probe_write_features() before register_cdrom() so the mask is + * complete here. + */ + set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | + CDC_CD_RW)); + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); mutex_lock(&cdrom_mutex); list_add(&cdi->list, &cdrom_list); @@ -748,6 +758,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) return 0; } +/* + * Probe write-related MMC features via GET CONFIGURATION and update + * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE + * capabilities page (e.g. sr) should call this after those MODE SENSE bits + * have been set but before register_cdrom(), so that the full set of + * write-capability bits is known by the time register_cdrom() decides on the + * initial read-only state of the disk. + */ +void cdrom_probe_write_features(struct cdrom_device_info *cdi) +{ + int mrw, mrw_write, ram_write; + + mrw = 0; + if (!cdrom_is_mrw(cdi, &mrw_write)) + mrw = 1; + + if (CDROM_CAN(CDC_MO_DRIVE)) + ram_write = 1; + else + (void) cdrom_is_random_writable(cdi, &ram_write); + + if (mrw) + cdi->mask &= ~CDC_MRW; + else + cdi->mask |= CDC_MRW; + + if (mrw_write) + cdi->mask &= ~CDC_MRW_W; + else + cdi->mask |= CDC_MRW_W; + + if (ram_write) + cdi->mask &= ~CDC_RAM; + else + cdi->mask |= CDC_RAM; +} +EXPORT_SYMBOL(cdrom_probe_write_features); + static int cdrom_media_erasable(struct cdrom_device_info *cdi) { disc_information di; @@ -900,33 +948,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) */ static int cdrom_open_write(struct cdrom_device_info *cdi) { - int mrw, mrw_write, ram_write; int ret = 1; - mrw = 0; - if (!cdrom_is_mrw(cdi, &mrw_write)) - mrw = 1; - - if (CDROM_CAN(CDC_MO_DRIVE)) - ram_write = 1; - else - (void) cdrom_is_random_writable(cdi, &ram_write); - - if (mrw) - cdi->mask &= ~CDC_MRW; - else - cdi->mask |= CDC_MRW; - - if (mrw_write) - cdi->mask &= ~CDC_MRW_W; - else - cdi->mask |= CDC_MRW_W; - - if (ram_write) - cdi->mask &= ~CDC_RAM; - else - cdi->mask |= CDC_RAM; - if (CDROM_CAN(CDC_MRW_W)) ret = cdrom_mrw_open_write(cdi); else if (CDROM_CAN(CDC_DVD_RAM)) diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c index e8460e966b83e8..5d5444b567a047 100644 --- a/drivers/char/ipmi/ssif_bmc.c +++ b/drivers/char/ipmi/ssif_bmc.c @@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, spin_unlock_irqrestore(&ssif_bmc->lock, flags); ret = copy_to_user(buf, &msg, count); + if (ret > 0) + ret = -EFAULT; } return (ret < 0) ? ret : count; @@ -455,6 +457,15 @@ static bool supported_write_cmd(u8 cmd) return false; } +static bool supported_write_start_cmd(u8 cmd) +{ + if (cmd == SSIF_IPMI_SINGLEPART_WRITE || + cmd == SSIF_IPMI_MULTIPART_WRITE_START) + return true; + + return false; +} + /* Process the IPMI response that will be read by master */ static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) { @@ -557,7 +568,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) len = ssif_bmc->request.len + part->length; /* Do the bound check here, not allow the request len exceed 254 bytes */ if (len > IPMI_SSIF_PAYLOAD_MAX) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: Request exceeded 254 bytes, aborting"); /* Request too long, aborting */ ssif_bmc->aborting = true; @@ -603,7 +614,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) ssif_bmc->state == SSIF_START || ssif_bmc->state == SSIF_REQ_RECVING || ssif_bmc->state == SSIF_RES_SENDING) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: %s unexpected READ REQUESTED in state=%s\n", __func__, state_to_string(ssif_bmc->state)); ssif_bmc->state = SSIF_ABORTING; @@ -612,7 +623,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { - dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", + dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", ssif_bmc->part_buf.smbus_cmd); ssif_bmc->aborting = true; } @@ -647,7 +658,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) ssif_bmc->state == SSIF_START || ssif_bmc->state == SSIF_REQ_RECVING || ssif_bmc->state == SSIF_SMBUS_CMD) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: %s unexpected READ PROCESSED in state=%s\n", __func__, state_to_string(ssif_bmc->state)); ssif_bmc->state = SSIF_ABORTING; @@ -672,7 +683,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) } else if (ssif_bmc->state == SSIF_START || ssif_bmc->state == SSIF_REQ_RECVING || ssif_bmc->state == SSIF_RES_SENDING) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: %s unexpected WRITE REQUEST in state=%s\n", __func__, state_to_string(ssif_bmc->state)); ssif_bmc->state = SSIF_ABORTING; @@ -687,7 +698,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) { if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: %s unexpected WRITE RECEIVED in state=%s\n", __func__, state_to_string(ssif_bmc->state)); ssif_bmc->state = SSIF_ABORTING; @@ -697,7 +708,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { - dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", + dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", ssif_bmc->part_buf.smbus_cmd); ssif_bmc->aborting = true; } @@ -706,6 +717,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) ssif_bmc->state = SSIF_ABORTING; else ssif_bmc->state = SSIF_REQ_RECVING; + } else if (ssif_bmc->state == SSIF_ABORTING) { + if (supported_write_start_cmd(*val)) { + ssif_bmc->state = SSIF_SMBUS_CMD; + ssif_bmc->aborting = false; + } } /* This is response sending state */ @@ -721,7 +737,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) ssif_bmc->state == SSIF_START || ssif_bmc->state == SSIF_SMBUS_CMD || ssif_bmc->state == SSIF_ABORTING) { - dev_warn(&ssif_bmc->client->dev, + dev_dbg(&ssif_bmc->client->dev, "Warn: %s unexpected SLAVE STOP in state=%s\n", __func__, state_to_string(ssif_bmc->state)); ssif_bmc->state = SSIF_READY; @@ -788,7 +804,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 break; default: - dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); break; } diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 4dcde305944c45..318acd176a2ef3 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -906,13 +906,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, return &cg->pll[pll].div[div]; } -static struct clk * __init create_mux_common(struct clockgen *cg, - struct mux_hwclock *hwc, - const struct clk_ops *ops, - unsigned long min_rate, - unsigned long max_rate, - unsigned long pct80_rate, - const char *fmt, int idx) +static struct clk * __init __printf(7, 8) +create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, + const struct clk_ops *ops, unsigned long min_rate, + unsigned long max_rate, unsigned long pct80_rate, + const char *fmt, ...) { struct clk_init_data init = {}; struct clk *clk; @@ -920,8 +918,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, const char *parent_names[NUM_MUX_PARENTS]; char name[32]; int i, j; + va_list args; - snprintf(name, sizeof(name), fmt, idx); + va_start(args, fmt); + vsnprintf(name, sizeof(name), fmt, args); + va_end(args); for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { unsigned long rate; diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 0c3d0cee98c83d..a542b78d9c7314 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty of_clk_add_provider(np, of_clk_src_simple_get, clk); clk_register_clkdev(clk, clk_name, NULL); pr_debug("Add %s clock PLL\n", clk_name); + } else { + iounmap(reg); } } diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index bf4c1d9c992879..048e2ddba490b3 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, } if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { pr_err("ccm: parent clock %d not in ccm\n", index); + of_node_put(clkspec.np); return; } parent = clkspec.args[0]; + of_node_put(clkspec.np); rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells", index, &clkspec); @@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, return; if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { pr_err("ccm: child clock %d not in ccm\n", index); + of_node_put(clkspec.np); return; } child = clkspec.args[0]; + of_node_put(clkspec.np); if (child != IMX6QDL_CLK_LDB_DI0_SEL && child != IMX6QDL_CLK_LDB_DI1_SEL) @@ -238,8 +242,11 @@ static bool pll6_bypassed(struct device_node *node) return false; if (clkspec.np == node && - clkspec.args[0] == IMX6QDL_PLL6_BYPASS) + clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { + of_node_put(clkspec.np); break; + } + of_node_put(clkspec.np); } /* PLL6 bypass is not part of the assigned clock list */ @@ -249,6 +256,9 @@ static bool pll6_bypassed(struct device_node *node) ret = of_parse_phandle_with_args(node, "assigned-clock-parents", "#clock-cells", index, &clkspec); + if (!ret) + of_node_put(clkspec.np); + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) return true; diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index f70ed231b92d63..cedc8a02aa1f0a 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; -static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", +static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", @@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; -static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", +static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c index 9536bfc72a43cf..166a4170e76f71 100644 --- a/drivers/clk/qcom/dispcc-sc7180.c +++ b/drivers/clk/qcom/dispcc-sc7180.c @@ -16,6 +16,7 @@ #include "clk-regmap-divider.h" #include "common.h" #include "gdsc.h" +#include "reset.h" enum { P_BI_TCXO, @@ -635,6 +636,11 @@ static struct gdsc mdss_gdsc = { .flags = HW_CTRL, }; +static const struct qcom_reset_map disp_cc_sc7180_resets[] = { + [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, + [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, +}; + static struct gdsc *disp_cc_sc7180_gdscs[] = { [MDSS_GDSC] = &mdss_gdsc, }; @@ -686,6 +692,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { .config = &disp_cc_sc7180_regmap_config, .clks = disp_cc_sc7180_clocks, .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), + .resets = disp_cc_sc7180_resets, + .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), .gdscs = disp_cc_sc7180_gdscs, .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), }; diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c index 30f636b9f0ec89..7f8819ece5eb01 100644 --- a/drivers/clk/qcom/dispcc-sc8280xp.c +++ b/drivers/clk/qcom/dispcc-sc8280xp.c @@ -1161,7 +1161,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = { &disp0_cc_mdss_byte0_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_regmap_div_ops, }, }; @@ -1176,7 +1175,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = { &disp1_cc_mdss_byte0_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_regmap_div_ops, }, }; @@ -1191,7 +1189,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = { &disp0_cc_mdss_byte1_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_regmap_div_ops, }, }; @@ -1206,7 +1203,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = { &disp1_cc_mdss_byte1_clk_src.clkr.hw, }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_regmap_div_ops, }, }; diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c index 317a7e2b50bfbc..7aa84c341f5988 100644 --- a/drivers/clk/qcom/dispcc-sm8250.c +++ b/drivers/clk/qcom/dispcc-sm8250.c @@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { .name = "disp_cc_mdss_pclk0_clk_src", .parent_data = disp_cc_parent_data_6, .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, .ops = &clk_pixel_ops, }, }; @@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { .name = "disp_cc_mdss_pclk1_clk_src", .parent_data = disp_cc_parent_data_6, .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, .ops = &clk_pixel_ops, }, }; @@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { .parent_data = disp_cc_parent_data_1, .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c index 239cc726c7e296..ab796f4f0ac034 100644 --- a/drivers/clk/qcom/dispcc-sm8450.c +++ b/drivers/clk/qcom/dispcc-sm8450.c @@ -364,7 +364,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { .parent_data = disp_cc_parent_data_1, .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_dp_ops, + .ops = &clk_rcg2_ops, }, }; diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c index ec0c45881c67a7..dd21a5898c5a54 100644 --- a/drivers/clk/qcom/gcc-sc8180x.c +++ b/drivers/clk/qcom/gcc-sc8180x.c @@ -4105,7 +4105,7 @@ static struct gdsc usb30_sec_gdsc = { .pd = { .name = "usb30_sec_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4123,7 +4123,7 @@ static struct gdsc usb30_prim_gdsc = { .pd = { .name = "usb30_prim_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4132,7 +4132,7 @@ static struct gdsc pcie_0_gdsc = { .pd = { .name = "pcie_0_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4159,7 +4159,7 @@ static struct gdsc pcie_1_gdsc = { .pd = { .name = "pcie_1_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4168,7 +4168,7 @@ static struct gdsc pcie_2_gdsc = { .pd = { .name = "pcie_2_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4186,7 +4186,7 @@ static struct gdsc pcie_3_gdsc = { .pd = { .name = "pcie_3_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; @@ -4195,10 +4195,55 @@ static struct gdsc usb30_mp_gdsc = { .pd = { .name = "usb30_mp_gdsc", }, - .pwrsts = PWRSTS_OFF_ON, + .pwrsts = PWRSTS_RET_ON, .flags = POLL_CFG_GDSCR, }; +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { + .gdscr = 0x7d050, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { + .gdscr = 0x7d058, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { + .gdscr = 0x7d054, + .pd = { + .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { + .gdscr = 0x7d05c, + .pd = { + .name = "hlos1_vote_turing_mmu_tbu0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { + .gdscr = 0x7d060, + .pd = { + .name = "hlos1_vote_turing_mmu_tbu1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + static struct clk_regmap *gcc_sc8180x_clocks[] = { [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, @@ -4499,6 +4544,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { [USB30_MP_GDSC] = &usb30_mp_gdsc, [USB30_PRIM_GDSC] = &usb30_prim_gdsc, [USB30_SEC_GDSC] = &usb30_sec_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, + [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, + [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, }; static const struct regmap_config gcc_sc8180x_regmap_config = { diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c index e9cd80e085dc3b..a540936196ca3c 100644 --- a/drivers/clk/visconti/pll.c +++ b/drivers/clk/visconti/pll.c @@ -244,7 +244,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, const struct visconti_pll_rate_table *rate_table, spinlock_t *lock) { - struct clk_init_data init; + struct clk_init_data init = {}; struct visconti_pll *pll; struct clk_hw *pll_hw_clk; size_t len; diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 97fcde0126766e..3402cf3f017f14 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -46,11 +46,6 @@ #define ATMEL_AES_BUFFER_ORDER 2 #define ATMEL_AES_BUFFER_SIZE (PAGE_SIZE << ATMEL_AES_BUFFER_ORDER) -#define CFB8_BLOCK_SIZE 1 -#define CFB16_BLOCK_SIZE 2 -#define CFB32_BLOCK_SIZE 4 -#define CFB64_BLOCK_SIZE 8 - #define SIZE_IN_WORDS(x) ((x) >> 2) /* AES flags */ @@ -60,12 +55,6 @@ #define AES_FLAGS_OPMODE_MASK (AES_MR_OPMOD_MASK | AES_MR_CFBS_MASK) #define AES_FLAGS_ECB AES_MR_OPMOD_ECB #define AES_FLAGS_CBC AES_MR_OPMOD_CBC -#define AES_FLAGS_OFB AES_MR_OPMOD_OFB -#define AES_FLAGS_CFB128 (AES_MR_OPMOD_CFB | AES_MR_CFBS_128b) -#define AES_FLAGS_CFB64 (AES_MR_OPMOD_CFB | AES_MR_CFBS_64b) -#define AES_FLAGS_CFB32 (AES_MR_OPMOD_CFB | AES_MR_CFBS_32b) -#define AES_FLAGS_CFB16 (AES_MR_OPMOD_CFB | AES_MR_CFBS_16b) -#define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) #define AES_FLAGS_CTR AES_MR_OPMOD_CTR #define AES_FLAGS_GCM AES_MR_OPMOD_GCM #define AES_FLAGS_XTS AES_MR_OPMOD_XTS @@ -87,7 +76,6 @@ struct atmel_aes_caps { bool has_dualbuff; - bool has_cfb64; bool has_gcm; bool has_xts; bool has_authenc; @@ -860,22 +848,6 @@ static int atmel_aes_dma_start(struct atmel_aes_dev *dd, int err; switch (dd->ctx->block_size) { - case CFB8_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - maxburst = 1; - break; - - case CFB16_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - maxburst = 1; - break; - - case CFB32_BLOCK_SIZE: - case CFB64_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - maxburst = 1; - break; - case AES_BLOCK_SIZE: addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; maxburst = dd->caps.max_burst_size; @@ -1103,7 +1075,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) } /* - * ECB, CBC, CFB, OFB or CTR mode require the plaintext and ciphertext + * ECB, CBC or CTR mode require the plaintext and ciphertext * to have a positve integer length. */ if (!req->cryptlen && opmode != AES_FLAGS_XTS) @@ -1113,27 +1085,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) !IS_ALIGNED(req->cryptlen, crypto_skcipher_blocksize(skcipher))) return -EINVAL; - switch (mode & AES_FLAGS_OPMODE_MASK) { - case AES_FLAGS_CFB8: - ctx->block_size = CFB8_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB16: - ctx->block_size = CFB16_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB32: - ctx->block_size = CFB32_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB64: - ctx->block_size = CFB64_BLOCK_SIZE; - break; - - default: - ctx->block_size = AES_BLOCK_SIZE; - break; - } + ctx->block_size = AES_BLOCK_SIZE; ctx->is_aead = false; rctx = skcipher_request_ctx(req); @@ -1188,66 +1140,6 @@ static int atmel_aes_cbc_decrypt(struct skcipher_request *req) return atmel_aes_crypt(req, AES_FLAGS_CBC); } -static int atmel_aes_ofb_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_OFB | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_ofb_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_OFB); -} - -static int atmel_aes_cfb_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB128 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB128); -} - -static int atmel_aes_cfb64_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB64 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb64_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB64); -} - -static int atmel_aes_cfb32_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB32 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb32_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB32); -} - -static int atmel_aes_cfb16_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB16 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb16_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB16); -} - -static int atmel_aes_cfb8_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB8 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb8_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB8); -} - static int atmel_aes_ctr_encrypt(struct skcipher_request *req) { return atmel_aes_crypt(req, AES_FLAGS_CTR | AES_FLAGS_ENCRYPT); @@ -1318,76 +1210,6 @@ static struct skcipher_alg aes_algs[] = { .decrypt = atmel_aes_cbc_decrypt, .ivsize = AES_BLOCK_SIZE, }, -{ - .base.cra_name = "ofb(aes)", - .base.cra_driver_name = "atmel-ofb-aes", - .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_ofb_encrypt, - .decrypt = atmel_aes_ofb_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "atmel-cfb-aes", - .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb_encrypt, - .decrypt = atmel_aes_cfb_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb32(aes)", - .base.cra_driver_name = "atmel-cfb32-aes", - .base.cra_blocksize = CFB32_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb32_encrypt, - .decrypt = atmel_aes_cfb32_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb16(aes)", - .base.cra_driver_name = "atmel-cfb16-aes", - .base.cra_blocksize = CFB16_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb16_encrypt, - .decrypt = atmel_aes_cfb16_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb8(aes)", - .base.cra_driver_name = "atmel-cfb8-aes", - .base.cra_blocksize = CFB8_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb8_encrypt, - .decrypt = atmel_aes_cfb8_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, { .base.cra_name = "ctr(aes)", .base.cra_driver_name = "atmel-ctr-aes", @@ -1404,21 +1226,6 @@ static struct skcipher_alg aes_algs[] = { }, }; -static struct skcipher_alg aes_cfb64_alg = { - .base.cra_name = "cfb64(aes)", - .base.cra_driver_name = "atmel-cfb64-aes", - .base.cra_blocksize = CFB64_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb64_encrypt, - .decrypt = atmel_aes_cfb64_decrypt, - .ivsize = AES_BLOCK_SIZE, -}; - /* gcm aead functions */ @@ -2393,12 +2200,10 @@ static irqreturn_t atmel_aes_irq(int irq, void *dev_id) static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) { - int i; - #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) if (dd->caps.has_authenc) - for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) - crypto_unregister_aead(&aes_authenc_algs[i]); + crypto_unregister_aeads(aes_authenc_algs, + ARRAY_SIZE(aes_authenc_algs)); #endif if (dd->caps.has_xts) @@ -2407,11 +2212,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) if (dd->caps.has_gcm) crypto_unregister_aead(&aes_gcm_alg); - if (dd->caps.has_cfb64) - crypto_unregister_skcipher(&aes_cfb64_alg); - - for (i = 0; i < ARRAY_SIZE(aes_algs); i++) - crypto_unregister_skcipher(&aes_algs[i]); + crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); } static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) @@ -2424,7 +2225,7 @@ static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) static int atmel_aes_register_algs(struct atmel_aes_dev *dd) { - int err, i, j; + int err, i; for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { atmel_aes_crypto_alg_init(&aes_algs[i].base); @@ -2434,14 +2235,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) goto err_aes_algs; } - if (dd->caps.has_cfb64) { - atmel_aes_crypto_alg_init(&aes_cfb64_alg.base); - - err = crypto_register_skcipher(&aes_cfb64_alg); - if (err) - goto err_aes_cfb64_alg; - } - if (dd->caps.has_gcm) { atmel_aes_crypto_alg_init(&aes_gcm_alg.base); @@ -2475,19 +2268,17 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) /* i = ARRAY_SIZE(aes_authenc_algs); */ err_aes_authenc_alg: - for (j = 0; j < i; j++) - crypto_unregister_aead(&aes_authenc_algs[j]); - crypto_unregister_skcipher(&aes_xts_alg); + crypto_unregister_aeads(aes_authenc_algs, i); + if (dd->caps.has_xts) + crypto_unregister_skcipher(&aes_xts_alg); #endif err_aes_xts_alg: - crypto_unregister_aead(&aes_gcm_alg); + if (dd->caps.has_gcm) + crypto_unregister_aead(&aes_gcm_alg); err_aes_gcm_alg: - crypto_unregister_skcipher(&aes_cfb64_alg); -err_aes_cfb64_alg: i = ARRAY_SIZE(aes_algs); err_aes_algs: - for (j = 0; j < i; j++) - crypto_unregister_skcipher(&aes_algs[j]); + crypto_unregister_skciphers(aes_algs, i); return err; } @@ -2495,7 +2286,6 @@ err_aes_algs: static void atmel_aes_get_cap(struct atmel_aes_dev *dd) { dd->caps.has_dualbuff = 0; - dd->caps.has_cfb64 = 0; dd->caps.has_gcm = 0; dd->caps.has_xts = 0; dd->caps.has_authenc = 0; @@ -2507,7 +2297,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) case 0x600: case 0x500: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.has_gcm = 1; dd->caps.has_xts = 1; dd->caps.has_authenc = 1; @@ -2515,13 +2304,11 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) break; case 0x200: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.has_gcm = 1; dd->caps.max_burst_size = 4; break; case 0x130: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.max_burst_size = 4; break; case 0x120: diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 3622120add625a..d32fb4e770119a 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -2418,27 +2418,23 @@ EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort); static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) { - int i; - if (dd->caps.has_hmac) - for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) - crypto_unregister_ahash(&sha_hmac_algs[i]); + crypto_unregister_ahashes(sha_hmac_algs, + ARRAY_SIZE(sha_hmac_algs)); - for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) - crypto_unregister_ahash(&sha_1_256_algs[i]); + crypto_unregister_ahashes(sha_1_256_algs, ARRAY_SIZE(sha_1_256_algs)); if (dd->caps.has_sha224) crypto_unregister_ahash(&sha_224_alg); - if (dd->caps.has_sha_384_512) { - for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) - crypto_unregister_ahash(&sha_384_512_algs[i]); - } + if (dd->caps.has_sha_384_512) + crypto_unregister_ahashes(sha_384_512_algs, + ARRAY_SIZE(sha_384_512_algs)); } static int atmel_sha_register_algs(struct atmel_sha_dev *dd) { - int err, i, j; + int err, i; for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { atmel_sha_alg_init(&sha_1_256_algs[i]); @@ -2480,18 +2476,15 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) /*i = ARRAY_SIZE(sha_hmac_algs);*/ err_sha_hmac_algs: - for (j = 0; j < i; j++) - crypto_unregister_ahash(&sha_hmac_algs[j]); + crypto_unregister_ahashes(sha_hmac_algs, i); i = ARRAY_SIZE(sha_384_512_algs); err_sha_384_512_algs: - for (j = 0; j < i; j++) - crypto_unregister_ahash(&sha_384_512_algs[j]); + crypto_unregister_ahashes(sha_384_512_algs, i); crypto_unregister_ahash(&sha_224_alg); err_sha_224_algs: i = ARRAY_SIZE(sha_1_256_algs); err_sha_1_256_algs: - for (j = 0; j < i; j++) - crypto_unregister_ahash(&sha_1_256_algs[j]); + crypto_unregister_ahashes(sha_1_256_algs, i); return err; } diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 6870a13342e22c..0bf485f350c8f0 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -45,11 +45,6 @@ #define TDES_FLAGS_OPMODE_MASK (TDES_MR_OPMOD_MASK | TDES_MR_CFBS_MASK) #define TDES_FLAGS_ECB TDES_MR_OPMOD_ECB #define TDES_FLAGS_CBC TDES_MR_OPMOD_CBC -#define TDES_FLAGS_OFB TDES_MR_OPMOD_OFB -#define TDES_FLAGS_CFB64 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_64b) -#define TDES_FLAGS_CFB32 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_32b) -#define TDES_FLAGS_CFB16 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_16b) -#define TDES_FLAGS_CFB8 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_8b) #define TDES_FLAGS_MODE_MASK (TDES_FLAGS_OPMODE_MASK | TDES_FLAGS_ENCRYPT) @@ -60,13 +55,8 @@ #define ATMEL_TDES_QUEUE_LENGTH 50 -#define CFB8_BLOCK_SIZE 1 -#define CFB16_BLOCK_SIZE 2 -#define CFB32_BLOCK_SIZE 4 - struct atmel_tdes_caps { bool has_dma; - u32 has_cfb_3keys; }; struct atmel_tdes_dev; @@ -376,7 +366,6 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length) { - struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); int len32; dd->dma_size = length; @@ -386,19 +375,7 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, DMA_TO_DEVICE); } - switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - len32 = DIV_ROUND_UP(length, sizeof(u8)); - break; - - case TDES_FLAGS_CFB16: - len32 = DIV_ROUND_UP(length, sizeof(u16)); - break; - - default: - len32 = DIV_ROUND_UP(length, sizeof(u32)); - break; - } + len32 = DIV_ROUND_UP(length, sizeof(u32)); atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); atmel_tdes_write(dd, TDES_TPR, dma_addr_in); @@ -419,7 +396,6 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length) { - struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); struct scatterlist sg[2]; struct dma_async_tx_descriptor *in_desc, *out_desc; enum dma_slave_buswidth addr_width; @@ -431,19 +407,7 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, DMA_TO_DEVICE); } - switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - break; - - case TDES_FLAGS_CFB16: - addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - - default: - addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - } + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dd->dma_lch_in.dma_conf.dst_addr_width = addr_width; dd->dma_lch_out.dma_conf.src_addr_width = addr_width; @@ -680,39 +644,11 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) if (!req->cryptlen) return 0; - switch (mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB8 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB8_BLOCK_SIZE; - break; - - case TDES_FLAGS_CFB16: - if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB16 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB16_BLOCK_SIZE; - break; - - case TDES_FLAGS_CFB32: - if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB32 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB32_BLOCK_SIZE; - break; - - default: - if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of DES blocks\n"); - return -EINVAL; - } - ctx->block_size = DES_BLOCK_SIZE; - break; + if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { + dev_dbg(dev, "request size is not exact amount of DES blocks\n"); + return -EINVAL; } + ctx->block_size = DES_BLOCK_SIZE; rctx->mode = mode; @@ -832,55 +768,6 @@ static int atmel_tdes_cbc_decrypt(struct skcipher_request *req) { return atmel_tdes_crypt(req, TDES_FLAGS_CBC); } -static int atmel_tdes_cfb_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB64 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB64); -} - -static int atmel_tdes_cfb8_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB8 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb8_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB8); -} - -static int atmel_tdes_cfb16_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB16 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb16_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB16); -} - -static int atmel_tdes_cfb32_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB32 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb32_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB32); -} - -static int atmel_tdes_ofb_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_OFB | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_ofb_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_OFB); -} static int atmel_tdes_init_tfm(struct crypto_skcipher *tfm) { @@ -931,71 +818,6 @@ static struct skcipher_alg tdes_algs[] = { .encrypt = atmel_tdes_cbc_encrypt, .decrypt = atmel_tdes_cbc_decrypt, }, -{ - .base.cra_name = "cfb(des)", - .base.cra_driver_name = "atmel-cfb-des", - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_alignmask = 0x7, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb_encrypt, - .decrypt = atmel_tdes_cfb_decrypt, -}, -{ - .base.cra_name = "cfb8(des)", - .base.cra_driver_name = "atmel-cfb8-des", - .base.cra_blocksize = CFB8_BLOCK_SIZE, - .base.cra_alignmask = 0, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb8_encrypt, - .decrypt = atmel_tdes_cfb8_decrypt, -}, -{ - .base.cra_name = "cfb16(des)", - .base.cra_driver_name = "atmel-cfb16-des", - .base.cra_blocksize = CFB16_BLOCK_SIZE, - .base.cra_alignmask = 0x1, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb16_encrypt, - .decrypt = atmel_tdes_cfb16_decrypt, -}, -{ - .base.cra_name = "cfb32(des)", - .base.cra_driver_name = "atmel-cfb32-des", - .base.cra_blocksize = CFB32_BLOCK_SIZE, - .base.cra_alignmask = 0x3, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb32_encrypt, - .decrypt = atmel_tdes_cfb32_decrypt, -}, -{ - .base.cra_name = "ofb(des)", - .base.cra_driver_name = "atmel-ofb-des", - .base.cra_blocksize = 1, - .base.cra_alignmask = 0x7, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_ofb_encrypt, - .decrypt = atmel_tdes_ofb_decrypt, -}, { .base.cra_name = "ecb(des3_ede)", .base.cra_driver_name = "atmel-ecb-tdes", @@ -1021,19 +843,6 @@ static struct skcipher_alg tdes_algs[] = { .decrypt = atmel_tdes_cbc_decrypt, .ivsize = DES_BLOCK_SIZE, }, -{ - .base.cra_name = "ofb(des3_ede)", - .base.cra_driver_name = "atmel-ofb-tdes", - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_alignmask = 0x7, - - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = atmel_tdes_setkey, - .encrypt = atmel_tdes_ofb_encrypt, - .decrypt = atmel_tdes_ofb_decrypt, - .ivsize = DES_BLOCK_SIZE, -}, }; static void atmel_tdes_queue_task(unsigned long data) @@ -1088,47 +897,32 @@ static irqreturn_t atmel_tdes_irq(int irq, void *dev_id) return IRQ_NONE; } -static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) - crypto_unregister_skcipher(&tdes_algs[i]); -} - static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) { - int err, i, j; + int err, i; for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { atmel_tdes_skcipher_alg_init(&tdes_algs[i]); err = crypto_register_skcipher(&tdes_algs[i]); - if (err) - goto err_tdes_algs; + if (err) { + crypto_unregister_skciphers(tdes_algs, i); + return err; + } } return 0; - -err_tdes_algs: - for (j = 0; j < i; j++) - crypto_unregister_skcipher(&tdes_algs[j]); - - return err; } static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) { - dd->caps.has_dma = 0; - dd->caps.has_cfb_3keys = 0; /* keep only major version number */ switch (dd->hw_version & 0xf00) { case 0x800: case 0x700: dd->caps.has_dma = 1; - dd->caps.has_cfb_3keys = 1; break; case 0x600: break; @@ -1254,7 +1048,7 @@ static int atmel_tdes_remove(struct platform_device *pdev) list_del(&tdes_dd->list); spin_unlock(&atmel_tdes.lock); - atmel_tdes_unregister_algs(tdes_dd); + crypto_unregister_skciphers(tdes_algs, ARRAY_SIZE(tdes_algs)); tasklet_kill(&tdes_dd->done_task); tasklet_kill(&tdes_dd->queue_task); diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 918e223f21b651..5a48155ea796a8 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -29,8 +29,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) if (ret) return ret; - if (ctx->u.aes.mode != CCP_AES_MODE_ECB) - memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); + if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { + size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); + + memcpy(req->iv, rctx->iv, ivsize); + } return 0; } diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h index 7ea8962272f2f4..d28732225c9e05 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h @@ -3,6 +3,8 @@ #ifndef _ICP_QAT_HW_20_COMP_H_ #define _ICP_QAT_HW_20_COMP_H_ +#include + #include "icp_qat_hw_20_comp_defs.h" #include "icp_qat_fw.h" @@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); - return __builtin_bswap32(val32); + return swab32(val32); } struct icp_qat_hw_comp_20_config_csr_upper { @@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); - return __builtin_bswap32(val32); + return swab32(val32); } struct icp_qat_hw_decomp_20_config_csr_lower { @@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS, ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK); - return __builtin_bswap32(val32); + return swab32(val32); } struct icp_qat_hw_decomp_20_config_csr_upper { @@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); - return __builtin_bswap32(val32); + return swab32(val32); } #endif diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 8b1dc05df8c8dc..3b82b6f67f8c40 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -101,13 +101,9 @@ static int update_param(struct nx842_crypto_param *p, return 0; } -void *nx842_crypto_alloc_ctx(struct nx842_driver *driver) +int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver) { - struct nx842_crypto_ctx *ctx; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); spin_lock_init(&ctx->lock); ctx->driver = driver; @@ -115,24 +111,25 @@ void *nx842_crypto_alloc_ctx(struct nx842_driver *driver) ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { - nx842_crypto_free_ctx(ctx); - return ERR_PTR(-ENOMEM); + kfree(ctx->wmem); + free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); + free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); + return -ENOMEM; } - return ctx; + return 0; } -EXPORT_SYMBOL_GPL(nx842_crypto_alloc_ctx); +EXPORT_SYMBOL_GPL(nx842_crypto_init); -void nx842_crypto_free_ctx(void *p) +void nx842_crypto_exit(struct crypto_tfm *tfm) { - struct nx842_crypto_ctx *ctx = p; + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); kfree(ctx->wmem); free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); - kfree(ctx); } -EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx); +EXPORT_SYMBOL_GPL(nx842_crypto_exit); static void check_constraints(struct nx842_constraints *c) { @@ -249,11 +246,11 @@ nospc: return update_param(p, slen, dskip + dlen); } -int nx842_crypto_compress(struct crypto_scomp *tfm, +int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen, void *pctx) + u8 *dst, unsigned int *dlen) { - struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr = container_of(&ctx->header, struct nx842_crypto_header, hdr); @@ -434,11 +431,11 @@ usesw: return update_param(p, slen + padding, dlen); } -int nx842_crypto_decompress(struct crypto_scomp *tfm, +int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen, void *pctx) + u8 *dst, unsigned int *dlen) { - struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr; struct nx842_crypto_param p; struct nx842_constraints c = *ctx->driver->constraints; diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h index 58137ffd3835b3..25fa70b2112cff 100644 --- a/drivers/crypto/nx/nx-842.h +++ b/drivers/crypto/nx/nx-842.h @@ -3,6 +3,7 @@ #ifndef __NX_842_H__ #define __NX_842_H__ +#include #include #include #include @@ -100,8 +101,6 @@ #define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1))) #define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE) -struct crypto_scomp; - static inline unsigned long nx842_get_pa(void *addr) { if (!is_vmalloc_addr(addr)) @@ -180,13 +179,13 @@ struct nx842_crypto_ctx { struct nx842_driver *driver; }; -void *nx842_crypto_alloc_ctx(struct nx842_driver *driver); -void nx842_crypto_free_ctx(void *ctx); -int nx842_crypto_compress(struct crypto_scomp *tfm, +int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver); +void nx842_crypto_exit(struct crypto_tfm *tfm); +int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen, void *ctx); -int nx842_crypto_decompress(struct crypto_scomp *tfm, + u8 *dst, unsigned int *dlen); +int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen, void *ctx); + u8 *dst, unsigned int *dlen); #endif /* __NX_842_H__ */ diff --git a/drivers/crypto/nx/nx-common-powernv.c b/drivers/crypto/nx/nx-common-powernv.c index fd0a98b2fb1b25..8c859872c1839e 100644 --- a/drivers/crypto/nx/nx-common-powernv.c +++ b/drivers/crypto/nx/nx-common-powernv.c @@ -9,7 +9,6 @@ #include "nx-842.h" -#include #include #include @@ -1032,21 +1031,23 @@ static struct nx842_driver nx842_powernv_driver = { .decompress = nx842_powernv_decompress, }; -static void *nx842_powernv_crypto_alloc_ctx(void) +static int nx842_powernv_crypto_init(struct crypto_tfm *tfm) { - return nx842_crypto_alloc_ctx(&nx842_powernv_driver); + return nx842_crypto_init(tfm, &nx842_powernv_driver); } -static struct scomp_alg nx842_powernv_alg = { - .base.cra_name = "842", - .base.cra_driver_name = "842-nx", - .base.cra_priority = 300, - .base.cra_module = THIS_MODULE, - - .alloc_ctx = nx842_powernv_crypto_alloc_ctx, - .free_ctx = nx842_crypto_free_ctx, - .compress = nx842_crypto_compress, - .decompress = nx842_crypto_decompress, +static struct crypto_alg nx842_powernv_alg = { + .cra_name = "842", + .cra_driver_name = "842-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_crypto_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_powernv_crypto_init, + .cra_exit = nx842_crypto_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } }; static __init int nx_compress_powernv_init(void) @@ -1106,7 +1107,7 @@ static __init int nx_compress_powernv_init(void) nx842_powernv_exec = nx842_exec_vas; } - ret = crypto_register_scomp(&nx842_powernv_alg); + ret = crypto_register_alg(&nx842_powernv_alg); if (ret) { nx_delete_coprocs(); return ret; @@ -1127,7 +1128,7 @@ static void __exit nx_compress_powernv_exit(void) if (!nx842_ct) vas_unregister_api_powernv(); - crypto_unregister_scomp(&nx842_powernv_alg); + crypto_unregister_alg(&nx842_powernv_alg); nx_delete_coprocs(); } diff --git a/drivers/crypto/nx/nx-common-pseries.c b/drivers/crypto/nx/nx-common-pseries.c index 0d26aafd08863e..7e98f174f69b99 100644 --- a/drivers/crypto/nx/nx-common-pseries.c +++ b/drivers/crypto/nx/nx-common-pseries.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "nx-842.h" #include "nx_csbcpb.h" /* struct nx_csbcpb */ @@ -1009,21 +1008,23 @@ static struct nx842_driver nx842_pseries_driver = { .decompress = nx842_pseries_decompress, }; -static void *nx842_pseries_crypto_alloc_ctx(void) +static int nx842_pseries_crypto_init(struct crypto_tfm *tfm) { - return nx842_crypto_alloc_ctx(&nx842_pseries_driver); + return nx842_crypto_init(tfm, &nx842_pseries_driver); } -static struct scomp_alg nx842_pseries_alg = { - .base.cra_name = "842", - .base.cra_driver_name = "842-nx", - .base.cra_priority = 300, - .base.cra_module = THIS_MODULE, - - .alloc_ctx = nx842_pseries_crypto_alloc_ctx, - .free_ctx = nx842_crypto_free_ctx, - .compress = nx842_crypto_compress, - .decompress = nx842_crypto_decompress, +static struct crypto_alg nx842_pseries_alg = { + .cra_name = "842", + .cra_driver_name = "842-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_crypto_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_pseries_crypto_init, + .cra_exit = nx842_crypto_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } }; static int nx842_probe(struct vio_dev *viodev, @@ -1071,7 +1072,7 @@ static int nx842_probe(struct vio_dev *viodev, if (ret) goto error; - ret = crypto_register_scomp(&nx842_pseries_alg); + ret = crypto_register_alg(&nx842_pseries_alg); if (ret) { dev_err(&viodev->dev, "could not register comp alg: %d\n", ret); goto error; @@ -1119,7 +1120,7 @@ static void nx842_remove(struct vio_dev *viodev) if (caps_feat) sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group); - crypto_unregister_scomp(&nx842_pseries_alg); + crypto_unregister_alg(&nx842_pseries_alg); spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, @@ -1251,7 +1252,7 @@ static void __exit nx842_pseries_exit(void) vas_unregister_api_pseries(); - crypto_unregister_scomp(&nx842_pseries_alg); + crypto_unregister_alg(&nx842_pseries_alg); spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index 94eb6f6afa2572..af221d5d999f2d 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -1775,13 +1775,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) { return sa_cra_init_aead(tfm, "sha1", - "authenc(hmac(sha1-ce),cbc(aes-ce))"); + "authenc(hmac(sha1),cbc(aes))"); } static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) { return sa_cra_init_aead(tfm, "sha256", - "authenc(hmac(sha256-ce),cbc(aes-ce))"); + "authenc(hmac(sha256),cbc(aes))"); } static void sa_exit_tfm_aead(struct crypto_aead *tfm) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 72fb40de58b3f4..3ea3e203253a9f 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -546,8 +546,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); - - return; } /* diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index cfb9962417ef68..53f572b6b6fc62 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev) if (ret) { dev_err(mxs_dma->dma_device.dev, "failed to register controller\n"); + return ret; } dev_info(mxs_dma->dma_device.dev, "initialized\n"); diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 97bafb5f703892..c6a8bdbcae71b9 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) cap_info->pages = temp_page; temp_page = krealloc(cap_info->phys, - pages_needed * sizeof(phys_addr_t *), + pages_needed * sizeof(phys_addr_t), GFP_KERNEL | __GFP_ZERO); if (!temp_page) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 52c093e42531bd..5f4fef27177b48 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -1257,6 +1257,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; break; + default: + return MODE_BAD; } /* When the display EDID claims that it's an HDMI display, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 8cb192636368f4..1584936f295104 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -264,7 +264,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc * @adev: amdgpu device structure holding all necessary information * @mc: memory controller structure holding memory information * - * Function will place try to place GART before or after VRAM. + * Function will try to place GART before or after VRAM. * If GART size is bigger than space left then we ajust GART size. * Thus function will never fails. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 10730f256ae0fd..4c678048be63b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -724,68 +724,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ? -EFAULT : 0; } case AMDGPU_INFO_READ_MMR_REG: { - int ret = 0; - unsigned int n, alloc_size; - uint32_t *regs; unsigned int se_num = (info->read_mmr_reg.instance >> AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & AMDGPU_INFO_MMR_SE_INDEX_MASK; unsigned int sh_num = (info->read_mmr_reg.instance >> AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & AMDGPU_INFO_MMR_SH_INDEX_MASK; - - if (!down_read_trylock(&adev->reset_domain->sem)) - return -ENOENT; + unsigned int alloc_size; + uint32_t *regs; + int ret; /* set full masks if the userspace set all bits * in the bitfields */ - if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { + if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) se_num = 0xffffffff; - } else if (se_num >= AMDGPU_GFX_MAX_SE) { - ret = -EINVAL; - goto out; - } + else if (se_num >= AMDGPU_GFX_MAX_SE) + return -EINVAL; - if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { + if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) sh_num = 0xffffffff; - } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { - ret = -EINVAL; - goto out; - } + else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) + return -EINVAL; - if (info->read_mmr_reg.count > 128) { - ret = -EINVAL; - goto out; - } + if (info->read_mmr_reg.count > 128) + return -EINVAL; - regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); - if (!regs) { - ret = -ENOMEM; - goto out; - } + regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), + GFP_KERNEL); + if (!regs) + return -ENOMEM; + down_read(&adev->reset_domain->sem); alloc_size = info->read_mmr_reg.count * sizeof(*regs); - amdgpu_gfx_off_ctrl(adev, false); + ret = 0; for (i = 0; i < info->read_mmr_reg.count; i++) { if (amdgpu_asic_read_register(adev, se_num, sh_num, info->read_mmr_reg.dword_offset + i, ®s[i])) { DRM_DEBUG_KMS("unallowed offset %#x\n", info->read_mmr_reg.dword_offset + i); - kfree(regs); - amdgpu_gfx_off_ctrl(adev, true); ret = -EFAULT; - goto out; + break; } } amdgpu_gfx_off_ctrl(adev, true); - n = copy_to_user(out, regs, min(size, alloc_size)); - kfree(regs); - ret = (n ? -EFAULT : 0); -out: up_read(&adev->reset_domain->sem); + + if (!ret) { + ret = copy_to_user(out, regs, min(size, alloc_size)) + ? -EFAULT : 0; + } + kfree(regs); return ret; } case AMDGPU_INFO_DEV_INFO: { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 1c29b4d04a2ca2..afa9eb70507512 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -6338,7 +6338,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, /* set up default queue priority level * 0x0 = low priority, 0x1 = high priority */ - if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) + if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) priority = 1; tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 34f9211b26793f..d4f0437001089b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -1554,6 +1554,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) mutex_unlock(&adev->grbm_idx_mutex); } +/** + * gfx_v6_0_setup_tcc() - setup which TCCs are used + * + * @adev: amdgpu_device pointer + * + * Verify whether the current GPU has any TCCs disabled, + * which can happen when the GPU is harvested and some + * memory channels are disabled, reducing the memory bus width. + * For example, on the Radeon HD 7870 XT (Tahiti LE). + * + * If some TCCs are disabled, we need to make sure that + * the disabled TCCs are not used, and the remaining TCCs + * are used optimally. + * + * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. + * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + * + * For optimal performance: + * - Rely on the CHAN_STEER from the golden registers table, + * only skip disabled TCCs but keep the mapping order. + * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + * which performs better than using the same TCC twice. + */ +static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) +{ + u32 i, tcc, tcp_addr_config, num_active_tcc = 0; + u64 chan_steer, patched_chan_steer = 0; + const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; + const u32 dis_tcc_mask = + amdgpu_gfx_create_bitmask(num_max_tcc) & + (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), + CGTS_TCC_DISABLE, TCC_DISABLE) | + REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), + CGTS_USER_TCC_DISABLE, TCC_DISABLE)); + + /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ + if (!dis_tcc_mask) + return; + + /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ + chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); + + /* Patch the TCP to TCC mapping to skip disabled TCCs */ + for (i = 0; i < num_max_tcc; ++i) { + tcc = (chan_steer >> (u64)(4 * i)) & 0xf; + + if (!((1 << tcc) & dis_tcc_mask)) { + /* Copy enabled TCC indices to the patched register value. */ + patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); + ++num_active_tcc; + } + } + + WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); + + /* Patch number of TCCs used by TCPs */ + tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), + TCP_ADDR_CONFIG, NUM_TCC_BANKS, + num_active_tcc - 1); + + WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); + WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); + WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); +} + static void gfx_v6_0_config_init(struct amdgpu_device *adev) { adev->gfx.config.double_offchip_lds_buf = 0; @@ -1712,6 +1777,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) gfx_v6_0_tiling_mode_table_init(adev); gfx_v6_0_setup_rb(adev); + gfx_v6_0_setup_tcc(adev); gfx_v6_0_setup_spi(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c index fbe57499495ec5..c2b9829c12fd97 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c @@ -764,6 +764,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr, .set_wptr = jpeg_v2_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index aadb74de52bcf8..1d2e5201bbca1d 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -657,6 +657,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr, @@ -686,6 +687,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index df4440c21bbf4f..f587664cf31a7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -562,6 +562,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c index 3eb3dcd56b5791..9d4eb9c8885f1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c @@ -722,6 +722,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index 78aaaee492e111..210177c7385542 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -1054,6 +1054,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_JPEG, .align_mask = 0xf, + .no_user_fence = true, .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c index 1e0189f90fd6ac..49a0d66d5b2c0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c @@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, } /** - * uvd_v3_1_ring_emit_fence - emit an fence & trap command + * uvd_v3_1_ring_emit_fence - emit a fence & trap command * * @ring: amdgpu_ring pointer * @addr: address @@ -242,7 +242,11 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) uint64_t addr; uint32_t size; - /* programm the VCPU memory controller bits 0-27 */ + /* When the keyselect is already set, don't perturb it. */ + if (RREG32(mmUVD_FW_START)) + return; + + /* program the VCPU memory controller bits 0-27 */ addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr); @@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) int i; uint32_t keysel = adev->uvd.keyselect; + if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { + dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", + RREG32(mmUVD_FW_START), adev->uvd.keyselect); + return 0; + } + WREG32(mmUVD_FW_START, keysel); for (i = 0; i < 10; ++i) { @@ -416,7 +426,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev) /* Set the write pointer delay */ WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); - /* programm the 4GB memory segment for rptr and ring buffer */ + /* Program the 4GB memory segment for rptr and ring buffer */ WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | (0x7 << 16) | (0x1 << 31)); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index c108b83817951b..01d8e7d2caf971 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -298,7 +298,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) /* enable VCPU clock */ WREG32(mmUVD_VCPU_CNTL, 1 << 9); - /* disable interupt */ + /* disable interrupt */ WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); #ifdef __BIG_ENDIAN @@ -308,6 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) #endif WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); + /* initialize UVD memory controller */ WREG32(mmUVD_LMI_CTRL, 0x203108); diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 67eb01fef789b9..479eb9382c77e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev) int status; if (vce_v2_0_lmi_clean(adev)) { - DRM_INFO("vce is not idle \n"); + DRM_INFO("VCE is not idle \n"); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 2505951ad06a09..1a9c8e9e854df2 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -2014,6 +2014,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_0_dec_ring_get_rptr, .get_wptr = vcn_v2_0_dec_ring_get_wptr, @@ -2045,6 +2046,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr, .set_wptr = vcn_v2_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 6fbea38f4d3e1b..fa0459ed079cab 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -1573,6 +1573,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_5_dec_ring_get_rptr, .get_wptr = vcn_v2_5_dec_ring_get_wptr, @@ -1673,6 +1674,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr, .set_wptr = vcn_v2_5_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index c9345da548a615..37b93af917fe29 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -1737,6 +1737,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr, @@ -1918,6 +1919,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr, @@ -2019,6 +2021,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr, .set_wptr = vcn_v3_0_enc_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index d1141a9baa916b..3379469ab04c12 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -1423,6 +1423,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 684b005f564c47..ac2a71e80723d1 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -1220,6 +1220,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( return BP_RESULT_FAILURE; } +static enum bp_result get_embedded_panel_extra_info( + struct bios_parser *bp, + struct embedded_panel_info *info, + const uint32_t table_offset) +{ + uint8_t *record = bios_get_image(&bp->base, table_offset, 1); + ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; + ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; + + while (*record != ATOM_RECORD_END_TYPE) { + switch (*record) { + case LCD_MODE_PATCH_RECORD_MODE_TYPE: + record += sizeof(ATOM_PATCH_RECORD_MODE); + break; + case LCD_RTS_RECORD_TYPE: + record += sizeof(ATOM_LCD_RTS_RECORD); + break; + case LCD_CAP_RECORD_TYPE: + record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); + break; + case LCD_FAKE_EDID_PATCH_RECORD_TYPE: + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; + if (fake_edid_record->ucFakeEDIDLength) { + if (fake_edid_record->ucFakeEDIDLength == 128) + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength; + else + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength * 128; + + info->fake_edid = fake_edid_record->ucFakeEDIDString; + + record += struct_size(fake_edid_record, + ucFakeEDIDString, + info->fake_edid_size); + } else { + /* empty fake edid record must be 3 bytes long */ + record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; + } + break; + case LCD_PANEL_RESOLUTION_RECORD_TYPE: + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; + info->panel_width_mm = panel_res_record->usHSize; + info->panel_height_mm = panel_res_record->usVSize; + record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); + break; + default: + return BP_RESULT_BADBIOSTABLE; + } + } + + return BP_RESULT_OK; +} + static enum bp_result get_embedded_panel_info_v1_2( struct bios_parser *bp, struct embedded_panel_info *info) @@ -1336,6 +1390,10 @@ static enum bp_result get_embedded_panel_info_v1_2( if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) info->lcd_timing.misc_info.API_ENABLED = true; + if (lvds->usExtInfoTableOffset) + return get_embedded_panel_extra_info(bp, info, + le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); + return BP_RESULT_OK; } @@ -1461,6 +1519,10 @@ static enum bp_result get_embedded_panel_info_v1_3( (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + if (lvds->usExtInfoTableOffset) + return get_embedded_panel_extra_info(bp, info, + le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); + return BP_RESULT_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 0a33f8f117e921..623abdf7065e75 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init( ASSERT(result == BP_RESULT_OK); } - aux_initialize(enc110); + + if (enc110->aux_regs) + aux_initialize(enc110); /* reinitialize HPD. * hpd_initialize() will pass DIG_FE id to HW context. diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 813463ffe15c52..8e776c90d21bff 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -153,6 +153,10 @@ struct embedded_panel_info { uint32_t drr_enabled; uint32_t min_drr_refresh_rate; bool realtek_eDPToLVDS; + uint16_t panel_width_mm; + uint16_t panel_height_mm; + uint16_t fake_edid_size; + const uint8_t *fake_edid; }; struct dc_firmware_info { diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c index 2b5ac21fee3997..1d6e30269d5679 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c @@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) PP_GFXOFF_MASK); hwmgr->pp_table_version = PP_TABLE_V0; hwmgr->od_enabled = false; + switch (hwmgr->chip_id) { + case CHIP_BONAIRE: + /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM + * R7 260X cards with old MC ucode: MCLK DPM is unstable + */ + if (adev->pdev->subsystem_vendor == 0x106B || + adev->pdev->device == 0x6658) { + dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); + adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; + hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; + } + break; + default: + break; + } smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_CZ: diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 965ffcac17f860..9dc01de3e72072 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) hwmgr->dyn_state.vddc_dependency_on_mclk; struct phm_cac_leakage_table *std_voltage_table = hwmgr->dyn_state.cac_leakage_table; - uint32_t i; + uint32_t i, clk; PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, "SCLK dependency table is missing. This table is mandatory", return -EINVAL); @@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) data->dpm_table.sclk_table.count = 0; for (i = 0; i < allowed_vdd_sclk_table->count; i++) { + clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != - allowed_vdd_sclk_table->entries[i].clk) { + clk) { data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = - allowed_vdd_sclk_table->entries[i].clk; + clk; data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; data->dpm_table.sclk_table.count++; } @@ -2802,6 +2804,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) if (tmp) return -EINVAL; + tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); + if (tmp) + return -EINVAL; + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); if (tmp) return -EINVAL; @@ -2885,6 +2891,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) { kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; + kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); + hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; kfree(hwmgr->backend); hwmgr->backend = NULL; @@ -2955,6 +2963,70 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) return ret; } +static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) +{ + struct phm_clock_voltage_dependency_table *table; + + if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) + return 0; + + table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); + if (!table) + return -ENOMEM; + + if (hwmgr->chip_id >= CHIP_POLARIS10) { + table->entries[0].clk = 38918; + table->entries[1].clk = 45900; + table->entries[2].clk = 66700; + table->entries[3].clk = 113200; + + table->entries[0].v = 700; + table->entries[1].v = 740; + table->entries[2].v = 800; + table->entries[3].v = 900; + } else { + if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { + table->entries[0].clk = 35200; + table->entries[1].clk = 35200; + table->entries[2].clk = 46700; + table->entries[3].clk = 64300; + } else { + table->entries[0].clk = 0; + table->entries[1].clk = 35200; + table->entries[2].clk = 54000; + table->entries[3].clk = 62500; + } + + table->entries[0].v = 0; + table->entries[1].v = 720; + table->entries[2].v = 810; + table->entries[3].v = 900; + } + + table->count = 4; + hwmgr->dyn_state.vddc_dependency_on_display_clock = table; + return 0; +} + +static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + data->sclk_cap = 0xffffffff; + + if (hwmgr->od_enabled) + return; + + /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ + if (adev->pdev->device == 0x67B0 && + adev->pdev->subsystem_vendor == 0x1043) + data->sclk_cap = 104000; /* 1040 MHz */ + + if (data->sclk_cap != 0xffffffff) + dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); +} + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; @@ -2966,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) return -ENOMEM; hwmgr->backend = data; + smu7_set_sclk_cap(hwmgr); smu7_patch_voltage_workaround(hwmgr); smu7_init_dpm_defaults(hwmgr); @@ -2983,6 +3056,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) smu7_get_elb_voltages(hwmgr); } + result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); + if (result) + goto fail; + if (hwmgr->pp_table_version == PP_TABLE_V1) { smu7_complete_dependency_tables(hwmgr); smu7_set_private_data_based_on_pptable_v1(hwmgr); @@ -3079,13 +3156,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) return 0; } +static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) +{ + const struct amd_pp_display_configuration *cfg = hwmgr->display_config; + const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = + hwmgr->dyn_state.vddc_dependency_on_display_clock; + uint32_t i; + + if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || + !cfg || !cfg->num_display || !cfg->display_clk) + return 0; + + /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ + for (i = 1; i < vddc_dep_on_dispclk->count; ++i) + if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) + return vddc_dep_on_dispclk->entries[i].v; + + return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; +} + +static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) +{ + uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_VddC_Request, + req_vddc * VOLTAGE_SCALE, + NULL); +} + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (hwmgr->pp_table_version == PP_TABLE_V1) - phm_apply_dal_min_voltage_request(hwmgr); -/* TO DO for v0 iceland and Ci*/ + smu7_apply_minimum_dce_voltage_request(hwmgr); if (!data->sclk_dpm_key_disabled) { if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) @@ -3821,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, /* Performance levels are arranged from low to high. */ performance_level->memory_clock = memory_clock; - performance_level->engine_clock = engine_clock; + performance_level->engine_clock = min(engine_clock, data->sclk_cap); pcie_gen_from_bios = visland_clk_info->ucPCIEGen; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h index d9e8b386bd4d38..66adabeab6a3aa 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h @@ -234,6 +234,7 @@ struct smu7_hwmgr { uint32_t pcie_gen_cap; uint32_t pcie_lane_cap; uint32_t pcie_spc_cap; + uint32_t sclk_cap; struct smu7_leakage_voltage vddc_leakage; struct smu7_leakage_voltage vddci_leakage; struct smu7_leakage_voltage vddcgfx_leakage; diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 81650727a5defe..6e7e6318b9505a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -632,6 +632,7 @@ struct phm_dynamic_state_info { struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; struct phm_clock_array *valid_sclk_values; struct phm_clock_array *valid_mclk_values; diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c index 23f991dd065f31..741ebeb276b843 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c @@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) smu_data->power_tune_defaults = &defaults_hawaii_pro; break; case 0x67B8: - case 0x66B0: + case 0x67B0: smu_data->power_tune_defaults = &defaults_hawaii_xt; break; case 0x6640: @@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; - uint32_t temp; if (ci_read_smc_sram_dword(hwmgr, fuse_table_offset + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), - (uint32_t *)&temp, SMC_RAM_END)) + (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) PP_ASSERT_WITH_CODE(false, "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", return -EINVAL); @@ -1217,7 +1216,7 @@ static int ci_populate_single_memory_level( } memory_level->EnabledForThrottle = 1; - memory_level->EnabledForActivity = 1; + memory_level->EnabledForActivity = 0; memory_level->UpH = data->current_profile_setting.mclk_up_hyst; memory_level->DownH = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownH = 0; @@ -1322,6 +1321,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) return result; } + if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { + /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ + for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { + levels[i] = levels[dpm_table->mclk_table.count - 1]; + levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; + } + } + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; dev_id = adev->pdev->device; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c index df5da5a447555c..b4f2b89651ff2f 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c @@ -4,6 +4,8 @@ * Author: James.Qian.Wang * */ +#include + #include #include #include @@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, kfb->afbc_size = kfb->offset_payload + n_blocks * ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, AFBC_SUPERBLK_ALIGNMENT); - min_size = kfb->afbc_size + fb->offsets[0]; + if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { + goto check_failed; + } if (min_size > obj->size) { DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", obj->size, min_size); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index bdb9fc00c776b3..44955601a9dfc4 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -810,7 +810,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) bridge_attached = mhdp->bridge_attached; spin_unlock(&mhdp->start_lock); if (bridge_attached) { - if (mhdp->connector.dev) + if (mhdp->connector_ptr) drm_kms_helper_hotplug_event(mhdp->bridge.dev); else drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); @@ -1709,6 +1709,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) return ret; } + mhdp->connector_ptr = conn; drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); ret = drm_display_info_set_bus_formats(&conn->display_info, @@ -1988,17 +1989,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state = bridge_state->base.state; struct cdns_mhdp_bridge_state *mhdp_state; struct drm_crtc_state *crtc_state; - struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_bridge_state *new_state; const struct drm_display_mode *mode; u32 resp; - int ret; + int ret = 0; dev_dbg(mhdp->dev, "bridge enable\n"); mutex_lock(&mhdp->link_mutex); + mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + if (WARN_ON(!mhdp->connector_ptr)) + goto out; + + conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); + if (WARN_ON(!conn_state)) + goto out; + if (mhdp->plugged && !mhdp->link_up) { ret = cdns_mhdp_link_up(mhdp); if (ret < 0) @@ -2018,15 +2027,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); - connector = drm_atomic_get_new_connector_for_encoder(state, - bridge->encoder); - if (WARN_ON(!connector)) - goto out; - - conn_state = drm_atomic_get_new_connector_state(state, connector); - if (WARN_ON(!conn_state)) - goto out; - if (mhdp->hdcp_supported && mhdp->hw_state == MHDP_HW_READY && conn_state->content_protection == @@ -2103,6 +2103,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) mhdp->info->ops->disable(mhdp); + mhdp->connector_ptr = NULL; mutex_unlock(&mhdp->link_mutex); } @@ -2195,6 +2196,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, { struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); const struct drm_display_mode *mode = &crtc_state->adjusted_mode; + struct drm_connector_state *old_state, *new_state; + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *conn = mhdp->connector_ptr; + u64 old_cp, new_cp; mutex_lock(&mhdp->link_mutex); @@ -2214,6 +2219,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, if (mhdp->info) bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags; + if (conn && mhdp->hdcp_supported) { + old_state = drm_atomic_get_old_connector_state(state, conn); + new_state = drm_atomic_get_new_connector_state(state, conn); + old_cp = old_state->content_protection; + new_cp = new_state->content_protection; + + if (old_state->hdcp_content_type != new_state->hdcp_content_type && + new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); + crtc_state->mode_changed = true; + } + + if (!new_state->crtc) { + if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + } + } + mutex_unlock(&mhdp->link_mutex); return 0; } @@ -2233,6 +2257,25 @@ static struct edid *cdns_mhdp_bridge_get_edid(struct drm_bridge *bridge, return cdns_mhdp_get_edid(mhdp, connector); } +static enum drm_mode_status +cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + + mutex_lock(&mhdp->link_mutex); + + if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, + mhdp->link.rate)) { + mutex_unlock(&mhdp->link_mutex); + return MODE_CLOCK_HIGH; + } + + mutex_unlock(&mhdp->link_mutex); + return MODE_OK; +} + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { .atomic_enable = cdns_mhdp_atomic_enable, .atomic_disable = cdns_mhdp_atomic_disable, @@ -2247,6 +2290,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { .get_edid = cdns_mhdp_bridge_get_edid, .hpd_enable = cdns_mhdp_bridge_hpd_enable, .hpd_disable = cdns_mhdp_bridge_hpd_disable, + .mode_valid = cdns_mhdp_bridge_mode_valid, }; static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) @@ -2368,7 +2412,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); - conn = &mhdp->connector; + conn = mhdp->connector_ptr; /* Grab the locks before changing connector property */ mutex_lock(&conn->dev->mode_config.mutex); @@ -2445,7 +2489,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) int ret; ret = cdns_mhdp_update_link_status(mhdp); - if (mhdp->connector.dev) { + if (mhdp->connector_ptr) { if (ret < 0) schedule_work(&mhdp->modeset_retry_work); else diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h index bad2fc0c730660..a76775c7689568 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h @@ -376,6 +376,7 @@ struct cdns_mhdp_device { struct mutex link_mutex; struct drm_connector connector; + struct drm_connector *connector_ptr; struct drm_bridge bridge; struct cdns_mhdp_link link; diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c index 5e3b8edcf79487..28660698055246 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) int ret; dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", - mhdp->connector.name, mhdp->connector.base.id); + mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); @@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) int ret = 0; mutex_lock(&mhdp->hdcp.mutex); + + if (!mhdp->connector_ptr) + goto out; + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) goto out; @@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) dev_err(mhdp->dev, "[%s:%d] HDCP link failed, retrying authentication\n", - mhdp->connector.name, mhdp->connector.base.id); + mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); ret = _cdns_mhdp_hdcp_disable(mhdp); if (ret) { @@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) struct cdns_mhdp_device *mhdp = container_of(hdcp, struct cdns_mhdp_device, hdcp); - struct drm_device *dev = mhdp->connector.dev; + struct drm_device *dev = NULL; struct drm_connector_state *state; + if (mhdp->connector_ptr) + dev = mhdp->connector_ptr->dev; + + if (!dev) + return; + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); mutex_lock(&mhdp->hdcp.mutex); if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - state = mhdp->connector.state; + state = mhdp->connector_ptr->state; state->content_protection = mhdp->hdcp.value; } mutex_unlock(&mhdp->hdcp.mutex); diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index f0ae675581d9a5..fa7a504c935863 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -579,6 +579,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector) } else { edid = (struct edid *)raw_edid; /* FIXME ? edid = drm_get_edid(connector, i2c_adap); */ + i2c_put_adapter(i2c_adap); } if (edid) { diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index d974d0c60d2a4a..a601511bfa34e1 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -294,7 +294,7 @@ void oaktrail_lvds_init(struct drm_device *dev, { struct gma_encoder *gma_encoder; struct gma_connector *gma_connector; - struct gma_i2c_chan *ddc_bus; + struct gma_i2c_chan *ddc_bus = NULL; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); @@ -368,6 +368,8 @@ void oaktrail_lvds_init(struct drm_device *dev, if (edid == NULL && dev_priv->lpc_gpio_base) { ddc_bus = oaktrail_lvds_i2c_init(dev); if (!IS_ERR(ddc_bus)) { + if (i2c_adap) + i2c_put_adapter(i2c_adap); i2c_adap = &ddc_bus->base; edid = drm_get_edid(connector, i2c_adap); } @@ -422,7 +424,10 @@ out: err_unlock: mutex_unlock(&dev->mode_config.mutex); - gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); + if (!IS_ERR_OR_NULL(ddc_bus)) + gma_i2c_destroy(ddc_bus); + else if (i2c_adap) + i2c_put_adapter(i2c_adap); drm_encoder_cleanup(encoder); err_connector_cleanup: drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9a894e234f6239..c3010c9e31c1a7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2029,8 +2029,13 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc drm_WARN_ON(&dev_priv->drm, vsc->bpc == 6 && vsc->pixelformat != DP_PIXELFORMAT_RGB); - /* all YCbCr are always limited range */ - vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA; + /* All YCbCr formats are always limited range. */ + if (vsc->pixelformat == DP_PIXELFORMAT_RGB) + vsc->dynamic_range = crtc_state->limited_color_range ? + DP_DYNAMIC_RANGE_CTA : DP_DYNAMIC_RANGE_VESA; + else + vsc->dynamic_range = DP_DYNAMIC_RANGE_CTA; + vsc->content_type = DP_CONTENT_TYPE_NOT_DEFINED; } diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 138144a65a457d..6e65b867137e79 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -234,7 +234,7 @@ void intel_modeset_verify_crtc(struct intel_crtc *crtc, !intel_crtc_needs_fastset(new_crtc_state)) return; - intel_wm_state_verify(crtc, new_crtc_state); + intel_wm_state_verify(state, crtc); verify_connector_state(state, crtc); verify_crtc_state(crtc, old_crtc_state, new_crtc_state); intel_shared_dpll_state_verify(crtc, old_crtc_state, new_crtc_state); diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 063929a42a42f5..3b30776b73b213 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -3132,10 +3132,12 @@ static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) skl_wm_sanitize(i915); } -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct skl_hw_state { struct skl_ddb_entry ddb[I915_MAX_PLANES]; struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; @@ -3237,8 +3239,8 @@ void intel_wm_state_verify(struct intel_crtc *crtc, } /* DDB */ - hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; - sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; + hw_ddb_entry = &hw->ddb[plane->id]; + sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { drm_err(&i915->drm, @@ -3470,6 +3472,21 @@ int intel_dbuf_init(struct drm_i915_private *i915) return 0; } +static void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, + u8 ratio, + bool joined_mbus) +{ + enum dbuf_slice slice; + + if (joined_mbus) + ratio *= 2; + + for_each_dbuf_slice(i915, slice) + intel_de_rmw(i915, DBUF_CTL_S(slice), + DBUF_MIN_TRACKER_STATE_SERVICE_MASK, + DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); +} + /* * Configure MBUS_CTL and all DBUF_CTL_S of each slice to join_mbus state before * update the request state of all DBUS slices. @@ -3477,8 +3494,7 @@ int intel_dbuf_init(struct drm_i915_private *i915) static void update_mbus_pre_enable(struct intel_atomic_state *state) { struct drm_i915_private *i915 = to_i915(state->base.dev); - u32 mbus_ctl, dbuf_min_tracker_val; - enum dbuf_slice slice; + u32 mbus_ctl; const struct intel_dbuf_state *dbuf_state = intel_atomic_get_new_dbuf_state(state); @@ -3489,24 +3505,18 @@ static void update_mbus_pre_enable(struct intel_atomic_state *state) * TODO: Implement vblank synchronized MBUS joining changes. * Must be properly coordinated with dbuf reprogramming. */ - if (dbuf_state->joined_mbus) { + if (dbuf_state->joined_mbus) mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN | MBUS_JOIN_PIPE_SELECT_NONE; - dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(3); - } else { + else mbus_ctl = MBUS_HASHING_MODE_2x2 | MBUS_JOIN_PIPE_SELECT_NONE; - dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(1); - } intel_de_rmw(i915, MBUS_CTL, MBUS_HASHING_MODE_MASK | MBUS_JOIN | MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl); - for_each_dbuf_slice(i915, slice) - intel_de_rmw(i915, DBUF_CTL_S(slice), - DBUF_MIN_TRACKER_STATE_SERVICE_MASK, - dbuf_min_tracker_val); + intel_dbuf_mdclk_cdclk_ratio_update(i915, 2, dbuf_state->joined_mbus); } void intel_dbuf_pre_plane_update(struct intel_atomic_state *state) @@ -3572,10 +3582,8 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; - const struct intel_crtc_state *new_crtc_state; const struct intel_crtc *crtc; u32 val = 0; - int i; if (DISPLAY_VER(i915) < 11) return; @@ -3619,12 +3627,9 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) val |= MBUS_DBOX_B_CREDIT(8); } - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, new_dbuf_state->active_pipes) { u32 pipe_val = val; - if (!new_crtc_state->hw.active) - continue; - if (DISPLAY_VER(i915) >= 14) { if (xelpdp_is_only_pipe_per_dbuf_bank(crtc->pipe, new_dbuf_state->active_pipes)) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index f91a3d4ddc0756..c7de2b3b2f9157 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -38,8 +38,8 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, const struct skl_ddb_entry *entries, int num_entries, int ignore_idx); -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state); +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc); void skl_watermark_ipc_init(struct drm_i915_private *i915); void skl_watermark_ipc_update(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 13fb8e5042c584..d4976d662c80e6 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -134,7 +134,8 @@ void __i915_request_reset(struct i915_request *rq, bool guilty) rcu_read_lock(); /* protect the GEM context */ if (guilty) { i915_request_set_error_once(rq, -EIO); - __i915_request_skip(rq); + if (!i915_request_signaled(rq)) + __i915_request_skip(rq); banned = mark_guilty(rq); } else { i915_request_set_error_once(rq, -EAGAIN); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 258de1bfc57005..6ebb7e62541757 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -672,7 +672,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; int i, regcount = 0; - in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); + in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); for (i = 0; i < regs->count; i += 2) { u32 count = RANGE(regs->registers, i); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c index 25b235b49ebc21..14a0ec4a56fda9 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c @@ -29,7 +29,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, struct a6xx_hfi_queue_header *header = queue->header; u32 i, hdr, index = header->read_index; - if (header->read_index == header->write_index) { + if (header->read_index == READ_ONCE(header->write_index)) { header->rx_request = 1; return 0; } @@ -57,7 +57,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, if (!gmu->legacy) index = ALIGN(index, 4) % header->size; - header->read_index = index; + /* Ensure all memory operations are complete before updating the read index */ + dma_mb(); + + WRITE_ONCE(header->read_index, index); return HFI_HEADER_SIZE(hdr); } @@ -69,7 +72,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, spin_lock(&queue->lock); - space = CIRC_SPACE(header->write_index, header->read_index, + space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), header->size); if (space < dwords) { header->dropped++; @@ -90,7 +93,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, queue->data[index] = 0xfafafafa; } - header->write_index = index; + /* Ensure all memory operations are complete before updating the write index */ + dma_mb(); + + WRITE_ONCE(header->write_index, index); spin_unlock(&queue->lock); gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 6ba289e04b3b22..4d93b5f78893ec 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1316,8 +1316,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) struct msm_drm_private *priv = platform_get_drvdata(pdev); struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - /* Drop the performance state vote */ - dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); for (i = 0; i < dpu_kms->num_paths; i++) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 1f98ff74ceb09d..39940685681b9a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -263,10 +263,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, + &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, - &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 43f0dd74edb656..32eff457446245 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -19,8 +19,8 @@ #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 +#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 -#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 6077331deba974..771ac345610372 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -533,6 +533,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case * @mode: The selected mode for the DSI output * @dsc: DRM DSC configuration for this DSI output + * @is_bonded_dsi: True if two DSI controllers are bonded * * Adjust the pclk rate by calculating a new hdisplay proportional to * the compression ratio such that: diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 0641f5bb8649ac..5d5cf51cde65ad 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -26,9 +26,8 @@ static bool can_swap(void) static bool can_block(struct shrink_control *sc) { - if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) - return false; - return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); + return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || + (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); } static unsigned long diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 855e64444daa66..58f201720e699a 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -224,6 +224,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); + sharp_nt->base.prepare_prev_first = true; ret = drm_panel_of_backlight(&sharp_nt->base); if (ret) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 8a94eee57d9435..7620ac20393b70 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1157,7 +1157,7 @@ static const struct panel_desc auo_g190ean01 = { .height = 301, }, .delay = { - .prepare = 50, + .prepare = 30, .enable = 200, .disable = 110, .unprepare = 1000, diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index ddcc8259061bbd..0c30310da50e2a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -324,6 +324,8 @@ panfrost_ioctl_wait_bo(struct drm_device *dev, void *data, true, timeout); if (!ret) ret = timeout ? -ETIMEDOUT : -EBUSY; + else if (ret > 0) + ret = 0; drm_gem_object_put(gem_obj); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 335fd0edb904cf..4943577ec7fb88 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -488,6 +488,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { struct drm_plane_state *plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; @@ -875,7 +878,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, &sun4i_backend_regmap_config); if (IS_ERR(backend->engine.regs)) { dev_err(dev, "Couldn't create the backend regmap\n"); - return PTR_ERR(backend->engine.regs); + ret = PTR_ERR(backend->engine.regs); + goto err_disable_ram_clk; } list_add_tail(&backend->engine.list, &drv->engine_list); diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c index 2d999a0facdee2..fe2d3b7c612580 100644 --- a/drivers/gpu/drm/tiny/ofdrm.c +++ b/drivers/gpu/drm/tiny/ofdrm.c @@ -351,6 +351,7 @@ static void ofdrm_pci_release(void *data) struct pci_dev *pcidev = data; pci_disable_device(pcidev); + pci_dev_put(pcidev); } static int ofdrm_device_init_pci(struct ofdrm_device *odev) @@ -376,6 +377,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) if (ret) { drm_err(dev, "pci_enable_device(%s) failed: %d\n", dev_name(&pcidev->dev), ret); + pci_dev_put(pcidev); return ret; } ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index ef991a9b1c6c46..057f9525a8a422 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -597,6 +597,11 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv, if (multisync.pad) return -EINVAL; + if (!multisync.in_sync_count && !multisync.out_sync_count) { + DRM_DEBUG("Empty multisync extension\n"); + return -EINVAL; + } + ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count, multisync.out_syncs); if (ret) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 544b74eda284ae..d3913f70d263d0 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -990,7 +990,8 @@ static int asus_start_multitouch(struct hid_device *hdev) return 0; } -static int __maybe_unused asus_resume(struct hid_device *hdev) { +static int __maybe_unused asus_resume(struct hid_device *hdev) +{ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); int ret = 0; @@ -1117,22 +1118,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) * were freed during registration due to no usages being mapped, * leaving drvdata->input pointing to freed memory. */ - if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { - hid_err(hdev, "Asus input not registered\n"); - ret = -ENOMEM; - goto err_stop_hw; - } - - if (drvdata->tp) { - drvdata->input->name = "Asus TouchPad"; - } else { - drvdata->input->name = "Asus Keyboard"; - } + if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { + if (drvdata->tp) + drvdata->input->name = "Asus TouchPad"; + else + drvdata->input->name = "Asus Keyboard"; - if (drvdata->tp) { - ret = asus_start_multitouch(hdev); - if (ret) - goto err_stop_hw; + if (drvdata->tp) { + ret = asus_start_multitouch(hdev); + if (ret) + goto err_stop_hw; + } } return 0; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 5e3bd615066c1b..415d44ac14807b 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1549,7 +1549,7 @@ static int hid_post_reset(struct usb_interface *intf) * configuration descriptors passed, we already know that * the size of the HID report descriptor has not changed. */ - rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); + rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); if (!rdesc) return -ENOMEM; diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c index e270fcd0f7c387..624d00b853a51a 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -636,7 +636,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) if (!(ibi_status & IBI_LAST_STATUS)) { ibi_size += chunks * rh->ibi_chunk_sz; } else { - ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); + if (chunks) { + ibi_size += (chunks - 1) * rh->ibi_chunk_sz; + ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); + } last_ptr = ptr; break; } diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c index 3c9a9869212bbe..feb09008eb9ca7 100644 --- a/drivers/infiniband/core/iwpm_msg.c +++ b/drivers/infiniband/core/iwpm_msg.c @@ -365,9 +365,9 @@ remove_mapping_error: /* netlink attribute policy for the received response to register pid request */ static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, - [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, + [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, .len = IWPM_DEVNAME_SIZE - 1 }, - [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, + [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, .len = IWPM_ULIBNAME_SIZE - 1 }, [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } @@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) /* netlink attribute policy for the received request for mapping info */ static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { - [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, + [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, .len = IWPM_ULIBNAME_SIZE - 1 }, [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } }; diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c index 8009a339bf9ca7..d17073c0bfeabd 100644 --- a/drivers/infiniband/hw/mana/qp.c +++ b/drivers/infiniband/hw/mana/qp.c @@ -24,6 +24,9 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, mdev = dev->gdma_dev; gc = mdev->gdma_context; + if (rx_hash_key_len > sizeof(req->hashkey)) + return -EINVAL; + req_buf_size = sizeof(*req) + sizeof(mana_handle_t) * MANA_INDIRECT_TABLE_SIZE; req = kzalloc(req_buf_size, GFP_KERNEL); @@ -234,13 +237,15 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, ibdev_dbg(&mdev->ib_dev, "Failed to copy to udata create rss-qp, %d\n", ret); - goto fail; + goto err_disable_vport_rx; } kfree(mana_ind_table); return 0; +err_disable_vport_rx: + mana_disable_vport_rx(mpc); fail: while (i-- > 0) { ibwq = ind_tbl->ind_tbl[i]; diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index ac7b8fb36db8fb..682d84d86739c9 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4851,6 +4851,9 @@ static void quirk_iommu_igfx(struct pci_dev *dev) dmar_map_gfx = 0; } +/* Q35 integrated gfx dmar support is totally busted. */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x29b2, quirk_iommu_igfx); + /* G4x/GM45 integrated gfx dmar support is totally busted. */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx); diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c index 6c810bf80f99a7..7351320394c85c 100644 --- a/drivers/iommu/iommufd/vfio_compat.c +++ b/drivers/iommu/iommufd/vfio_compat.c @@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, case VFIO_TYPE1_IOMMU: case VFIO_TYPE1v2_IOMMU: case VFIO_UNMAP_ALL: - return 1; + return !ictx->no_iommu_mode; case VFIO_NOIOMMU_IOMMU: return IS_ENABLED(CONFIG_VFIO_NOIOMMU); diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c index 5d6b8e025bb876..3cc6b439f5f90c 100644 --- a/drivers/irqchip/irq-pic32-evic.c +++ b/drivers/irqchip/irq-pic32-evic.c @@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) of_property_for_each_u32(node, pname, hwirq) { if (i >= ARRAY_SIZE(priv->ext_irqs)) { - pr_warn("More than %d external irq, skip rest\n", + pr_warn("More than %zu external irq, skip rest\n", ARRAY_SIZE(priv->ext_irqs)); break; } diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c index 35c61311e7fd8b..e104010345b187 100644 --- a/drivers/leds/blink/leds-lgm-sso.c +++ b/drivers/leds/blink/leds-lgm-sso.c @@ -806,8 +806,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); - priv->mmap = syscon_node_to_regmap(dev->of_node); - priv->mmap = syscon_node_to_regmap(dev->of_node); if (IS_ERR(priv->mmap)) { dev_err(dev, "Failed to map iomem!\n"); diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 6bdee87f308369..f2ed7f884a5759 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -28,8 +28,6 @@ #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) -static bool mbox_data_ready; - struct mbox_test_device { struct device *dev; void __iomem *tx_mmio; @@ -42,6 +40,7 @@ struct mbox_test_device { spinlock_t lock; struct mutex mutex; wait_queue_head_t waitq; + bool data_ready; struct fasync_struct *async_queue; struct dentry *root_debugfs_dir; }; @@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) unsigned long flags; spin_lock_irqsave(&tdev->lock, flags); - data_ready = mbox_data_ready; + data_ready = tdev->data_ready; spin_unlock_irqrestore(&tdev->lock, flags); return data_ready; @@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, *(touser + l) = '\0'; memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); - mbox_data_ready = false; + tdev->data_ready = false; spin_unlock_irqrestore(&tdev->lock, flags); @@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) message, MBOX_MAX_MSG_LEN); memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); } - mbox_data_ready = true; + tdev->data_ready = true; spin_unlock_irqrestore(&tdev->lock, flags); wake_up_interruptible(&tdev->waitq); @@ -366,6 +365,12 @@ static int mbox_test_probe(struct platform_device *pdev) if (!tdev) return -ENOMEM; + tdev->dev = &pdev->dev; + spin_lock_init(&tdev->lock); + mutex_init(&tdev->mutex); + init_waitqueue_head(&tdev->waitq); + platform_set_drvdata(pdev, tdev); + /* It's okay for MMIO to be NULL */ tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { @@ -395,27 +400,29 @@ static int mbox_test_probe(struct platform_device *pdev) if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) tdev->rx_channel = tdev->tx_channel; - tdev->dev = &pdev->dev; - platform_set_drvdata(pdev, tdev); - - spin_lock_init(&tdev->lock); - mutex_init(&tdev->mutex); - if (tdev->rx_channel) { tdev->rx_buffer = devm_kzalloc(&pdev->dev, MBOX_MAX_MSG_LEN, GFP_KERNEL); - if (!tdev->rx_buffer) - return -ENOMEM; + if (!tdev->rx_buffer) { + ret = -ENOMEM; + goto err_free_chans; + } } ret = mbox_test_add_debugfs(pdev, tdev); if (ret) - return ret; + goto err_free_chans; - init_waitqueue_head(&tdev->waitq); dev_info(&pdev->dev, "Successfully registered\n"); return 0; + +err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); + if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; } static int mbox_test_remove(struct platform_device *pdev) @@ -426,7 +433,7 @@ static int mbox_test_remove(struct platform_device *pdev) if (tdev->tx_channel) mbox_free_channel(tdev->tx_channel); - if (tdev->rx_channel) + if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) mbox_free_channel(tdev->rx_channel); return 0; diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index b4d52b814055b7..39269359e3a64d 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -520,8 +520,7 @@ int mbox_controller_register(struct mbox_controller *mbox) { int i, txdone; - /* Sanity check */ - if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) + if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) return -EINVAL; if (mbox->txdone_irq) diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index acffed750e3edc..74078b90653f30 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) return; \ } while (0) +#define WRITE_LOCK_OR_GOTO(cmd, label) \ + do { \ + if (!cmd_write_lock((cmd))) \ + goto label; \ + } while (0) + #define WRITE_UNLOCK(cmd) \ up_write(&(cmd)->root_lock) @@ -1756,17 +1762,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * return r; } -int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) -{ - int r; - - READ_LOCK(cmd); - r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); - READ_UNLOCK(cmd); - - return r; -} - void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) { WRITE_LOCK_VOID(cmd); @@ -1833,11 +1828,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, CACHE_MAX_CONCURRENT_LOCKS); - WRITE_LOCK(cmd); - if (cmd->fail_io) { - WRITE_UNLOCK(cmd); - goto out; - } + /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ + WRITE_LOCK_OR_GOTO(cmd, out); __destroy_persistent_data_objects(cmd, false); old_bm = cmd->bm; diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h index 57afc704794728..24e4af14fcca49 100644 --- a/drivers/md/dm-cache-metadata.h +++ b/drivers/md/dm-cache-metadata.h @@ -138,11 +138,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); */ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); -/* - * Query method. Are all the blocks in the cache clean? - */ -int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); - int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c index 8bd2ad743d9aef..1566e040f7aac7 100644 --- a/drivers/md/dm-cache-policy-smq.c +++ b/drivers/md/dm-cache-policy-smq.c @@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) { struct smq_policy *mq = to_smq_policy(p); struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); + unsigned long flags; if (!e->allocated) return -ENODATA; + spin_lock_irqsave(&mq->lock, flags); // FIXME: what if this block has pending background work? del_queue(mq, e); h_remove(&mq->table, e); free_entry(&mq->cache_alloc, e); + spin_unlock_irqrestore(&mq->lock, flags); + return 0; } diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 0d002d50329da9..5522f8e9443f2f 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -407,6 +407,12 @@ struct cache { mempool_t migration_pool; struct bio_set bs; + + /* + * Cache_size entries. Set bits indicate blocks mapped beyond the + * target length, which are marked for invalidation. + */ + unsigned long *invalid_bitset; }; struct per_bio_data { @@ -1458,11 +1464,19 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) struct cache *cache = mg->cache; bio_list_init(&bios); - if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) - free_prison_cell(cache, mg->cell); + if (mg->cell) { + if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) + free_prison_cell(cache, mg->cell); + } - if (!success && mg->overwrite_bio) - bio_io_error(mg->overwrite_bio); + if (mg->overwrite_bio) { + // Set generic error if the bio hasn't been issued yet, + // e.g., invalidation or metadata commit failed before bio + // submission. Otherwise preserve the bio's own error status. + if (!success && !mg->overwrite_bio->bi_status) + mg->overwrite_bio->bi_status = BLK_STS_IOERR; + bio_endio(mg->overwrite_bio); + } free_migration(mg); defer_bios(cache, &bios); @@ -1502,6 +1516,24 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) return r; } +static void invalidate_committed(struct work_struct *ws) +{ + struct dm_cache_migration *mg = ws_to_mg(ws); + struct cache *cache = mg->cache; + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + + if (mg->k.input) { + invalidate_complete(mg, false); + return; + } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); + dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); + dm_submit_bio_remap(bio, NULL); +} + static void invalidate_remove(struct work_struct *ws) { int r; @@ -1514,10 +1546,8 @@ static void invalidate_remove(struct work_struct *ws) return; } - init_continuation(&mg->k, invalidate_completed); + init_continuation(&mg->k, invalidate_committed); continue_after_commit(&cache->committer, &mg->k); - remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); - mg->overwrite_bio = NULL; schedule_commit(&cache->committer); } @@ -1535,6 +1565,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); if (r < 0) { free_prison_cell(cache, prealloc); + + /* Defer the bio for retrying the cell lock */ + if (mg->overwrite_bio) { + struct bio *bio = mg->overwrite_bio; + + mg->overwrite_bio = NULL; + defer_bio(cache, bio); + } + invalidate_complete(mg, false); return r; } @@ -1697,6 +1736,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, bio_drop_shared_lock(cache, bio); atomic_inc(&cache->stats.demotion); invalidate_start(cache, cblock, block, bio); + return DM_MAPIO_SUBMITTED; } else remap_to_origin_clear_discard(cache, bio, block); } else { @@ -1926,6 +1966,9 @@ static void __destroy(struct cache *cache) if (cache->discard_bitset) free_bitset(cache->discard_bitset); + if (cache->invalid_bitset) + free_bitset(cache->invalid_bitset); + if (cache->copier) dm_kcopyd_client_destroy(cache->copier); @@ -2469,23 +2512,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) goto bad; } - if (passthrough_mode(cache)) { - bool all_clean; - - r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); - if (r) { - *error = "dm_cache_metadata_all_clean() failed"; - goto bad; - } - - if (!all_clean) { - *error = "Cannot enter passthrough mode unless all blocks are clean"; - r = -EINVAL; - goto bad; - } - + if (passthrough_mode(cache)) policy_allow_migrations(cache->policy, false); - } spin_lock_init(&cache->lock); bio_list_init(&cache->deferred_bios); @@ -2514,6 +2542,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) } clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); + if (!cache->invalid_bitset) { + *error = "could not allocate bitset for invalid blocks"; + goto bad; + } + clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); if (IS_ERR(cache->copier)) { *error = "could not create kcopyd client"; @@ -2804,6 +2839,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, struct cache *cache = context; if (dirty) { + if (passthrough_mode(cache)) { + DMERR("%s: cannot enter passthrough mode unless all blocks are clean", + cache_device_name(cache)); + return -EBUSY; + } + set_bit(from_cblock(cblock), cache->dirty_bitset); atomic_inc(&cache->nr_dirty); } else @@ -2812,6 +2853,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, return policy_load_mapping(cache->policy, oblock, cblock, dirty, hint, hint_valid); } +static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + bool dirty, uint32_t hint, bool hint_valid) +{ + struct cache *cache = context; + + if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { + if (dirty) { + DMERR("%s: unable to shrink origin; cache block %u is dirty", + cache_device_name(cache), from_cblock(cblock)); + return -EFBIG; + } + set_bit(from_cblock(cblock), cache->invalid_bitset); + return 0; + } + + return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); +} + /* * The discard block size in the on disk metadata is not * necessarily the same as we're currently using. So we have to @@ -2966,6 +3025,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) return 0; } +static int truncate_oblocks(struct cache *cache) +{ + uint32_t nr_blocks = from_cblock(cache->cache_size); + uint32_t i; + int r; + + for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { + r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); + if (r) { + DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", + cache_device_name(cache)); + return r; + } + } + + return 0; +} + static int cache_preresume(struct dm_target *ti) { int r = 0; @@ -2990,11 +3067,25 @@ static int cache_preresume(struct dm_target *ti) } if (!cache->loaded_mappings) { + /* + * The fast device could have been resized since the last + * failed preresume attempt. To be safe we start by a blank + * bitset for cache blocks. + */ + clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); + r = dm_cache_load_mappings(cache->cmd, cache->policy, - load_mapping, cache); + load_filtered_mapping, cache); if (r) { DMERR("%s: could not load cache mappings", cache_device_name(cache)); - metadata_operation_failed(cache, "dm_cache_load_mappings", r); + if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } + + r = truncate_oblocks(cache); + if (r) { + metadata_operation_failed(cache, "dm_cache_remove_mapping", r); return r; } @@ -3460,7 +3551,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) static struct target_type cache_target = { .name = "cache", - .version = {2, 2, 0}, + .version = {2, 3, 0}, .module = THIS_MODULE, .ctr = cache_ctr, .dtr = cache_dtr, diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c index b37bbe76250034..423269cbdd2bbb 100644 --- a/drivers/md/dm-init.c +++ b/drivers/md/dm-init.c @@ -303,8 +303,10 @@ static int __init dm_init_init(void) } } - if (waitfor[0]) + if (waitfor[0]) { + wait_for_device_probe(); DMINFO("all devices available"); + } list_for_each_entry(dev, &devices, list) { if (dm_early_create(&dev->dmi, dev->table, diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index e215478bcee048..94d3f13e673e98 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, struct log_c *lc; uint32_t region_size; - unsigned int region_count; + sector_t region_count; size_t bitset_size, buf_size; int r; char dummy; @@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, } region_count = dm_sector_div_up(ti->len, region_size); + if (region_count > UINT_MAX) { + DMWARN("region count exceeds limit of %u", UINT_MAX); + return -EINVAL; + } lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c index 111be77eca1caf..f4a9f130e3cf67 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -1456,7 +1456,7 @@ int mxc_isi_video_register(struct mxc_isi_pipe *pipe, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mxc_isi_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; + q->min_buffers_needed = 0; q->lock = &video->lock; q->dev = pipe->isi->dev; diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 00ed2b6a0d1b27..ca2714b0a521ac 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) dll_change = DLL_CHANGE_NONE; - else if (timing->emc_mode_1 & 0x1) + else if (!(timing->emc_mode_1 & 0x1)) dll_change = DLL_CHANGE_ON; else dll_change = DLL_CHANGE_OFF; diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index 9eae25c57ec6ec..b5cf2df6b1933b 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); emc_dbg = readl_relaxed(emc->regs + EMC_DBG); - if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) + if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) dll_change = DLL_CHANGE_NONE; - else if (timing->emc_mode_1 & 0x1) + else if (!(timing->emc_mode_1 & 0x1)) dll_change = DLL_CHANGE_ON; else dll_change = DLL_CHANGE_OFF; - emc->dll_on = !!(timing->emc_mode_1 & 0x1); + emc->dll_on = !(timing->emc_mode_1 & 0x1); if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) emc->zcal_long = true; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1000572761a84a..ddc90cbb7be52b 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) return -E2BIG; - cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); + cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); if (!cell.name) return -ENOMEM; diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c index 9d3b4bf84a1ad7..1c34b4ef77ea3f 100644 --- a/drivers/mtd/maps/physmap-gemini.c +++ b/drivers/mtd/maps/physmap-gemini.c @@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, dev_err(dev, "no enabled pin control state\n"); gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); - if (IS_ERR(gf->enabled_state)) { + if (IS_ERR(gf->disabled_state)) { dev_err(dev, "no disabled pin control state\n"); } else { ret = pinctrl_select_state(gf->p, gf->disabled_state); diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 4469618ee60331..8d31cb0133acc4 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -886,9 +886,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, if (len <= 0) return; - if (!cur_off || *cur_off != offset) - nand_change_read_column_op(nand, mtd->writesize, NULL, 0, - false); + if (!cur_off || *cur_off != (offset + mtd->writesize)) + nand_change_read_column_op(nand, mtd->writesize + offset, + NULL, 0, false); if (!randomize) sunxi_nfc_read_buf(nand, oob + offset, len); diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c index 3cf75b56d5a2e7..c18fa1b3e32764 100644 --- a/drivers/mtd/parsers/ofpart_core.c +++ b/drivers/mtd/parsers/ofpart_core.c @@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, dedicated = false; } } else { /* Partition */ - ofpart_node = mtd_node; + ofpart_node = of_node_get(mtd_node); } of_id = of_match_node(parse_ofpart_match_table, ofpart_node); @@ -191,11 +191,11 @@ static int parse_fixed_partitions(struct mtd_info *master, ofpart_fail: pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", master->name, pp, mtd_node); + of_node_put(pp); ret = -EINVAL; ofpart_none: if (dedicated) of_node_put(ofpart_node); - of_node_put(pp); kfree(parts); return ret; } diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 6e135581ec62a7..6f8a9c6253205b 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2477,7 +2477,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, /* convert the dummy cycles to the number of bytes */ op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * op.dummy.buswidth / 8; - if (spi_nor_protocol_is_dtr(nor->read_proto)) + if (spi_nor_protocol_is_dtr(read->proto)) op.dummy.nbytes *= 2; return spi_nor_spimem_check_op(nor, &op); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 9217379b9cfefd..398383ba0d8d63 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -416,7 +416,11 @@ struct spi_nor_flash_parameter { * flash parameters when information provided by the flash_info * table is incomplete or wrong. * @post_bfpt: called after the BFPT table has been parsed - * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. + * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs * that do not support RDSFDP). Typically used to tweak various * parameters that could not be extracted by other means (i.e. * when information provided by the SFDP/flash_info tables are @@ -433,6 +437,8 @@ struct spi_nor_fixups { int (*post_bfpt)(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); + void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); + void (*smpt_map_id)(const struct spi_nor *nor, u8 *map_id); int (*post_sfdp)(struct spi_nor *nor); int (*late_init)(struct spi_nor *nor); }; diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index b3b11dfed7893d..dcf88ad2a00b23 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -674,6 +674,17 @@ static u8 spi_nor_smpt_addr_nbytes(const struct spi_nor *nor, const u32 settings } } +static void spi_nor_smpt_read_dummy_fixups(const struct spi_nor *nor, + u8 *read_dummy) +{ + if (nor->manufacturer && nor->manufacturer->fixups && + nor->manufacturer->fixups->smpt_read_dummy) + nor->manufacturer->fixups->smpt_read_dummy(nor, read_dummy); + + if (nor->info->fixups && nor->info->fixups->smpt_read_dummy) + nor->info->fixups->smpt_read_dummy(nor, read_dummy); +} + /** * spi_nor_smpt_read_dummy() - return the configuration detection command read * latency, in clock cycles. @@ -686,11 +697,24 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) { u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); - if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) - return nor->read_dummy; + if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) { + read_dummy = nor->read_dummy; + spi_nor_smpt_read_dummy_fixups(nor, &read_dummy); + } + return read_dummy; } +static void spi_nor_smpt_map_id_fixups(const struct spi_nor *nor, u8 *map_id) +{ + if (nor->manufacturer && nor->manufacturer->fixups && + nor->manufacturer->fixups->smpt_map_id) + nor->manufacturer->fixups->smpt_map_id(nor, map_id); + + if (nor->info->fixups && nor->info->fixups->smpt_map_id) + nor->info->fixups->smpt_map_id(nor, map_id); +} + /** * spi_nor_get_map_in_use() - get the configuration map in use * @nor: pointer to a 'struct spi_nor' @@ -744,6 +768,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, map_id = map_id << 1 | !!(*buf & read_data_mask); } + spi_nor_smpt_map_id_fixups(nor, &map_id); + /* * If command descriptors are provided, they always precede map * descriptors in the table. There is no need to start the iteration diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c index a186d1fde8694a..4f34283603587d 100644 --- a/drivers/mtd/spi-nor/swp.c +++ b/drivers/mtd/spi-nor/swp.c @@ -27,8 +27,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) { if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) return SR_TB_BIT6; - else + else if (nor->flags & SNOR_F_HAS_SR_TB) return SR_TB_BIT5; + else + return 0; } static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index cfbc0240126ef0..b181c03368153e 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -325,8 +325,10 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, if (!sock) return -ESHUTDOWN; - rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info, - IPPROTO_UDP, use_cache); + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key, + 0, 0, key->tos, + use_cache ? + (struct dst_cache *)&info->dst_cache : NULL); if (IS_ERR(rt)) return PTR_ERR(rt); @@ -391,8 +393,8 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, if (!sock) return -ESHUTDOWN; - dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info, - IPPROTO_UDP, use_cache); + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, &saddr, info, + IPPROTO_UDP, use_cache); if (IS_ERR(dst)) return PTR_ERR(dst); @@ -505,8 +507,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, struct rtable *rt; __be32 saddr; - rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, - info, IPPROTO_UDP, use_cache); + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, + &info->key, 0, 0, info->key.tos, + use_cache ? &info->dst_cache : NULL); if (IS_ERR(rt)) return PTR_ERR(rt); @@ -517,9 +520,12 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, struct in6_addr saddr; struct socket *sock = rcu_dereference(bareudp->sock); - dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, - &saddr, info, IPPROTO_UDP, - use_cache); + if (!sock) + return -ESHUTDOWN; + + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + &saddr, info, IPPROTO_UDP, + use_cache); if (IS_ERR(dst)) return PTR_ERR(dst); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index d02a91cefec89b..d1da96f3efd406 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -82,10 +82,6 @@ enum ad_link_speed_type { #define MAC_ADDRESS_EQUAL(A, B) \ ether_addr_equal_64bits((const u8 *)A, (const u8 *)B) -static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { - 0, 0, 0, 0, 0, 0 -}; - static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; @@ -440,6 +436,7 @@ static void __ad_actor_update_port(struct port *port) port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; port->actor_system_priority = BOND_AD_INFO(bond).system.sys_priority; + port->actor_port_priority = SLAVE_AD_INFO(port->slave)->port_priority; } /* Conversions */ @@ -994,6 +991,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) static void ad_mux_machine(struct port *port, bool *update_slave_arr) { struct bonding *bond = __get_bond_by_port(port); + struct aggregator *aggregator; mux_states_t last_state; /* keep current State Machine state to compare later if it was @@ -1001,6 +999,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) */ last_state = port->sm_mux_state; + aggregator = rcu_dereference(port->aggregator); if (port->sm_vars & AD_PORT_BEGIN) { port->sm_mux_state = AD_MUX_DETACHED; } else { @@ -1020,7 +1019,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) * cycle to update ready variable, we check * READY_N and update READY here */ - __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); port->sm_mux_state = AD_MUX_DETACHED; break; } @@ -1035,7 +1034,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) * update ready variable, we check READY_N and update * READY here */ - __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); /* if the wait_while_timer expired, and the port is * in READY state, move to ATTACHED state @@ -1051,7 +1050,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { - if (port->aggregator->is_active) { + if (aggregator->is_active) { int state = AD_MUX_COLLECTING_DISTRIBUTING; if (!bond->params.coupled_control) @@ -1067,9 +1066,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) * cycle to update ready variable, we check * READY_N and update READY here */ - __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); port->sm_mux_state = AD_MUX_DETACHED; - } else if (port->aggregator->is_active) { + } else if (aggregator->is_active) { port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION; } @@ -1080,7 +1079,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) * sure that a collecting distributing * port in an active aggregator is enabled */ - if (port->aggregator->is_active && + if (aggregator->is_active && !__port_is_collecting_distributing(port)) { __enable_port(port); *update_slave_arr = true; @@ -1099,7 +1098,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) */ struct slave *slave = port->slave; - if (port->aggregator->is_active && + if (aggregator->is_active && bond_is_slave_rx_disabled(slave)) { ad_enable_collecting(port); *update_slave_arr = true; @@ -1119,8 +1118,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) * sure that a collecting distributing * port in an active aggregator is enabled */ - if (port->aggregator && - port->aggregator->is_active && + if (aggregator && + aggregator->is_active && !__port_is_collecting_distributing(port)) { __enable_port(port); *update_slave_arr = true; @@ -1152,7 +1151,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); break; case AD_MUX_ATTACHED: - if (port->aggregator->is_active) + if (aggregator->is_active) port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION; else @@ -1525,9 +1524,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) bond = __get_bond_by_port(port); /* if the port is connected to other aggregator, detach it */ - if (port->aggregator) { + temp_aggregator = rcu_dereference(port->aggregator); + if (temp_aggregator) { /* detach the port from its former aggregator */ - temp_aggregator = port->aggregator; for (curr_port = temp_aggregator->lag_ports; curr_port; last_port = curr_port, curr_port = curr_port->next_port_in_aggregator) { @@ -1550,7 +1549,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) /* clear the port's relations to this * aggregator */ - port->aggregator = NULL; + RCU_INIT_POINTER(port->aggregator, NULL); port->next_port_in_aggregator = NULL; port->actor_port_aggregator_identifier = 0; @@ -1573,7 +1572,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) port->slave->bond->dev->name, port->slave->dev->name, port->actor_port_number, - port->aggregator->aggregator_identifier); + temp_aggregator->aggregator_identifier); } } /* search on all aggregators for a suitable aggregator for this port */ @@ -1592,20 +1591,20 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) (aggregator->partner_system_priority == port->partner_oper.system_priority) && (aggregator->partner_oper_aggregator_key == port->partner_oper.key) ) && - ((!MAC_ADDRESS_EQUAL(&(port->partner_oper.system), &(null_mac_addr)) && /* partner answers */ + ((__agg_has_partner(aggregator) && /* partner answers */ !aggregator->is_individual) /* but is not individual OR */ ) ) { /* attach to the founded aggregator */ - port->aggregator = aggregator; + rcu_assign_pointer(port->aggregator, aggregator); port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + aggregator->aggregator_identifier; port->next_port_in_aggregator = aggregator->lag_ports; - port->aggregator->num_of_ports++; + aggregator->num_of_ports++; aggregator->lag_ports = port; slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier); /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; @@ -1620,39 +1619,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) if (!found) { if (free_aggregator) { /* assign port a new aggregator */ - port->aggregator = free_aggregator; port->actor_port_aggregator_identifier = - port->aggregator->aggregator_identifier; + free_aggregator->aggregator_identifier; /* update the new aggregator's parameters * if port was responsed from the end-user */ if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) /* if port is full duplex */ - port->aggregator->is_individual = false; + free_aggregator->is_individual = false; else - port->aggregator->is_individual = true; + free_aggregator->is_individual = true; - port->aggregator->actor_admin_aggregator_key = + free_aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; - port->aggregator->actor_oper_aggregator_key = + free_aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system = + free_aggregator->partner_system = port->partner_oper.system; - port->aggregator->partner_system_priority = + free_aggregator->partner_system_priority = port->partner_oper.system_priority; - port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; - port->aggregator->receive_state = 1; - port->aggregator->transmit_state = 1; - port->aggregator->lag_ports = port; - port->aggregator->num_of_ports++; + free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; + free_aggregator->receive_state = 1; + free_aggregator->transmit_state = 1; + free_aggregator->lag_ports = port; + free_aggregator->num_of_ports++; + + rcu_assign_pointer(port->aggregator, free_aggregator); /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + free_aggregator->aggregator_identifier); } else { slave_err(bond->dev, port->slave->dev, "Port %d did not find a suitable aggregator\n", @@ -1664,13 +1664,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) * in all aggregator's ports, else set ready=FALSE in all * aggregator's ports */ - __set_agg_ports_ready(port->aggregator, - __agg_ports_are_ready(port->aggregator)); + aggregator = rcu_dereference(port->aggregator); + __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); - aggregator = __get_first_agg(port); - ad_agg_selection_logic(aggregator, update_slave_arr); + ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); - if (!port->aggregator->is_active) + if (!aggregator->is_active) port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; } @@ -2024,13 +2023,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond */ static void ad_enable_collecting(struct port *port) { - if (port->aggregator->is_active) { + struct aggregator *aggregator = rcu_dereference(port->aggregator); + + if (aggregator->is_active) { struct slave *slave = port->slave; slave_dbg(slave->bond->dev, slave->dev, "Enabling collecting on port %d (LAG %d)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier); __enable_collecting_port(port); } } @@ -2042,13 +2043,13 @@ static void ad_enable_collecting(struct port *port) */ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) { - if (port->aggregator && - !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, - &(null_mac_addr))) { + struct aggregator *aggregator = rcu_dereference(port->aggregator); + + if (aggregator && __agg_has_partner(aggregator)) { slave_dbg(port->slave->bond->dev, port->slave->dev, "Disabling distributing on port %d (LAG %d)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier); __disable_distributing_port(port); /* Slave array needs an update */ *update_slave_arr = true; @@ -2065,11 +2066,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) static void ad_enable_collecting_distributing(struct port *port, bool *update_slave_arr) { - if (port->aggregator->is_active) { + struct aggregator *aggregator = rcu_dereference(port->aggregator); + + if (aggregator->is_active) { slave_dbg(port->slave->bond->dev, port->slave->dev, "Enabling port %d (LAG %d)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier); __enable_port(port); /* Slave array needs update */ *update_slave_arr = true; @@ -2084,13 +2087,13 @@ static void ad_enable_collecting_distributing(struct port *port, static void ad_disable_collecting_distributing(struct port *port, bool *update_slave_arr) { - if (port->aggregator && - !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), - &(null_mac_addr))) { + struct aggregator *aggregator = rcu_dereference(port->aggregator); + + if (aggregator && __agg_has_partner(aggregator)) { slave_dbg(port->slave->bond->dev, port->slave->dev, "Disabling port %d (LAG %d)\n", port->actor_port_number, - port->aggregator->aggregator_identifier); + aggregator->aggregator_identifier); __disable_port(port); /* Slave array needs an update */ *update_slave_arr = true; @@ -2203,6 +2206,9 @@ void bond_3ad_bind_slave(struct slave *slave) ad_initialize_port(port, &bond->params); + /* Port priority is initialized. Update it to slave's ad info */ + SLAVE_AD_INFO(slave)->port_priority = port->actor_port_priority; + port->slave = slave; port->actor_port_number = SLAVE_AD_INFO(slave)->id; /* key is determined according to the link speed, duplex and @@ -2327,7 +2333,7 @@ void bond_3ad_unbind_slave(struct slave *slave) */ for (temp_port = aggregator->lag_ports; temp_port; temp_port = temp_port->next_port_in_aggregator) { - temp_port->aggregator = new_aggregator; + rcu_assign_pointer(temp_port->aggregator, new_aggregator); temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; } @@ -2796,15 +2802,16 @@ out: int __bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) { - struct aggregator *aggregator = NULL; + struct aggregator *aggregator = NULL, *tmp; struct list_head *iter; struct slave *slave; struct port *port; bond_for_each_slave_rcu(bond, slave, iter) { port = &(SLAVE_AD_INFO(slave)->port); - if (port->aggregator && port->aggregator->is_active) { - aggregator = port->aggregator; + tmp = rcu_dereference(port->aggregator); + if (tmp && tmp->is_active) { + aggregator = tmp; break; } } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8d481a6495e895..029a7f001dd8a0 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -211,6 +211,8 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(0); unsigned int bond_net_id __read_mostly; +DEFINE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); + static const struct flow_dissector_key flow_keys_bonding_keys[] = { { .key_id = FLOW_DISSECTOR_KEY_CONTROL, @@ -1392,7 +1394,7 @@ static void bond_poll_controller(struct net_device *bond_dev) if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct aggregator *agg = - SLAVE_AD_INFO(slave)->port.aggregator; + rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); if (agg && agg->aggregator_identifier != ad_info.aggregator_id) @@ -4397,6 +4399,9 @@ static int bond_open(struct net_device *bond_dev) bond_for_each_slave(bond, slave, iter) dev_mc_add(slave->dev, lacpdu_mcast_addr); + + if (bond->params.broadcast_neighbor) + static_branch_inc(&bond_bcast_neigh_enabled); } if (bond_mode_can_use_xmit_hash(bond)) @@ -4420,6 +4425,10 @@ static int bond_close(struct net_device *bond_dev) if (bond_is_lb(bond)) bond_alb_deinitialize(bond); + if (BOND_MODE(bond) == BOND_MODE_8023AD && + bond->params.broadcast_neighbor) + static_branch_dec(&bond_bcast_neigh_enabled); + if (bond_uses_primary(bond)) { rcu_read_lock(); slave = rcu_dereference(bond->curr_active_slave); @@ -5187,15 +5196,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) spin_unlock_bh(&bond->mode_lock); agg_id = ad_info.aggregator_id; } + rcu_read_lock(); bond_for_each_slave(bond, slave, iter) { if (skipslave == slave) continue; all_slaves->arr[all_slaves->count++] = slave; if (BOND_MODE(bond) == BOND_MODE_8023AD) { - struct aggregator *agg; + const struct aggregator *agg; - agg = SLAVE_AD_INFO(slave)->port.aggregator; + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); if (!agg || agg->aggregator_identifier != agg_id) continue; } @@ -5207,6 +5217,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) usable_slaves->arr[usable_slaves->count++] = slave; } + rcu_read_unlock(); bond_set_slave_arr(bond, usable_slaves, all_slaves); return ret; @@ -5256,6 +5267,37 @@ static struct slave *bond_xdp_xmit_3ad_xor_slave_get(struct bonding *bond, return slaves->arr[hash % count]; } +static bool bond_should_broadcast_neighbor(struct sk_buff *skb, + struct net_device *dev) +{ + struct bonding *bond = netdev_priv(dev); + struct { + struct ipv6hdr ip6; + struct icmp6hdr icmp6; + } *combined, _combined; + + if (!static_branch_unlikely(&bond_bcast_neigh_enabled)) + return false; + + if (!bond->params.broadcast_neighbor) + return false; + + if (skb->protocol == htons(ETH_P_ARP)) + return true; + + if (skb->protocol == htons(ETH_P_IPV6)) { + combined = skb_header_pointer(skb, skb_mac_header_len(skb), + sizeof(_combined), + &_combined); + if (combined && combined->ip6.nexthdr == NEXTHDR_ICMP && + (combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION || + combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) + return true; + } + + return false; +} + /* Use this Xmit function for 3AD as well as XOR modes. The current * usable slave array is formed in the control path. The xmit function * just calculates hash and sends the packet out. @@ -5275,17 +5317,27 @@ static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb, return bond_tx_drop(dev, skb); } -/* in broadcast mode, we send everything to all usable interfaces. */ +/* in broadcast mode, we send everything to all or usable slave interfaces. + * under rcu_read_lock when this function is called. + */ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, - struct net_device *bond_dev) + struct net_device *bond_dev, + bool all_slaves) { struct bonding *bond = netdev_priv(bond_dev); - struct slave *slave = NULL; - struct list_head *iter; + struct bond_up_slave *slaves; bool xmit_suc = false; bool skb_used = false; + int slaves_count, i; - bond_for_each_slave_rcu(bond, slave, iter) { + if (all_slaves) + slaves = rcu_dereference(bond->all_slaves); + else + slaves = rcu_dereference(bond->usable_slaves); + + slaves_count = slaves ? READ_ONCE(slaves->count) : 0; + for (i = 0; i < slaves_count; i++) { + struct slave *slave = slaves->arr[i]; struct sk_buff *skb2; if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) @@ -5523,10 +5575,13 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev case BOND_MODE_ACTIVEBACKUP: return bond_xmit_activebackup(skb, dev); case BOND_MODE_8023AD: + if (bond_should_broadcast_neighbor(skb, dev)) + return bond_xmit_broadcast(skb, dev, false); + fallthrough; case BOND_MODE_XOR: return bond_3ad_xor_xmit(skb, dev); case BOND_MODE_BROADCAST: - return bond_xmit_broadcast(skb, dev); + return bond_xmit_broadcast(skb, dev, true); case BOND_MODE_ALB: return bond_alb_xmit(skb, dev); case BOND_MODE_TLB: @@ -6426,6 +6481,7 @@ static int __init bond_check_params(struct bond_params *params) eth_zero_addr(params->ad_actor_system); params->ad_user_port_key = ad_user_port_key; params->coupled_control = 1; + params->broadcast_neighbor = 0; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index aebc814ad495d9..0eaf4b0e06ffb2 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -28,6 +28,9 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ 0; } @@ -62,24 +65,39 @@ static int bond_fill_slave_info(struct sk_buff *skb, const struct port *ad_port; ad_port = &SLAVE_AD_INFO(slave)->port; - agg = SLAVE_AD_INFO(slave)->port.aggregator; + rcu_read_lock(); + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); if (agg) { if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, agg->aggregator_identifier)) - goto nla_put_failure; + goto nla_put_failure_rcu; if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, ad_port->actor_oper_port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu; if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, ad_port->partner_oper.port_state)) - goto nla_put_failure; + goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + ad_port->sm_churn_actor_state)) + goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + ad_port->sm_churn_partner_state)) + goto nla_put_failure_rcu; } + rcu_read_unlock(); + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + SLAVE_AD_INFO(slave)->port_priority)) + goto nla_put_failure; } return 0; +nla_put_failure_rcu: + rcu_read_unlock(); nla_put_failure: return -EMSGSIZE; } @@ -128,6 +146,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, + [IFLA_BOND_SLAVE_ACTOR_PORT_PRIO] = { .type = NLA_U16 }, }; static int bond_validate(struct nlattr *tb[], struct nlattr *data[], @@ -178,6 +197,16 @@ static int bond_slave_changelink(struct net_device *bond_dev, return err; } + if (data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]) { + u16 ad_prio = nla_get_u16(data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]); + + bond_opt_slave_initval(&newval, &slave_dev, ad_prio); + err = __bond_opt_set(bond, BOND_OPT_ACTOR_PORT_PRIO, &newval, + data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO], extack); + if (err) + return err; + } + return 0; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index b823425ad7f69c..5b6c01b31f9850 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -79,6 +79,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_actor_port_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); static int bond_option_ad_actor_system_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_ad_user_port_key_set(struct bonding *bond, @@ -87,6 +89,8 @@ static int bond_option_missed_max_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_coupled_control_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_broadcast_neigh_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, @@ -240,6 +244,12 @@ static const struct bond_opt_value bond_coupled_control_tbl[] = { { NULL, -1, 0}, }; +static const struct bond_opt_value bond_broadcast_neigh_tbl[] = { + { "off", 0, BOND_VALFLAG_DEFAULT}, + { "on", 1, 0}, + { NULL, -1, 0} +}; + static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -476,6 +486,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_ad_actor_sys_prio_tbl, .set = bond_option_ad_actor_sys_prio_set, }, + [BOND_OPT_ACTOR_PORT_PRIO] = { + .id = BOND_OPT_ACTOR_PORT_PRIO, + .name = "actor_port_prio", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_RAWVAL, + .set = bond_option_actor_port_prio_set, + }, [BOND_OPT_AD_ACTOR_SYSTEM] = { .id = BOND_OPT_AD_ACTOR_SYSTEM, .name = "ad_actor_system", @@ -513,6 +530,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .flags = BOND_OPTFLAG_IFDOWN, .values = bond_coupled_control_tbl, .set = bond_option_coupled_control_set, + }, + [BOND_OPT_BROADCAST_NEIGH] = { + .id = BOND_OPT_BROADCAST_NEIGH, + .name = "broadcast_neighbor", + .desc = "Broadcast neighbor packets to all active slaves", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .values = bond_broadcast_neigh_tbl, + .set = bond_option_broadcast_neigh_set, } }; @@ -894,6 +919,13 @@ static int bond_option_mode_set(struct bonding *bond, bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; bond->params.mode = newval->value; + /* When changing mode, the bond device is down, we may reduce + * the bond_bcast_neigh_enabled in bond_close() if broadcast_neighbor + * enabled in 8023ad mode. Therefore, only clear broadcast_neighbor + * to 0. + */ + bond->params.broadcast_neighbor = 0; + if (bond->dev->reg_state == NETREG_REGISTERED) { bool update = false; @@ -1796,6 +1828,26 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, return 0; } +static int bond_option_actor_port_prio_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + struct slave *slave; + + slave = bond_slave_get_rtnl(newval->slave_dev); + if (!slave) { + netdev_dbg(bond->dev, "%s called on NULL slave\n", __func__); + return -ENODEV; + } + + netdev_dbg(newval->slave_dev, "Setting actor_port_prio to %llu\n", + newval->value); + + SLAVE_AD_INFO(slave)->port_priority = newval->value; + bond_3ad_update_ad_actor_settings(bond); + + return 0; +} + static int bond_option_ad_actor_system_set(struct bonding *bond, const struct bond_opt_value *newval) { @@ -1843,3 +1895,22 @@ static int bond_option_coupled_control_set(struct bonding *bond, bond->params.coupled_control = newval->value; return 0; } + +static int bond_option_broadcast_neigh_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + if (bond->params.broadcast_neighbor == newval->value) + return 0; + + bond->params.broadcast_neighbor = newval->value; + if (bond->dev->flags & IFF_UP) { + if (bond->params.broadcast_neighbor) + static_branch_inc(&bond_bcast_neigh_enabled); + else + static_branch_dec(&bond_bcast_neigh_enabled); + } + + netdev_dbg(bond->dev, "Setting broadcast_neighbor to %s (%llu)\n", + newval->string, newval->value); + return 0; +} diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 43be458422b3f9..bc919814eb5048 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) } } +/* Note: runs under rcu_read_lock() */ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { @@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq, if (BOND_MODE(bond) == BOND_MODE_8023AD) { const struct port *port = &SLAVE_AD_INFO(slave)->port; - const struct aggregator *agg = port->aggregator; + const struct aggregator *agg = rcu_dereference(port->aggregator); if (agg) { seq_printf(seq, "Aggregator ID: %d\n", diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c index 313866f2c0e49a..75df3e21b804d3 100644 --- a/drivers/net/bonding/bond_sysfs_slave.c +++ b/drivers/net/bonding/bond_sysfs_slave.c @@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) const struct aggregator *agg; if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { - agg = SLAVE_AD_INFO(slave)->port.aggregator; - if (agg) - return sysfs_emit(buf, "%d\n", - agg->aggregator_identifier); + rcu_read_lock(); + agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (agg) { + ssize_t res = sysfs_emit(buf, "%d\n", + agg->aggregator_identifier); + rcu_read_unlock(); + return res; + } + rcu_read_unlock(); } return sysfs_emit(buf, "N/A\n"); @@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { ad_port = &SLAVE_AD_INFO(slave)->port; - if (ad_port->aggregator) + if (rcu_access_pointer(ad_port->aggregator)) return sysfs_emit(buf, "%u\n", ad_port->actor_oper_port_state); } @@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { ad_port = &SLAVE_AD_INFO(slave)->port; - if (ad_port->aggregator) + if (rcu_access_pointer(ad_port->aggregator)) return sysfs_emit(buf, "%u\n", ad_port->partner_oper.port_state); } diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index 9d59d938078252..625d1d4d17a20c 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -213,7 +213,7 @@ (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ 0x0) #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ - (0xF << (((_extint) % 2))) + (0xF << (((_extint) % 2) * 4)) #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ (((_extint) % 2) * 4) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index baa5f8cc31f219..775cbbc1aa4212 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -374,7 +374,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev) pci_disable_device(pdev); if (system_state == SYSTEM_POWER_OFF) { - pci_wake_from_d3(pdev, false); + pci_wake_from_d3(pdev, self->aq_hw->aq_nic_cfg->wol); pci_set_power_state(pdev, PCI_D3hot); } } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 79d096a371ae77..d1f5ae56fa417d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -41,15 +41,13 @@ #include "bcmgenet.h" -/* Maximum number of hardware queues, downsized if needed */ -#define GENET_MAX_MQ_CNT 4 - /* Default highest priority queue for multi queue support */ -#define GENET_Q0_PRIORITY 0 +#define GENET_Q1_PRIORITY 0 +#define GENET_Q0_PRIORITY 1 -#define GENET_Q16_RX_BD_CNT \ +#define GENET_Q0_RX_BD_CNT \ (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) -#define GENET_Q16_TX_BD_CNT \ +#define GENET_Q0_TX_BD_CNT \ (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q) #define RX_BUF_LENGTH 2048 @@ -104,7 +102,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, * the platform is explicitly configured for 64-bits/LPAE. */ #ifdef CONFIG_PHYS_ADDR_T_64BIT - if (priv->hw_params->flags & GENET_HAS_40BITS) + if (bcmgenet_has_40bits(priv)) bcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); #endif } @@ -585,7 +583,7 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, u16 mask_16; size_t size; - f = fs->location; + f = fs->location + 1; if (fs->flow_type & FLOW_MAC_EXT) { bcmgenet_hfb_insert_data(priv, f, 0, &fs->h_ext.h_dest, &fs->m_ext.h_dest, @@ -667,19 +665,14 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, } bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); - if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { - /* Ring 0 flows can be handled by the default Descriptor Ring - * We'll map them to ring 0, but don't enable the filter - */ + if (fs->ring_cookie == RX_CLS_FLOW_WAKE) bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); - rule->state = BCMGENET_RXNFC_STATE_DISABLED; - } else { + else /* Other Rx rings are direct mapped here */ bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, fs->ring_cookie); - bcmgenet_hfb_enable_filter(priv, f); - rule->state = BCMGENET_RXNFC_STATE_ENABLED; - } + bcmgenet_hfb_enable_filter(priv, f); + rule->state = BCMGENET_RXNFC_STATE_ENABLED; } /* bcmgenet_hfb_clear @@ -715,6 +708,10 @@ static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) bcmgenet_hfb_clear_filter(priv, i); + + /* Enable filter 0 to send default flow to ring 0 */ + bcmgenet_hfb_set_filter_length(priv, 0, 4); + bcmgenet_hfb_enable_filter(priv, 0); } static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) @@ -819,20 +816,16 @@ static int bcmgenet_get_coalesce(struct net_device *dev, unsigned int i; ec->tx_max_coalesced_frames = - bcmgenet_tdma_ring_readl(priv, DESC_INDEX, - DMA_MBUF_DONE_THRESH); + bcmgenet_tdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); ec->rx_max_coalesced_frames = - bcmgenet_rdma_ring_readl(priv, DESC_INDEX, - DMA_MBUF_DONE_THRESH); + bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); ec->rx_coalesce_usecs = - bcmgenet_rdma_readl(priv, DMA_RING16_TIMEOUT) * 8192 / 1000; + bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000; - for (i = 0; i < priv->hw_params->rx_queues; i++) { + for (i = 0; i <= priv->hw_params->rx_queues; i++) { ring = &priv->rx_rings[i]; ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; } - ring = &priv->rx_rings[DESC_INDEX]; - ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; return 0; } @@ -902,17 +895,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev, /* Program all TX queues with the same values, as there is no * ethtool knob to do coalescing on a per-queue basis */ - for (i = 0; i < priv->hw_params->tx_queues; i++) + for (i = 0; i <= priv->hw_params->tx_queues; i++) bcmgenet_tdma_ring_writel(priv, i, ec->tx_max_coalesced_frames, DMA_MBUF_DONE_THRESH); - bcmgenet_tdma_ring_writel(priv, DESC_INDEX, - ec->tx_max_coalesced_frames, - DMA_MBUF_DONE_THRESH); - for (i = 0; i < priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec); - bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[DESC_INDEX], ec); return 0; } @@ -961,12 +950,13 @@ static int bcmgenet_set_pauseparam(struct net_device *dev, /* standard ethtool support functions. */ enum bcmgenet_stat_type { - BCMGENET_STAT_NETDEV = -1, + BCMGENET_STAT_RTNL = -1, BCMGENET_STAT_MIB_RX, BCMGENET_STAT_MIB_TX, BCMGENET_STAT_RUNT, BCMGENET_STAT_MISC, BCMGENET_STAT_SOFT, + BCMGENET_STAT_SOFT64, }; struct bcmgenet_stats { @@ -976,13 +966,15 @@ struct bcmgenet_stats { enum bcmgenet_stat_type type; /* reg offset from UMAC base for misc counters */ u16 reg_offset; + /* sync for u64 stats counters */ + int syncp_offset; }; -#define STAT_NETDEV(m) { \ +#define STAT_RTNL(m) { \ .stat_string = __stringify(m), \ - .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ - .stat_offset = offsetof(struct net_device_stats, m), \ - .type = BCMGENET_STAT_NETDEV, \ + .stat_sizeof = sizeof(((struct rtnl_link_stats64 *)0)->m), \ + .stat_offset = offsetof(struct rtnl_link_stats64, m), \ + .type = BCMGENET_STAT_RTNL, \ } #define STAT_GENET_MIB(str, m, _type) { \ @@ -992,6 +984,14 @@ struct bcmgenet_stats { .type = _type, \ } +#define STAT_GENET_SOFT_MIB64(str, s, m) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->s.m), \ + .stat_offset = offsetof(struct bcmgenet_priv, s.m), \ + .type = BCMGENET_STAT_SOFT64, \ + .syncp_offset = offsetof(struct bcmgenet_priv, s.syncp), \ +} + #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX) #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX) #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT) @@ -1006,18 +1006,18 @@ struct bcmgenet_stats { } #define STAT_GENET_Q(num) \ - STAT_GENET_SOFT_MIB("txq" __stringify(num) "_packets", \ - tx_rings[num].packets), \ - STAT_GENET_SOFT_MIB("txq" __stringify(num) "_bytes", \ - tx_rings[num].bytes), \ - STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_bytes", \ - rx_rings[num].bytes), \ - STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_packets", \ - rx_rings[num].packets), \ - STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_errors", \ - rx_rings[num].errors), \ - STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_dropped", \ - rx_rings[num].dropped) + STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_packets", \ + tx_rings[num].stats64, packets), \ + STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_bytes", \ + tx_rings[num].stats64, bytes), \ + STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_bytes", \ + rx_rings[num].stats64, bytes), \ + STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_packets", \ + rx_rings[num].stats64, packets), \ + STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_errors", \ + rx_rings[num].stats64, errors), \ + STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_dropped", \ + rx_rings[num].stats64, dropped) /* There is a 0xC gap between the end of RX and beginning of TX stats and then * between the end of TX stats and the beginning of the RX RUNT @@ -1029,15 +1029,15 @@ struct bcmgenet_stats { */ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { /* general stats */ - STAT_NETDEV(rx_packets), - STAT_NETDEV(tx_packets), - STAT_NETDEV(rx_bytes), - STAT_NETDEV(tx_bytes), - STAT_NETDEV(rx_errors), - STAT_NETDEV(tx_errors), - STAT_NETDEV(rx_dropped), - STAT_NETDEV(tx_dropped), - STAT_NETDEV(multicast), + STAT_RTNL(rx_packets), + STAT_RTNL(tx_packets), + STAT_RTNL(rx_bytes), + STAT_RTNL(tx_bytes), + STAT_RTNL(rx_errors), + STAT_RTNL(tx_errors), + STAT_RTNL(rx_dropped), + STAT_RTNL(tx_dropped), + STAT_RTNL(multicast), /* UniMAC RSV counters */ STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), @@ -1120,11 +1120,25 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { STAT_GENET_Q(1), STAT_GENET_Q(2), STAT_GENET_Q(3), - STAT_GENET_Q(16), + STAT_GENET_Q(4), }; #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) +#define BCMGENET_STATS64_ADD(stats, m, v) \ + do { \ + u64_stats_update_begin(&stats->syncp); \ + u64_stats_add(&stats->m, v); \ + u64_stats_update_end(&stats->syncp); \ + } while (0) + +#define BCMGENET_STATS64_INC(stats, m) \ + do { \ + u64_stats_update_begin(&stats->syncp); \ + u64_stats_inc(&stats->m); \ + u64_stats_update_end(&stats->syncp); \ + } while (0) + static void bcmgenet_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -1208,8 +1222,9 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) s = &bcmgenet_gstrings_stats[i]; switch (s->type) { - case BCMGENET_STAT_NETDEV: + case BCMGENET_STAT_RTNL: case BCMGENET_STAT_SOFT: + case BCMGENET_STAT_SOFT64: continue; case BCMGENET_STAT_RUNT: offset += BCMGENET_STAT_OFFSET; @@ -1247,28 +1262,40 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev, u64 *data) { struct bcmgenet_priv *priv = netdev_priv(dev); + struct rtnl_link_stats64 stats64; + struct u64_stats_sync *syncp; + unsigned int start; int i; if (netif_running(dev)) bcmgenet_update_mib_counters(priv); - dev->netdev_ops->ndo_get_stats(dev); + dev_get_stats(dev, &stats64); for (i = 0; i < BCMGENET_STATS_LEN; i++) { const struct bcmgenet_stats *s; char *p; s = &bcmgenet_gstrings_stats[i]; - if (s->type == BCMGENET_STAT_NETDEV) - p = (char *)&dev->stats; - else - p = (char *)priv; - p += s->stat_offset; - if (sizeof(unsigned long) != sizeof(u32) && - s->stat_sizeof == sizeof(unsigned long)) - data[i] = *(unsigned long *)p; - else - data[i] = *(u32 *)p; + p = (char *)priv; + + if (s->type == BCMGENET_STAT_SOFT64) { + syncp = (struct u64_stats_sync *)(p + s->syncp_offset); + do { + start = u64_stats_fetch_begin(syncp); + data[i] = u64_stats_read((u64_stats_t *)(p + s->stat_offset)); + } while (u64_stats_fetch_retry(syncp, start)); + } else { + if (s->type == BCMGENET_STAT_RTNL) + p = (char *)&stats64; + + p += s->stat_offset; + if (sizeof(unsigned long) != sizeof(u32) && + s->stat_sizeof == sizeof(unsigned long)) + data[i] = *(unsigned long *)p; + else + data[i] = *(u32 *)p; + } } } @@ -1474,10 +1501,10 @@ static int bcmgenet_insert_flow(struct net_device *dev, loc_rule = &priv->rxnfc_rules[cmd->fs.location]; } if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) - bcmgenet_hfb_disable_filter(priv, cmd->fs.location); + bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { list_del(&loc_rule->list); - bcmgenet_hfb_clear_filter(priv, cmd->fs.location); + bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); } loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; memcpy(&loc_rule->fs, &cmd->fs, @@ -1507,10 +1534,10 @@ static int bcmgenet_delete_flow(struct net_device *dev, } if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) - bcmgenet_hfb_disable_filter(priv, cmd->fs.location); + bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { list_del(&rule->list); - bcmgenet_hfb_clear_filter(priv, cmd->fs.location); + bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); } rule->state = BCMGENET_RXNFC_STATE_UNUSED; memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); @@ -1653,9 +1680,9 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, case GENET_POWER_PASSIVE: /* Power down LED */ - if (priv->hw_params->flags & GENET_HAS_EXT) { + if (bcmgenet_has_ext(priv)) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); - if (GENET_IS_V5(priv) && !priv->ephy_16nm) + if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) reg |= EXT_PWR_DOWN_PHY_EN | EXT_PWR_DOWN_PHY_RD | EXT_PWR_DOWN_PHY_SD | @@ -1683,7 +1710,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, { u32 reg; - if (!(priv->hw_params->flags & GENET_HAS_EXT)) + if (!bcmgenet_has_ext(priv)) return; reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); @@ -1692,7 +1719,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, case GENET_POWER_PASSIVE: reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | EXT_ENERGY_DET_MASK); - if (GENET_IS_V5(priv) && !priv->ephy_16nm) { + if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) { reg &= ~(EXT_PWR_DOWN_PHY_EN | EXT_PWR_DOWN_PHY_RD | EXT_PWR_DOWN_PHY_SD | @@ -1749,28 +1776,16 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, { struct enet_cb *tx_cb_ptr; - tx_cb_ptr = ring->cbs; - tx_cb_ptr += ring->write_ptr - ring->cb_ptr; - /* Rewinding local write pointer */ if (ring->write_ptr == ring->cb_ptr) ring->write_ptr = ring->end_ptr; else ring->write_ptr--; - return tx_cb_ptr; -} - -static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_MASK_SET); -} + tx_cb_ptr = ring->cbs; + tx_cb_ptr += ring->write_ptr - ring->cb_ptr; -static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_MASK_CLEAR); + return tx_cb_ptr; } static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) @@ -1787,18 +1802,6 @@ static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) INTRL2_CPU_MASK_CLEAR); } -static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_MASK_SET); -} - -static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) -{ - bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_MASK_CLEAR); -} - static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) { bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, @@ -1870,6 +1873,7 @@ static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, struct bcmgenet_tx_ring *ring) { + struct bcmgenet_tx_stats64 *stats = &ring->stats64; struct bcmgenet_priv *priv = netdev_priv(dev); unsigned int txbds_processed = 0; unsigned int bytes_compl = 0; @@ -1879,12 +1883,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, struct sk_buff *skb; /* Clear status before servicing to reduce spurious interrupts */ - if (ring->index == DESC_INDEX) - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE, - INTRL2_CPU_CLEAR); - else - bcmgenet_intrl2_1_writel(priv, (1 << ring->index), - INTRL2_CPU_CLEAR); + bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_CLEAR); /* Compute how many buffers are transmitted since last xmit call */ c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX) @@ -1915,22 +1914,53 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, ring->free_bds += txbds_processed; ring->c_index = c_index; - ring->packets += pkts_compl; - ring->bytes += bytes_compl; + u64_stats_update_begin(&stats->syncp); + u64_stats_add(&stats->packets, pkts_compl); + u64_stats_add(&stats->bytes, bytes_compl); + u64_stats_update_end(&stats->syncp); - netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue), + netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), pkts_compl, bytes_compl); return txbds_processed; } static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, - struct bcmgenet_tx_ring *ring) + struct bcmgenet_tx_ring *ring, + bool all) { - unsigned int released; + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + unsigned int released, drop, wr_ptr; + struct enet_cb *cb_ptr; + struct sk_buff *skb; spin_lock_bh(&ring->lock); released = __bcmgenet_tx_reclaim(dev, ring); + if (all) { + skb = NULL; + drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; + released += drop; + ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; + ring->free_bds += drop; + while (drop--) { + cb_ptr = bcmgenet_put_txcb(priv, ring); + skb = cb_ptr->skb; + bcmgenet_free_tx_cb(kdev, cb_ptr); + if (skb && cb_ptr == GENET_CB(skb)->first_cb) { + dev_consume_skb_any(skb); + skb = NULL; + } + } + if (skb) + dev_consume_skb_any(skb); + netdev_tx_reset_queue(netdev_get_tx_queue(dev, ring->index)); + bcmgenet_tdma_ring_writel(priv, ring->index, + ring->prod_index, TDMA_PROD_INDEX); + wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); + bcmgenet_tdma_ring_writel(priv, ring->index, wr_ptr, + TDMA_WRITE_PTR); + } spin_unlock_bh(&ring->lock); return released; @@ -1946,14 +1976,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) spin_lock(&ring->lock); work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring); if (ring->free_bds > (MAX_SKB_FRAGS + 1)) { - txq = netdev_get_tx_queue(ring->priv->dev, ring->queue); + txq = netdev_get_tx_queue(ring->priv->dev, ring->index); netif_tx_wake_queue(txq); } spin_unlock(&ring->lock); if (work_done == 0) { napi_complete(napi); - ring->int_enable(ring); + bcmgenet_tx_ring_int_enable(ring); return 0; } @@ -1964,22 +1994,21 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) static void bcmgenet_tx_reclaim_all(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - int i; - - if (netif_is_multiqueue(dev)) { - for (i = 0; i < priv->hw_params->tx_queues; i++) - bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); - } + int i = 0; - bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); + do { + bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true); + } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); } /* Reallocate the SKB to put enough headroom in front of it and insert * the transmit checksum offsets in the descriptors */ static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, - struct sk_buff *skb) + struct sk_buff *skb, + struct bcmgenet_tx_ring *ring) { + struct bcmgenet_tx_stats64 *stats = &ring->stats64; struct bcmgenet_priv *priv = netdev_priv(dev); struct status_64 *status = NULL; struct sk_buff *new_skb; @@ -1996,7 +2025,7 @@ static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, if (!new_skb) { dev_kfree_skb_any(skb); priv->mib.tx_realloc_tsb_failed++; - dev->stats.tx_dropped++; + BCMGENET_STATS64_INC(stats, dropped); return NULL; } dev_consume_skb_any(skb); @@ -2059,19 +2088,14 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) index = skb_get_queue_mapping(skb); /* Mapping strategy: - * queue_mapping = 0, unclassified, packet xmited through ring16 - * queue_mapping = 1, goes to ring 0. (highest priority queue - * queue_mapping = 2, goes to ring 1. - * queue_mapping = 3, goes to ring 2. - * queue_mapping = 4, goes to ring 3. + * queue_mapping = 0, unclassified, packet xmited through ring 0 + * queue_mapping = 1, goes to ring 1. (highest priority queue) + * queue_mapping = 2, goes to ring 2. + * queue_mapping = 3, goes to ring 3. + * queue_mapping = 4, goes to ring 4. */ - if (index == 0) - index = DESC_INDEX; - else - index -= 1; - ring = &priv->tx_rings[index]; - txq = netdev_get_tx_queue(dev, ring->queue); + txq = netdev_get_tx_queue(dev, index); nr_frags = skb_shinfo(skb)->nr_frags; @@ -2089,7 +2113,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) GENET_CB(skb)->bytes_sent = skb->len; /* add the Transmit Status Block */ - skb = bcmgenet_add_tsb(dev, skb); + skb = bcmgenet_add_tsb(dev, skb, ring); if (!skb) { ret = NETDEV_TX_OK; goto out; @@ -2231,6 +2255,7 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, unsigned int budget) { + struct bcmgenet_rx_stats64 *stats = &ring->stats64; struct bcmgenet_priv *priv = ring->priv; struct net_device *dev = priv->dev; struct enet_cb *cb; @@ -2244,15 +2269,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, unsigned int discards; /* Clear status before servicing to reduce spurious interrupts */ - if (ring->index == DESC_INDEX) { - bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE, - INTRL2_CPU_CLEAR); - } else { - mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); - bcmgenet_intrl2_1_writel(priv, - mask, - INTRL2_CPU_CLEAR); - } + mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); + bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); @@ -2260,7 +2278,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, DMA_P_INDEX_DISCARD_CNT_MASK; if (discards > ring->old_discards) { discards = discards - ring->old_discards; - ring->errors += discards; + BCMGENET_STATS64_ADD(stats, errors, discards); ring->old_discards += discards; /* Clear HW register when we reach 75% of maximum 0xFFFF */ @@ -2286,7 +2304,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, skb = bcmgenet_rx_refill(priv, cb); if (unlikely(!skb)) { - ring->dropped++; + BCMGENET_STATS64_INC(stats, dropped); goto next; } @@ -2313,8 +2331,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, if (unlikely(len > RX_BUF_LENGTH)) { netif_err(priv, rx_status, dev, "oversized packet\n"); - dev->stats.rx_length_errors++; - dev->stats.rx_errors++; + BCMGENET_STATS64_INC(stats, length_errors); dev_kfree_skb_any(skb); goto next; } @@ -2322,7 +2339,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { netif_err(priv, rx_status, dev, "dropping fragmented packet!\n"); - ring->errors++; + BCMGENET_STATS64_INC(stats, errors); dev_kfree_skb_any(skb); goto next; } @@ -2335,15 +2352,22 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, DMA_RX_RXER))) { netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", (unsigned int)dma_flag); + u64_stats_update_begin(&stats->syncp); if (dma_flag & DMA_RX_CRC_ERROR) - dev->stats.rx_crc_errors++; + u64_stats_inc(&stats->crc_errors); if (dma_flag & DMA_RX_OV) - dev->stats.rx_over_errors++; + u64_stats_inc(&stats->over_errors); if (dma_flag & DMA_RX_NO) - dev->stats.rx_frame_errors++; + u64_stats_inc(&stats->frame_errors); if (dma_flag & DMA_RX_LG) - dev->stats.rx_length_errors++; - dev->stats.rx_errors++; + u64_stats_inc(&stats->length_errors); + if ((dma_flag & (DMA_RX_CRC_ERROR | + DMA_RX_OV | + DMA_RX_NO | + DMA_RX_LG | + DMA_RX_RXER)) == DMA_RX_RXER) + u64_stats_inc(&stats->errors); + u64_stats_update_end(&stats->syncp); dev_kfree_skb_any(skb); goto next; } /* error packet */ @@ -2363,10 +2387,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, /*Finish setting up the received SKB and send it to the kernel*/ skb->protocol = eth_type_trans(skb, priv->dev); - ring->packets++; - ring->bytes += len; + + u64_stats_update_begin(&stats->syncp); + u64_stats_inc(&stats->packets); + u64_stats_add(&stats->bytes, len); if (dma_flag & DMA_RX_MULT) - dev->stats.multicast++; + u64_stats_inc(&stats->multicast); + u64_stats_update_end(&stats->syncp); /* Notify kernel */ napi_gro_receive(&ring->napi, skb); @@ -2401,7 +2428,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete_done(napi, work_done); - ring->int_enable(ring); + bcmgenet_rx_ring_int_enable(ring); } if (ring->dim.use_dim) { @@ -2525,7 +2552,7 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { - if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + if (bcmgenet_has_moca_link_det(priv)) int0_enable |= UMAC_IRQ_LINK_EVENT; } bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); @@ -2590,7 +2617,7 @@ static void init_umac(struct bcmgenet_priv *priv) } /* Enable MDIO interrupts on GENET v3+ */ - if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) + if (bcmgenet_has_mdio_intr(priv)) int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); @@ -2641,15 +2668,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, spin_lock_init(&ring->lock); ring->priv = priv; ring->index = index; - if (index == DESC_INDEX) { - ring->queue = 0; - ring->int_enable = bcmgenet_tx_ring16_int_enable; - ring->int_disable = bcmgenet_tx_ring16_int_disable; - } else { - ring->queue = index + 1; - ring->int_enable = bcmgenet_tx_ring_int_enable; - ring->int_disable = bcmgenet_tx_ring_int_disable; - } ring->cbs = priv->tx_cbs + start_ptr; ring->size = size; ring->clean_ptr = start_ptr; @@ -2660,8 +2678,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, ring->end_ptr = end_ptr - 1; ring->prod_index = 0; - /* Set flow period for ring != 16 */ - if (index != DESC_INDEX) + /* Set flow period for ring != 0 */ + if (index) flow_period_val = ENET_MAX_MTU_SIZE << 16; bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); @@ -2699,13 +2717,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, ring->priv = priv; ring->index = index; - if (index == DESC_INDEX) { - ring->int_enable = bcmgenet_rx_ring16_int_enable; - ring->int_disable = bcmgenet_rx_ring16_int_disable; - } else { - ring->int_enable = bcmgenet_rx_ring_int_enable; - ring->int_disable = bcmgenet_rx_ring_int_disable; - } ring->cbs = priv->rx_cbs + start_ptr; ring->size = size; ring->c_index = 0; @@ -2751,15 +2762,11 @@ static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; napi_enable(&ring->napi); - ring->int_enable(ring); + bcmgenet_tx_ring_int_enable(ring); } - - ring = &priv->tx_rings[DESC_INDEX]; - napi_enable(&ring->napi); - ring->int_enable(ring); } static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) @@ -2767,13 +2774,10 @@ static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; napi_disable(&ring->napi); } - - ring = &priv->tx_rings[DESC_INDEX]; - napi_disable(&ring->napi); } static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) @@ -2781,33 +2785,31 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_tx_ring *ring; - for (i = 0; i < priv->hw_params->tx_queues; ++i) { + for (i = 0; i <= priv->hw_params->tx_queues; ++i) { ring = &priv->tx_rings[i]; netif_napi_del(&ring->napi); } - - ring = &priv->tx_rings[DESC_INDEX]; - netif_napi_del(&ring->napi); } /* Initialize Tx queues * - * Queues 0-3 are priority-based, each one has 32 descriptors, - * with queue 0 being the highest priority queue. + * Queues 1-4 are priority-based, each one has 32 descriptors, + * with queue 1 being the highest priority queue. * - * Queue 16 is the default Tx queue with - * GENET_Q16_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. + * Queue 0 is the default Tx queue with + * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. * * The transmit control block pool is then partitioned as follows: - * - Tx queue 0 uses tx_cbs[0..31] - * - Tx queue 1 uses tx_cbs[32..63] - * - Tx queue 2 uses tx_cbs[64..95] - * - Tx queue 3 uses tx_cbs[96..127] - * - Tx queue 16 uses tx_cbs[128..255] + * - Tx queue 0 uses tx_cbs[0..127] + * - Tx queue 1 uses tx_cbs[128..159] + * - Tx queue 2 uses tx_cbs[160..191] + * - Tx queue 3 uses tx_cbs[192..223] + * - Tx queue 4 uses tx_cbs[224..255] */ static void bcmgenet_init_tx_queues(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; u32 i, dma_enable; u32 dma_ctrl, ring_cfg; u32 dma_priority[3] = {0, 0, 0}; @@ -2824,27 +2826,17 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); /* Initialize Tx priority queues */ - for (i = 0; i < priv->hw_params->tx_queues; i++) { - bcmgenet_init_tx_ring(priv, i, priv->hw_params->tx_bds_per_q, - i * priv->hw_params->tx_bds_per_q, - (i + 1) * priv->hw_params->tx_bds_per_q); + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + bcmgenet_init_tx_ring(priv, i, end - start, start, end); + start = end; + end += priv->hw_params->tx_bds_per_q; ring_cfg |= (1 << i); dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); dma_priority[DMA_PRIO_REG_INDEX(i)] |= - ((GENET_Q0_PRIORITY + i) << DMA_PRIO_REG_SHIFT(i)); + (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) + << DMA_PRIO_REG_SHIFT(i); } - /* Initialize Tx default queue 16 */ - bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_Q16_TX_BD_CNT, - priv->hw_params->tx_queues * - priv->hw_params->tx_bds_per_q, - TOTAL_DESC); - ring_cfg |= (1 << DESC_INDEX); - dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); - dma_priority[DMA_PRIO_REG_INDEX(DESC_INDEX)] |= - ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << - DMA_PRIO_REG_SHIFT(DESC_INDEX)); - /* Set Tx queue priorities */ bcmgenet_tdma_writel(priv, dma_priority[0], DMA_PRIORITY_0); bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); @@ -2864,15 +2856,11 @@ static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; napi_enable(&ring->napi); - ring->int_enable(ring); + bcmgenet_rx_ring_int_enable(ring); } - - ring = &priv->rx_rings[DESC_INDEX]; - napi_enable(&ring->napi); - ring->int_enable(ring); } static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) @@ -2880,15 +2868,11 @@ static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; napi_disable(&ring->napi); cancel_work_sync(&ring->dim.dim.work); } - - ring = &priv->rx_rings[DESC_INDEX]; - napi_disable(&ring->napi); - cancel_work_sync(&ring->dim.dim.work); } static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) @@ -2896,13 +2880,10 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) unsigned int i; struct bcmgenet_rx_ring *ring; - for (i = 0; i < priv->hw_params->rx_queues; ++i) { + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { ring = &priv->rx_rings[i]; netif_napi_del(&ring->napi); } - - ring = &priv->rx_rings[DESC_INDEX]; - netif_napi_del(&ring->napi); } /* Initialize Rx queues @@ -2910,15 +2891,13 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be * used to direct traffic to these queues. * - * Queue 16 is the default Rx queue with GENET_Q16_RX_BD_CNT descriptors. + * Queue 0 is also the default Rx queue with GENET_Q0_RX_BD_CNT descriptors. */ static int bcmgenet_init_rx_queues(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); - u32 i; - u32 dma_enable; - u32 dma_ctrl; - u32 ring_cfg; + unsigned int start = 0, end = GENET_Q0_RX_BD_CNT; + u32 i, dma_enable, dma_ctrl = 0, ring_cfg = 0; int ret; dma_ctrl = bcmgenet_rdma_readl(priv, DMA_CTRL); @@ -2930,34 +2909,21 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) ring_cfg = 0; /* Initialize Rx priority queues */ - for (i = 0; i < priv->hw_params->rx_queues; i++) { - ret = bcmgenet_init_rx_ring(priv, i, - priv->hw_params->rx_bds_per_q, - i * priv->hw_params->rx_bds_per_q, - (i + 1) * - priv->hw_params->rx_bds_per_q); + for (i = 0; i <= priv->hw_params->rx_queues; i++) { + ret = bcmgenet_init_rx_ring(priv, i, end - start, start, end); if (ret) return ret; + start = end; + end += priv->hw_params->rx_bds_per_q; ring_cfg |= (1 << i); dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); } - /* Initialize Rx default queue 16 */ - ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, GENET_Q16_RX_BD_CNT, - priv->hw_params->rx_queues * - priv->hw_params->rx_bds_per_q, - TOTAL_DESC); - if (ret) - return ret; - - ring_cfg |= (1 << DESC_INDEX); - dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); - - /* Enable rings */ + /* Configure Rx queues as descriptor rings */ bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); - /* Configure ring as descriptor ring and re-enable DMA if enabled */ + /* Enable Rx rings */ if (dma_enable) dma_ctrl |= DMA_EN; bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); @@ -3016,14 +2982,14 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) } dma_ctrl = 0; - for (i = 0; i < priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); reg = bcmgenet_rdma_readl(priv, DMA_CTRL); reg &= ~dma_ctrl; bcmgenet_rdma_writel(priv, reg, DMA_CTRL); dma_ctrl = 0; - for (i = 0; i < priv->hw_params->tx_queues; i++) + for (i = 0; i <= priv->hw_params->tx_queues; i++) dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); reg = bcmgenet_tdma_readl(priv, DMA_CTRL); reg &= ~dma_ctrl; @@ -3040,18 +3006,11 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) bcmgenet_fini_rx_napi(priv); bcmgenet_fini_tx_napi(priv); - for (i = 0; i < priv->num_tx_bds; i++) - dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, - priv->tx_cbs + i)); - - for (i = 0; i < priv->hw_params->tx_queues; i++) { - txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + txq = netdev_get_tx_queue(priv->dev, i); netdev_tx_reset_queue(txq); } - txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[DESC_INDEX].queue); - netdev_tx_reset_queue(txq); - bcmgenet_free_rx_buffers(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); @@ -3144,7 +3103,7 @@ static void bcmgenet_irq_task(struct work_struct *work) } -/* bcmgenet_isr1: handle Rx and Tx priority queues */ +/* bcmgenet_isr1: handle Rx and Tx queues */ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; @@ -3163,7 +3122,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) "%s: IRQ=0x%x\n", __func__, status); /* Check Rx priority queue interrupts */ - for (index = 0; index < priv->hw_params->rx_queues; index++) { + for (index = 0; index <= priv->hw_params->rx_queues; index++) { if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) continue; @@ -3171,20 +3130,20 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) rx_ring->dim.event_ctr++; if (likely(napi_schedule_prep(&rx_ring->napi))) { - rx_ring->int_disable(rx_ring); + bcmgenet_rx_ring_int_disable(rx_ring); __napi_schedule_irqoff(&rx_ring->napi); } } /* Check Tx priority queue interrupts */ - for (index = 0; index < priv->hw_params->tx_queues; index++) { + for (index = 0; index <= priv->hw_params->tx_queues; index++) { if (!(status & BIT(index))) continue; tx_ring = &priv->tx_rings[index]; if (likely(napi_schedule_prep(&tx_ring->napi))) { - tx_ring->int_disable(tx_ring); + bcmgenet_tx_ring_int_disable(tx_ring); __napi_schedule_irqoff(&tx_ring->napi); } } @@ -3192,12 +3151,10 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) return IRQ_HANDLED; } -/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ +/* bcmgenet_isr0: handle other stuff */ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) { struct bcmgenet_priv *priv = dev_id; - struct bcmgenet_rx_ring *rx_ring; - struct bcmgenet_tx_ring *tx_ring; unsigned int status; unsigned long flags; @@ -3211,26 +3168,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) netif_dbg(priv, intr, priv->dev, "IRQ=0x%x\n", status); - if (status & UMAC_IRQ_RXDMA_DONE) { - rx_ring = &priv->rx_rings[DESC_INDEX]; - rx_ring->dim.event_ctr++; - - if (likely(napi_schedule_prep(&rx_ring->napi))) { - rx_ring->int_disable(rx_ring); - __napi_schedule_irqoff(&rx_ring->napi); - } - } - - if (status & UMAC_IRQ_TXDMA_DONE) { - tx_ring = &priv->tx_rings[DESC_INDEX]; - - if (likely(napi_schedule_prep(&tx_ring->napi))) { - tx_ring->int_disable(tx_ring); - __napi_schedule_irqoff(&tx_ring->napi); - } - } - - if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && + if (bcmgenet_has_mdio_intr(priv) && status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { wake_up(&priv->wq); } @@ -3255,23 +3193,6 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_NET_POLL_CONTROLLER -static void bcmgenet_poll_controller(struct net_device *dev) -{ - struct bcmgenet_priv *priv = netdev_priv(dev); - - /* Invoke the main RX/TX interrupt handler */ - disable_irq(priv->irq0); - bcmgenet_isr0(priv->irq0, priv); - enable_irq(priv->irq0); - - /* And the interrupt handler for RX/TX priority queues */ - disable_irq(priv->irq1); - bcmgenet_isr1(priv->irq1, priv); - enable_irq(priv->irq1); -} -#endif - static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) { u32 reg; @@ -3312,15 +3233,15 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) u32 dma_ctrl; /* disable DMA */ - dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; - for (i = 0; i < priv->hw_params->tx_queues; i++) + dma_ctrl = DMA_EN; + for (i = 0; i <= priv->hw_params->tx_queues; i++) dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); reg = bcmgenet_tdma_readl(priv, DMA_CTRL); reg &= ~dma_ctrl; bcmgenet_tdma_writel(priv, reg, DMA_CTRL); - dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; - for (i = 0; i < priv->hw_params->rx_queues; i++) + dma_ctrl = DMA_EN; + for (i = 0; i <= priv->hw_params->rx_queues; i++) dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); reg = bcmgenet_rdma_readl(priv, DMA_CTRL); reg &= ~dma_ctrl; @@ -3403,6 +3324,9 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); + /* HFB init */ + bcmgenet_hfb_init(priv); + /* Disable RX/TX DMA and flush TX and RX queues */ dma_ctrl = bcmgenet_dma_disable(priv, true); @@ -3413,12 +3337,8 @@ static int bcmgenet_open(struct net_device *dev) goto err_clk_disable; } - /* Always enable ring 16 - descriptor ring */ bcmgenet_enable_dma(priv, dma_ctrl); - /* HFB init */ - bcmgenet_hfb_init(priv); - ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, dev->name, priv); if (ret < 0) { @@ -3525,16 +3445,11 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) if (!netif_msg_tx_err(priv)) return; - txq = netdev_get_tx_queue(priv->dev, ring->queue); + txq = netdev_get_tx_queue(priv->dev, ring->index); spin_lock(&ring->lock); - if (ring->index == DESC_INDEX) { - intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); - intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; - } else { - intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); - intmsk = 1 << ring->index; - } + intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); + intmsk = 1 << ring->index; c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); txq_stopped = netif_tx_queue_stopped(txq); @@ -3548,7 +3463,7 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) "(sw)c_index: %d (hw)c_index: %d\n" "(sw)clean_p: %d (sw)write_p: %d\n" "(sw)cb_ptr: %d (sw)end_ptr: %d\n", - ring->index, ring->queue, + ring->index, ring->index, txq_stopped ? "stopped" : "active", intsts & intmsk ? "enabled" : "disabled", free_bds, ring->size, @@ -3561,32 +3476,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) { struct bcmgenet_priv *priv = netdev_priv(dev); - u32 int0_enable = 0; - u32 int1_enable = 0; - unsigned int q; + struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; + struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); - for (q = 0; q < priv->hw_params->tx_queues; q++) - bcmgenet_dump_tx_queue(&priv->tx_rings[q]); - bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); + bcmgenet_dump_tx_queue(ring); - bcmgenet_tx_reclaim_all(dev); - - for (q = 0; q < priv->hw_params->tx_queues; q++) - int1_enable |= (1 << q); + bcmgenet_tx_reclaim(dev, ring, true); - int0_enable = UMAC_IRQ_TXDMA_DONE; - - /* Re-enable TX interrupts if disabled */ - bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); - bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); + /* Re-enable the TX interrupt for this ring */ + bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); - netif_trans_update(dev); + txq_trans_cond_update(txq); - dev->stats.tx_errors++; + BCMGENET_STATS64_INC((&ring->stats64), errors); - netif_tx_wake_all_queues(dev); + netif_tx_wake_queue(txq); } #define MAX_MDF_FILTER 17 @@ -3673,47 +3579,68 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p) return 0; } -static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) +static void bcmgenet_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) { struct bcmgenet_priv *priv = netdev_priv(dev); - unsigned long tx_bytes = 0, tx_packets = 0; - unsigned long rx_bytes = 0, rx_packets = 0; - unsigned long rx_errors = 0, rx_dropped = 0; - struct bcmgenet_tx_ring *tx_ring; - struct bcmgenet_rx_ring *rx_ring; + struct bcmgenet_tx_stats64 *tx_stats; + struct bcmgenet_rx_stats64 *rx_stats; + u64 rx_length_errors, rx_over_errors; + u64 rx_crc_errors, rx_frame_errors; + u64 tx_errors, tx_dropped; + u64 rx_errors, rx_dropped; + u64 tx_bytes, tx_packets; + u64 rx_bytes, rx_packets; + unsigned int start; unsigned int q; - - for (q = 0; q < priv->hw_params->tx_queues; q++) { - tx_ring = &priv->tx_rings[q]; - tx_bytes += tx_ring->bytes; - tx_packets += tx_ring->packets; + u64 multicast; + + for (q = 0; q <= priv->hw_params->tx_queues; q++) { + tx_stats = &priv->tx_rings[q].stats64; + do { + start = u64_stats_fetch_begin(&tx_stats->syncp); + tx_bytes = u64_stats_read(&tx_stats->bytes); + tx_packets = u64_stats_read(&tx_stats->packets); + tx_errors = u64_stats_read(&tx_stats->errors); + tx_dropped = u64_stats_read(&tx_stats->dropped); + } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); + + stats->tx_bytes += tx_bytes; + stats->tx_packets += tx_packets; + stats->tx_errors += tx_errors; + stats->tx_dropped += tx_dropped; } - tx_ring = &priv->tx_rings[DESC_INDEX]; - tx_bytes += tx_ring->bytes; - tx_packets += tx_ring->packets; - - for (q = 0; q < priv->hw_params->rx_queues; q++) { - rx_ring = &priv->rx_rings[q]; - rx_bytes += rx_ring->bytes; - rx_packets += rx_ring->packets; - rx_errors += rx_ring->errors; - rx_dropped += rx_ring->dropped; + for (q = 0; q <= priv->hw_params->rx_queues; q++) { + rx_stats = &priv->rx_rings[q].stats64; + do { + start = u64_stats_fetch_begin(&rx_stats->syncp); + rx_bytes = u64_stats_read(&rx_stats->bytes); + rx_packets = u64_stats_read(&rx_stats->packets); + rx_errors = u64_stats_read(&rx_stats->errors); + rx_dropped = u64_stats_read(&rx_stats->dropped); + rx_length_errors = u64_stats_read(&rx_stats->length_errors); + rx_over_errors = u64_stats_read(&rx_stats->over_errors); + rx_crc_errors = u64_stats_read(&rx_stats->crc_errors); + rx_frame_errors = u64_stats_read(&rx_stats->frame_errors); + multicast = u64_stats_read(&rx_stats->multicast); + } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); + + rx_errors += rx_length_errors; + rx_errors += rx_crc_errors; + rx_errors += rx_frame_errors; + + stats->rx_bytes += rx_bytes; + stats->rx_packets += rx_packets; + stats->rx_errors += rx_errors; + stats->rx_dropped += rx_dropped; + stats->rx_missed_errors += rx_errors; + stats->rx_length_errors += rx_length_errors; + stats->rx_over_errors += rx_over_errors; + stats->rx_crc_errors += rx_crc_errors; + stats->rx_frame_errors += rx_frame_errors; + stats->multicast += multicast; } - rx_ring = &priv->rx_rings[DESC_INDEX]; - rx_bytes += rx_ring->bytes; - rx_packets += rx_ring->packets; - rx_errors += rx_ring->errors; - rx_dropped += rx_ring->dropped; - - dev->stats.tx_bytes = tx_bytes; - dev->stats.tx_packets = tx_packets; - dev->stats.rx_bytes = rx_bytes; - dev->stats.rx_packets = rx_packets; - dev->stats.rx_errors = rx_errors; - dev->stats.rx_missed_errors = rx_errors; - dev->stats.rx_dropped = rx_dropped; - return &dev->stats; } static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) @@ -3741,10 +3668,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_set_mac_address = bcmgenet_set_mac_addr, .ndo_eth_ioctl = phy_do_ioctl_running, .ndo_set_features = bcmgenet_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = bcmgenet_poll_controller, -#endif - .ndo_get_stats = bcmgenet_get_stats, + .ndo_get_stats64 = bcmgenet_get_stats64, .ndo_change_carrier = bcmgenet_change_carrier, }; @@ -3920,7 +3844,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) } #ifdef CONFIG_PHYS_ADDR_T_64BIT - if (!(params->flags & GENET_HAS_40BITS)) + if (!bcmgenet_has_40bits(priv)) pr_warn("GENET does not support 40-bits PA\n"); #endif @@ -4099,7 +4023,7 @@ static int bcmgenet_probe(struct platform_device *pdev) bcmgenet_set_hw_params(priv); err = -EIO; - if (priv->hw_params->flags & GENET_HAS_40BITS) + if (bcmgenet_has_40bits(priv)) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); if (err) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); @@ -4154,16 +4078,19 @@ static int bcmgenet_probe(struct platform_device *pdev) if (err) goto err_clk_disable; - /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues - * just the ring 16 descriptor based TX - */ + /* setup number of real queues + 1 */ netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); /* Set default coalescing parameters */ - for (i = 0; i < priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) priv->rx_rings[i].rx_max_coalesced_frames = 1; - priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; + + /* Initialize u64 stats seq counter for 32bit machines */ + for (i = 0; i <= priv->hw_params->rx_queues; i++) + u64_stats_init(&priv->rx_rings[i].stats64.syncp); + for (i = 0; i <= priv->hw_params->tx_queues; i++) + u64_stats_init(&priv->tx_rings[i].stats64.syncp); /* libphy will determine the link state */ netif_carrier_off(dev); @@ -4288,7 +4215,6 @@ static int bcmgenet_resume(struct device *d) goto out_clk_disable; } - /* Always enable ring 16 - descriptor ring */ bcmgenet_enable_dma(priv, dma_ctrl); if (!device_may_wakeup(d)) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 28e2c94ef835c9..94957dfa55b6fd 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2014-2024 Broadcom + * Copyright (c) 2014-2025 Broadcom */ #ifndef __BCMGENET_H__ @@ -18,6 +18,9 @@ #include "../unimac.h" +/* Maximum number of hardware queues, downsized if needed */ +#define GENET_MAX_MQ_CNT 4 + /* total number of Buffer Descriptors, same for Rx/Tx */ #define TOTAL_DESC 256 @@ -152,6 +155,27 @@ struct bcmgenet_mib_counters { u32 tx_realloc_tsb_failed; }; +struct bcmgenet_tx_stats64 { + struct u64_stats_sync syncp; + u64_stats_t packets; + u64_stats_t bytes; + u64_stats_t errors; + u64_stats_t dropped; +}; + +struct bcmgenet_rx_stats64 { + struct u64_stats_sync syncp; + u64_stats_t bytes; + u64_stats_t packets; + u64_stats_t errors; + u64_stats_t dropped; + u64_stats_t multicast; + u64_stats_t length_errors; + u64_stats_t over_errors; + u64_stats_t crc_errors; + u64_stats_t frame_errors; +}; + #define UMAC_MIB_START 0x400 #define UMAC_MDIO_CMD 0x614 @@ -510,10 +534,8 @@ struct bcmgenet_skb_cb { struct bcmgenet_tx_ring { spinlock_t lock; /* ring lock */ struct napi_struct napi; /* NAPI per tx queue */ - unsigned long packets; - unsigned long bytes; + struct bcmgenet_tx_stats64 stats64; unsigned int index; /* ring index */ - unsigned int queue; /* queue index */ struct enet_cb *cbs; /* tx ring buffer control block*/ unsigned int size; /* size of each tx ring */ unsigned int clean_ptr; /* Tx ring clean pointer */ @@ -523,8 +545,6 @@ struct bcmgenet_tx_ring { unsigned int prod_index; /* Tx ring producer index SW copy */ unsigned int cb_ptr; /* Tx ring initial CB ptr */ unsigned int end_ptr; /* Tx ring end CB ptr */ - void (*int_enable)(struct bcmgenet_tx_ring *); - void (*int_disable)(struct bcmgenet_tx_ring *); struct bcmgenet_priv *priv; }; @@ -538,10 +558,7 @@ struct bcmgenet_net_dim { struct bcmgenet_rx_ring { struct napi_struct napi; /* Rx NAPI struct */ - unsigned long bytes; - unsigned long packets; - unsigned long errors; - unsigned long dropped; + struct bcmgenet_rx_stats64 stats64; unsigned int index; /* Rx ring index */ struct enet_cb *cbs; /* Rx ring buffer control block */ unsigned int size; /* Rx ring size */ @@ -553,8 +570,6 @@ struct bcmgenet_rx_ring { struct bcmgenet_net_dim dim; u32 rx_max_coalesced_frames; u32 rx_coalesce_usecs; - void (*int_enable)(struct bcmgenet_rx_ring *); - void (*int_disable)(struct bcmgenet_rx_ring *); struct bcmgenet_priv *priv; }; @@ -583,7 +598,7 @@ struct bcmgenet_priv { struct enet_cb *tx_cbs; unsigned int num_tx_bds; - struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1]; + struct bcmgenet_tx_ring tx_rings[GENET_MAX_MQ_CNT + 1]; /* receive variables */ void __iomem *rx_bds; @@ -593,7 +608,7 @@ struct bcmgenet_priv { struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES]; struct list_head rxnfc_list; - struct bcmgenet_rx_ring rx_rings[DESC_INDEX + 1]; + struct bcmgenet_rx_ring rx_rings[GENET_MAX_MQ_CNT + 1]; /* other misc variables */ struct bcmgenet_hw_params *hw_params; @@ -650,6 +665,31 @@ struct bcmgenet_priv { struct ethtool_eee eee; }; +static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) +{ + return !!(priv->hw_params->flags & GENET_HAS_40BITS); +} + +static inline bool bcmgenet_has_ext(struct bcmgenet_priv *priv) +{ + return !!(priv->hw_params->flags & GENET_HAS_EXT); +} + +static inline bool bcmgenet_has_mdio_intr(struct bcmgenet_priv *priv) +{ + return !!(priv->hw_params->flags & GENET_HAS_MDIO_INTR); +} + +static inline bool bcmgenet_has_moca_link_det(struct bcmgenet_priv *priv) +{ + return !!(priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET); +} + +static inline bool bcmgenet_has_ephy_16nm(struct bcmgenet_priv *priv) +{ + return priv->ephy_16nm; +} + #define GENET_IO_MACRO(name, offset) \ static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \ u32 off) \ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 2033fb9d893e02..98358b71cef5c9 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -2,7 +2,7 @@ /* * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support * - * Copyright (c) 2014-2024 Broadcom + * Copyright (c) 2014-2025 Broadcom */ #define pr_fmt(fmt) "bcmgenet_wol: " fmt @@ -180,7 +180,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, if (priv->wolopts & WAKE_FILTER) { list_for_each_entry(rule, &priv->rxnfc_list, list) if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE) - hfb_enable |= (1 << rule->fs.location); + hfb_enable |= (1 << (rule->fs.location + 1)); reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN; bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); } diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index e7c659cd39746f..e4b498d6bd9142 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -2,7 +2,7 @@ /* * Broadcom GENET MDIO routines * - * Copyright (c) 2014-2024 Broadcom + * Copyright (c) 2014-2025 Broadcom */ #include @@ -153,7 +153,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) u32 reg = 0; /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ - if (GENET_IS_V4(priv) || priv->ephy_16nm) { + if (GENET_IS_V4(priv) || bcmgenet_has_ephy_16nm(priv)) { reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); if (enable) { reg &= ~EXT_CK25_DIS; @@ -183,7 +183,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) { - if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + if (bcmgenet_has_moca_link_det(priv)) fixed_phy_set_link_update(priv->dev->phydev, bcmgenet_fixed_phy_link_update); } diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index de7b3184223309..d0a259e47960f8 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o obj-$(CONFIG_FSL_FMAN) += fman/ obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ -obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ - +obj-y += dpaa2/ obj-y += enetc/ diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index d029b69c3f183e..36280e5d99e1f3 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH tristate "Freescale DPAA2 Ethernet Switch" depends on BRIDGE || BRIDGE=n depends on NET_SWITCHDEV + depends on FSL_MC_BUS && FSL_MC_DPIO + select PHYLINK + select PCS_LYNX + select FSL_XGMAC_MDIO help Driver for Freescale DPAA2 Ethernet Switch. This driver manages switch objects discovered on the Freeescale MC bus. diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 9e9138ccac421f..3b1d142ebf2766 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7700,6 +7700,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_register: if (!(adapter->flags & FLAG_HAS_AMT)) e1000e_release_hw_control(adapter); + e1000e_ptp_remove(adapter); err_eeprom: if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) e1000_phy_hw_reset(&adapter->hw); diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index f095069dc32a9e..9858186160b868 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1262,6 +1262,7 @@ void i40e_ptp_restore_hw_time(struct i40e_pf *pf); void i40e_ptp_init(struct i40e_pf *pf); void i40e_ptp_stop(struct i40e_pf *pf); int i40e_ptp_alloc_pins(struct i40e_pf *pf); +void i40e_ptp_free_pins(struct i40e_pf *pf); int i40e_update_adq_vsi_queues(struct i40e_vsi *vsi, int vsi_offset); int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi); int i40e_get_partition_bw_setting(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9bcd32d31da771..063f9ced3ffd1d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -13940,7 +13940,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) netdev->neigh_priv_len = sizeof(u32) * 4; netdev->priv_flags |= IFF_UNICAST_FLT; - netdev->priv_flags |= IFF_SUPP_NOFCS; /* Setup netdev TC information */ i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); @@ -16301,6 +16300,7 @@ err_vsis: i40e_clear_interrupt_scheme(pf); kfree(pf->vsi); err_switch_setup: + i40e_ptp_free_pins(pf); i40e_reset_interrupt_capability(pf); timer_shutdown_sync(&pf->service_timer); err_mac_addr: diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 65c714d0bfffd1..613213aa4da8fc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -937,12 +937,13 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) * * Release memory allocated for PTP pins. **/ -static void i40e_ptp_free_pins(struct i40e_pf *pf) +void i40e_ptp_free_pins(struct i40e_pf *pf) { if (i40e_is_ptp_pin_dev(&pf->hw)) { kfree(pf->ptp_pins); kfree(pf->ptp_caps.pin_config); pf->ptp_pins = NULL; + pf->ptp_caps.pin_config = NULL; } } diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 431d9d62c8c668..c9553fa475ae1a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -158,11 +158,10 @@ struct iavf_vlan { enum iavf_vlan_state_t { IAVF_VLAN_INVALID, IAVF_VLAN_ADD, /* filter needs to be added */ - IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ - IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ - IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ - IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ - IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ }; struct iavf_vlan_filter { diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 02e07fe6a05284..b9b855a35fc85a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -802,10 +802,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, adapter->num_vlan_filters++; iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); } else if (f->state == IAVF_VLAN_REMOVE) { - /* Re-add the filter since we cannot tell whether the - * pending delete has already been processed by the PF. - * A duplicate add is harmless. - */ + /* DEL not yet sent to PF, cancel it */ + f->state = IAVF_VLAN_ACTIVE; + } else if (f->state == IAVF_VLAN_REMOVING) { + /* DEL already sent to PF, re-add after completion */ f->state = IAVF_VLAN_ADD; iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); @@ -836,37 +836,19 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) list_del(&f->list); kfree(f); adapter->num_vlan_filters--; - } else { + } else if (f->state != IAVF_VLAN_REMOVING) { f->state = IAVF_VLAN_REMOVE; iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_VLAN_FILTER); } + /* If REMOVING, DEL is already sent to PF; completion + * handler will free the filter when PF confirms. + */ } spin_unlock_bh(&adapter->mac_vlan_list_lock); } -/** - * iavf_restore_filters - * @adapter: board private structure - * - * Restore existing non MAC filters when VF netdev comes back up - **/ -static void iavf_restore_filters(struct iavf_adapter *adapter) -{ - struct iavf_vlan_filter *f; - - /* re-add all VLAN filters */ - spin_lock_bh(&adapter->mac_vlan_list_lock); - - list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->state == IAVF_VLAN_INACTIVE) - f->state = IAVF_VLAN_ADD; - } - - spin_unlock_bh(&adapter->mac_vlan_list_lock); - adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; -} /** * iavf_get_num_vlans_added - get number of VLANs added @@ -1289,13 +1271,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) } /** - * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF - * yet and mark other to be removed. + * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark + * others to be removed. * @adapter: board private structure **/ -static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) +static void iavf_clear_mac_filters(struct iavf_adapter *adapter) { - struct iavf_vlan_filter *vlf, *vlftmp; struct iavf_mac_filter *f, *ftmp; spin_lock_bh(&adapter->mac_vlan_list_lock); @@ -1314,11 +1295,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) } } - /* disable all VLAN filters */ - list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, - list) - vlf->state = IAVF_VLAN_DISABLE; - spin_unlock_bh(&adapter->mac_vlan_list_lock); } @@ -1414,7 +1390,7 @@ void iavf_down(struct iavf_adapter *adapter) iavf_napi_disable_all(adapter); iavf_irq_disable(adapter); - iavf_clear_mac_vlan_filters(adapter); + iavf_clear_mac_filters(adapter); iavf_clear_cloud_filters(adapter); iavf_clear_fdir_filters(adapter); iavf_clear_adv_rss_conf(adapter); @@ -1429,8 +1405,6 @@ void iavf_down(struct iavf_adapter *adapter) */ if (!list_empty(&adapter->mac_filter_list)) adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; - if (!list_empty(&adapter->vlan_filter_list)) - adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; if (!list_empty(&adapter->cloud_filter_list)) adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; if (!list_empty(&adapter->fdir_list_head)) @@ -4295,8 +4269,6 @@ static int iavf_open(struct net_device *netdev) spin_unlock_bh(&adapter->mac_vlan_list_lock); - /* Restore filters that were removed with IFF_DOWN */ - iavf_restore_filters(adapter); iavf_restore_fdir_filters(adapter); iavf_configure(adapter); diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index b95a4f903204b4..b6bc5609e118c4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -637,7 +637,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->state == IAVF_VLAN_IS_NEW) { + if (f->state == IAVF_VLAN_ADDING) { list_del(&f->list); kfree(f); adapter->num_vlan_filters--; @@ -702,7 +702,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) if (f->state == IAVF_VLAN_ADD) { vvfl->vlan_id[i] = f->vlan.vid; i++; - f->state = IAVF_VLAN_IS_NEW; + f->state = IAVF_VLAN_ADDING; if (i == count) break; } @@ -763,7 +763,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vlan->tpid = f->vlan.tpid; i++; - f->state = IAVF_VLAN_IS_NEW; + f->state = IAVF_VLAN_ADDING; } } @@ -800,22 +800,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - /* since VLAN capabilities are not allowed, we dont want to send - * a VLAN delete request because it will most likely fail and - * create unnecessary errors/noise, so just free the VLAN - * filters marked for removal to enable bailing out before - * sending a virtchnl message - */ if (f->state == IAVF_VLAN_REMOVE && !VLAN_FILTERING_ALLOWED(adapter)) { list_del(&f->list); kfree(f); adapter->num_vlan_filters--; - } else if (f->state == IAVF_VLAN_DISABLE && - !VLAN_FILTERING_ALLOWED(adapter)) { - f->state = IAVF_VLAN_INACTIVE; - } else if (f->state == IAVF_VLAN_REMOVE || - f->state == IAVF_VLAN_DISABLE) { + } else if (f->state == IAVF_VLAN_REMOVE) { count++; } } @@ -846,18 +836,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; - list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->state == IAVF_VLAN_DISABLE) { - vvfl->vlan_id[i] = f->vlan.vid; - f->state = IAVF_VLAN_INACTIVE; - i++; - if (i == count) - break; - } else if (f->state == IAVF_VLAN_REMOVE) { + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { vvfl->vlan_id[i] = f->vlan.vid; - list_del(&f->list); - kfree(f); - adapter->num_vlan_filters--; + f->state = IAVF_VLAN_REMOVING; i++; if (i == count) break; @@ -893,9 +875,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; - list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->state == IAVF_VLAN_DISABLE || - f->state == IAVF_VLAN_REMOVE) { + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support; struct virtchnl_vlan *vlan; @@ -909,13 +890,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; - if (f->state == IAVF_VLAN_DISABLE) { - f->state = IAVF_VLAN_INACTIVE; - } else { - list_del(&f->list); - kfree(f); - adapter->num_vlan_filters--; - } + f->state = IAVF_VLAN_REMOVING; i++; if (i == count) break; @@ -2040,10 +2015,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); wake_up(&adapter->vc_waitqueue); break; - case VIRTCHNL_OP_DEL_VLAN: - dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", - iavf_stat_str(&adapter->hw, v_retval)); - break; case VIRTCHNL_OP_DEL_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", iavf_stat_str(&adapter->hw, v_retval)); @@ -2515,17 +2486,42 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, spin_unlock_bh(&adapter->adv_rss_lock); } break; + case VIRTCHNL_OP_ADD_VLAN: case VIRTCHNL_OP_ADD_VLAN_V2: { struct iavf_vlan_filter *f; + if (v_retval) + break; + spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->state == IAVF_VLAN_IS_NEW) + if (f->state == IAVF_VLAN_ADDING) f->state = IAVF_VLAN_ACTIVE; } spin_unlock_bh(&adapter->mac_vlan_list_lock); } break; + case VIRTCHNL_OP_DEL_VLAN: + case VIRTCHNL_OP_DEL_VLAN_V2: { + struct iavf_vlan_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, + list) { + if (f->state == IAVF_VLAN_REMOVING) { + if (v_retval) { + /* PF rejected DEL, keep filter */ + f->state = IAVF_VLAN_ACTIVE; + } else { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; + } + } + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: /* PF enabled vlan strip on this VF. * Update netdev->features if needed to be in sync with ethtool. diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index eae4376c685952..4e110a008a257c 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -2364,8 +2364,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) ice_trace(xmit_frame_ring, tx_ring, skb); - if (unlikely(ipv6_hopopt_jumbo_remove(skb))) - goto out_drop; + /* record the location of the first descriptor for this packet */ + first = &tx_ring->tx_buf[tx_ring->next_to_use]; count = ice_xmit_desc_count(skb); if (ice_chk_linearize(skb, count)) { @@ -2392,8 +2392,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) offload.tx_ring = tx_ring; - /* record the location of the first descriptor for this packet */ - first = &tx_ring->tx_buf[tx_ring->next_to_use]; first->skb = skb; first->type = ICE_TX_BUF_SKB; first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); @@ -2455,6 +2453,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) out_drop: ice_trace(xmit_frame_ring_drop, tx_ring, skb); dev_kfree_skb_any(skb); + first->type = ICE_TX_BUF_EMPTY; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 58f9ac81dfbb2c..1463fee451efcc 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -787,7 +787,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) ice_vf_ctrl_invalidate_vsi(vf); ice_vf_pre_vsi_rebuild(vf); - ice_vf_rebuild_vsi(vf); + if (ice_vf_rebuild_vsi(vf)) { + dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", + vf->vf_id); + mutex_unlock(&vf->cfg_lock); + continue; + } ice_vf_post_vsi_rebuild(vf); mutex_unlock(&vf->cfg_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c index fd03aa4f47b5a9..004cf295eb2497 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ +#include + #include "mlx5_core.h" #include "en.h" #include "ipsec.h" @@ -591,7 +593,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, struct mlx5_wqe_aso_ctrl_seg *ctrl; struct mlx5e_hw_objs *res; struct mlx5_aso_wqe *wqe; - unsigned long expires; u8 ds_cnt; int ret; @@ -613,13 +614,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, mlx5e_ipsec_aso_copy(ctrl, data); mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); - expires = jiffies + msecs_to_jiffies(10); - do { - ret = mlx5_aso_poll_cq(aso->aso, false); - if (ret) - /* We are in atomic context */ - udelay(10); - } while (ret && time_is_after_jiffies(expires)); + read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10, + 10 * USEC_PER_MSEC, false, aso->aso, false); if (!ret) memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso)); spin_unlock_bh(&aso->lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 71749497ec27a3..97fa2095498cc8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -6093,6 +6093,14 @@ static int mlx5e_probe(struct auxiliary_device *adev, goto err_resume; } + /* mlx5e_fix_features() returns early when the device is not present + * to avoid dereferencing cleared priv during profile changes. + * This also causes it to be a no-op during register_netdev(), where + * the device is not yet present. + * Trigger an additional features update that will actually work. + */ + mlx5e_update_features(netdev); + mlx5e_dcbnl_init_app(priv); mlx5_core_uplink_netdev_set(mdev, netdev); mlx5e_params_print_info(mdev, &priv->channels.params); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c index 79470f198a62a6..9cf19446657c6c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c @@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, /* Full Island ID and channel bits overlap? */ ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); - if (ret) + if (ret) { + pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); return ret; + } /* The current address won't go where expected? */ - if (dest_island != -1 && dest_island != v) + if (dest_island != -1 && dest_island != v) { + pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", + __func__, dest_island, v); return -EINVAL; + } /* If dest_island was -1, we don't care where it goes. */ return 0; @@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, * the address but we can verify if the existing * contents will point to a valid island. */ - return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); iid_lsb = addr40 ? 34 : 26; @@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, return 0; case 1: if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) - return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); idx_lsb = addr40 ? 39 : 31; @@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, * be set before hand and with them select an island. * So we need to confirm that it's at least plausible. */ - return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); /* Make sure we compare against isldN values @@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, * iid<1> = addr<30> = channel<0> * channel<1> = addr<31> = Index */ - return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); isld[0] &= ~3; diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c index 3cd750820fdde3..d5a4b3cf945447 100644 --- a/drivers/net/ethernet/sfc/efx_devlink.c +++ b/drivers/net/ethernet/sfc/efx_devlink.c @@ -530,7 +530,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { netif_err(efx, drv, efx->net_dev, "mcdi MC_CMD_GET_VERSION failed\n"); - return rc; + return rc ?: -EIO; } /* Handle previous output */ diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 6cecdfa8631d72..1b8680923919d9 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -94,8 +94,8 @@ struct sixpack { unsigned char *xhead; /* next byte to XMIT */ int xleft; /* bytes left in XMIT queue */ - unsigned char raw_buf[4]; - unsigned char cooked_buf[400]; + u8 raw_buf[4]; + u8 cooked_buf[400]; unsigned int rx_count; unsigned int rx_count_cooked; @@ -113,8 +113,8 @@ struct sixpack { unsigned char slottime; unsigned char duplex; unsigned char led_state; - unsigned char status; - unsigned char status1; + u8 status; + u8 status1; unsigned char status2; unsigned char tx_enable; unsigned char tnc_state; @@ -126,7 +126,7 @@ struct sixpack { #define AX25_6PACK_HEADER_LEN 0 -static void sixpack_decode(struct sixpack *, const unsigned char[], int); +static void sixpack_decode(struct sixpack *, const u8 *, size_t); static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); /* @@ -331,7 +331,7 @@ static void sp_bump(struct sixpack *sp, char cmd) { struct sk_buff *skb; int count; - unsigned char *ptr; + u8 *ptr; count = sp->rcount + 1; @@ -397,7 +397,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count) { struct sixpack *sp; - int count1; if (!count) return; @@ -407,16 +406,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, return; /* Read the characters out of the buffer */ - count1 = count; - while (count) { - count--; + while (count--) { if (fp && *fp++) { if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) sp->dev->stats.rx_errors++; + cp++; continue; } + sixpack_decode(sp, cp, 1); + cp++; } - sixpack_decode(sp, cp, count1); tty_unthrottle(tty); } @@ -773,9 +772,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, /* decode 4 sixpack-encoded bytes into 3 data bytes */ -static void decode_data(struct sixpack *sp, unsigned char inbyte) +static void decode_data(struct sixpack *sp, u8 inbyte) { - unsigned char *buf; + u8 *buf; if (sp->rx_count != 3) { sp->raw_buf[sp->rx_count++] = inbyte; @@ -801,9 +800,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) /* identify and execute a 6pack priority command byte */ -static void decode_prio_command(struct sixpack *sp, unsigned char cmd) +static void decode_prio_command(struct sixpack *sp, u8 cmd) { - int actual; + ssize_t actual; if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ @@ -851,9 +850,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) /* identify and execute a standard 6pack command byte */ -static void decode_std_command(struct sixpack *sp, unsigned char cmd) +static void decode_std_command(struct sixpack *sp, u8 cmd) { - unsigned char checksum = 0, rest = 0; + u8 checksum = 0, rest = 0; short i; switch (cmd & SIXP_CMD_MASK) { /* normal command */ @@ -901,10 +900,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) /* decode a 6pack packet */ static void -sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count) +sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) { - unsigned char inbyte; - int count1; + size_t count1; + u8 inbyte; for (count1 = 0; count1 < count; count1++) { inbyte = pre_rbuff[count1]; diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c index 9a0b1fe4a93a88..05157492f99b44 100644 --- a/drivers/net/ipa/gsi.c +++ b/drivers/net/ipa/gsi.c @@ -2046,6 +2046,7 @@ static int gsi_ring_setup(struct gsi *gsi) count = reg_decode(reg, NUM_EV_PER_EE, val); } else { reg = gsi_reg(gsi, HW_PARAM_4); + val = ioread32(gsi->virt + reg_offset(reg)); count = reg_decode(reg, EV_PER_EE, val); } if (!count) { diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index da853353a5c72d..f5924142021d20 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -369,7 +369,7 @@ static void ipa_qtime_config(struct ipa *ipa) { const struct reg *reg; u32 offset; - u32 val; + u32 val = 0; /* Timer clock divider must be disabled when we change the rate */ reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); @@ -380,8 +380,8 @@ static void ipa_qtime_config(struct ipa *ipa) val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); val |= reg_bit(reg, DPL_TIMESTAMP_SEL); /* Configure tag and NAT Qtime timestamp resolution as well */ - val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); - val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); + val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); + val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); iowrite32(val, ipa->reg_virt + reg_offset(reg)); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 4e28fcbf13c74d..399c8deb35103b 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -351,6 +351,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, const struct macvlan_dev *src, struct sk_buff *skb) { + u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); struct sk_buff *nskb; int err = -ENOMEM; @@ -361,7 +362,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, MACVLAN_SKB_CB(nskb)->src = src; spin_lock(&port->bc_queue.lock); - if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { + if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { if (src) dev_hold(src->dev); __skb_queue_tail(&port->bc_queue, nskb); @@ -1686,6 +1687,7 @@ static size_t macvlan_get_size(const struct net_device *dev) + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */ ); } @@ -1732,7 +1734,8 @@ static int macvlan_fill_info(struct sk_buff *skb, } if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) goto nla_put_failure; - if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, + READ_ONCE(port->bc_queue_len_used))) goto nla_put_failure; if (port->bc_cutoff != 1 && nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) @@ -1792,7 +1795,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) if (vlan->bc_queue_len_req > max_bc_queue_len_req) max_bc_queue_len_req = vlan->bc_queue_len_req; } - port->bc_queue_len_used = max_bc_queue_len_req; + WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); } static int macvlan_device_event(struct notifier_block *unused, diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c index 1a7e7397ba75c6..8f0b4eb5b6f895 100644 --- a/drivers/net/mctp/mctp-i2c.c +++ b/drivers/net/mctp/mctp-i2c.c @@ -461,8 +461,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) u8 *pecp; int rc; - fs = mctp_i2c_get_tx_flow_state(midev, skb); - hdr = (void *)skb_mac_header(skb); /* Sanity check that packet contents matches skb length, * and can't exceed MCTP_I2C_BUFSZ @@ -474,6 +472,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) return; } + fs = mctp_i2c_get_tx_flow_state(midev, skb); + if (skb_tailroom(skb) >= 1) { /* Linear case with space, we can just append the PEC */ skb_put(skb, 1); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 9c2e71b9c0324e..fffffa3658d222 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -272,6 +272,18 @@ static struct netconsole_target *to_target(struct config_item *item) NULL; } +/* Get rid of possible trailing newline, returning the new length */ +static void trim_newline(char *s, size_t maxlen) +{ + size_t len; + + len = strnlen(s, maxlen); + if (!len) + return; + if (s[len - 1] == '\n') + s[len - 1] = '\0'; +} + /* * Attribute operations for netconsole_target. */ @@ -466,7 +478,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, size_t count) { struct netconsole_target *nt = to_target(item); - size_t len; + size_t len = count; + + /* Account for a trailing newline appended by tools like echo */ + if (len && buf[len - 1] == '\n') + len--; + if (len >= IFNAMSIZ) + return -ENAMETOOLONG; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -477,11 +495,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, } strscpy(nt->np.dev_name, buf, IFNAMSIZ); - - /* Get rid of possible trailing newline from echo(1) */ - len = strnlen(nt->np.dev_name, IFNAMSIZ); - if (nt->np.dev_name[len - 1] == '\n') - nt->np.dev_name[len - 1] = '\0'; + trim_newline(nt->np.dev_name, IFNAMSIZ); mutex_unlock(&dynamic_netconsole_mutex); return strnlen(buf, count); diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 2614d6509954c1..daec92570c2e3a 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -758,7 +758,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) skb->protocol = htons(ETH_P_IP); skb_set_network_header(skb, skb->len); - iph = skb_put(skb, sizeof(struct iphdr)); + iph = skb_put_zero(skb, sizeof(struct iphdr)); iph->protocol = IPPROTO_UDP; iph->saddr = in_aton("192.0.2.1"); iph->daddr = in_aton("198.51.100.1"); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 107880d13d219f..e49131cef9570e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -96,10 +96,7 @@ config ADIN1100_PHY Currently supports the: - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY -config AQUANTIA_PHY - tristate "Aquantia PHYs" - help - Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 +source "drivers/net/phy/aquantia/Kconfig" config AX88796B_PHY tristate "Asix PHYs" @@ -107,6 +104,14 @@ config AX88796B_PHY Currently supports the Asix Electronics PHY found in the X-Surf 100 AX88796B package. +config AX88796B_RUST_PHY + bool "Rust reference driver for Asix PHYs" + depends on RUST_PHYLIB_ABSTRACTIONS && AX88796B_PHY + help + Uses the Rust reference driver for Asix PHYs (ax88796b_rust.ko). + The features are equivalent. It supports the Asix Electronics PHY + found in the X-Surf 100 AX88796B package. + config BROADCOM_PHY tristate "Broadcom 54XX PHYs" select BCM_NET_PHYLIB @@ -321,12 +326,7 @@ config NCN26000_PHY Currently supports the NCN26000 10BASE-T1S Industrial PHY with MII interface. -config AT803X_PHY - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" - depends on REGULATOR - help - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal - QCA8337(Internal qca8k PHY) model +source "drivers/net/phy/qcom/Kconfig" config QSEMI_PHY tristate "Quality Semiconductor PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index c945ed9bd14b39..6e4493e26816da 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,13 +35,12 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o obj-$(CONFIG_AMD_PHY) += amd.o -aquantia-objs += aquantia_main.o -ifdef CONFIG_HWMON -aquantia-objs += aquantia_hwmon.o +obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ +ifdef CONFIG_AX88796B_RUST_PHY + obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o +else + obj-$(CONFIG_AX88796B_PHY) += ax88796b.o endif -obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o -obj-$(CONFIG_AT803X_PHY) += at803x.o -obj-$(CONFIG_AX88796B_PHY) += ax88796b.o obj-$(CONFIG_BCM54140_PHY) += bcm54140.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o @@ -86,6 +85,7 @@ obj-$(CONFIG_NCN26000_PHY) += ncn26000.o obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o +obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h deleted file mode 100644 index c684b65c642cc5..00000000000000 --- a/drivers/net/phy/aquantia.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* HWMON driver for Aquantia PHY - * - * Author: Nikita Yushchenko - * Author: Andrew Lunn - * Author: Heiner Kallweit - */ - -#include -#include - -#if IS_REACHABLE(CONFIG_HWMON) -int aqr_hwmon_probe(struct phy_device *phydev); -#else -static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } -#endif diff --git a/drivers/net/phy/aquantia/Kconfig b/drivers/net/phy/aquantia/Kconfig new file mode 100644 index 00000000000000..226146417a6a7a --- /dev/null +++ b/drivers/net/phy/aquantia/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +config AQUANTIA_PHY + tristate "Aquantia PHYs" + help + Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 diff --git a/drivers/net/phy/aquantia/Makefile b/drivers/net/phy/aquantia/Makefile new file mode 100644 index 00000000000000..346f350bc0846b --- /dev/null +++ b/drivers/net/phy/aquantia/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +aquantia-objs += aquantia_main.o +ifdef CONFIG_HWMON +aquantia-objs += aquantia_hwmon.o +endif +obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h new file mode 100644 index 00000000000000..c684b65c642cc5 --- /dev/null +++ b/drivers/net/phy/aquantia/aquantia.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* HWMON driver for Aquantia PHY + * + * Author: Nikita Yushchenko + * Author: Andrew Lunn + * Author: Heiner Kallweit + */ + +#include +#include + +#if IS_REACHABLE(CONFIG_HWMON) +int aqr_hwmon_probe(struct phy_device *phydev); +#else +static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; } +#endif diff --git a/drivers/net/phy/aquantia/aquantia_hwmon.c b/drivers/net/phy/aquantia/aquantia_hwmon.c new file mode 100644 index 00000000000000..0da451e46f6915 --- /dev/null +++ b/drivers/net/phy/aquantia/aquantia_hwmon.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* HWMON driver for Aquantia PHY + * + * Author: Nikita Yushchenko + * Author: Andrew Lunn + * Author: Heiner Kallweit + */ + +#include +#include +#include +#include + +#include "aquantia.h" + +/* Vendor specific 1, MDIO_MMD_VEND2 */ +#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421 +#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422 +#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423 +#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424 +#define VEND1_THERMAL_STAT1 0xc820 +#define VEND1_THERMAL_STAT2 0xc821 +#define VEND1_THERMAL_STAT2_VALID BIT(0) +#define VEND1_GENERAL_STAT1 0xc830 +#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14) +#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13) +#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12) +#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11) + +#if IS_REACHABLE(CONFIG_HWMON) + +static umode_t aqr_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_min_alarm: + case hwmon_temp_max_alarm: + case hwmon_temp_lcrit_alarm: + case hwmon_temp_crit_alarm: + return 0444; + case hwmon_temp_min: + case hwmon_temp_max: + case hwmon_temp_lcrit: + case hwmon_temp_crit: + return 0644; + default: + return 0; + } +} + +static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value) +{ + int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); + + if (temp < 0) + return temp; + + /* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */ + *value = (s16)temp * 1000 / 256; + + return 0; +} + +static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value) +{ + int temp; + + if (value >= 128000 || value < -128000) + return -ERANGE; + + temp = value * 256 / 1000; + + /* temp is in s16 range and we're interested in lower 16 bits only */ + return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp); +} + +static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit) +{ + int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); + + if (val < 0) + return val; + + return !!(val & bit); +} + +static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value) +{ + int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit); + + if (val < 0) + return val; + + *value = val; + + return 0; +} + +static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *value) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + int reg; + + if (type != hwmon_temp) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_temp_input: + reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2, + VEND1_THERMAL_STAT2_VALID); + if (reg < 0) + return reg; + if (!reg) + return -EBUSY; + + return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value); + + case hwmon_temp_lcrit: + return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, + value); + case hwmon_temp_min: + return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, + value); + case hwmon_temp_max: + return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, + value); + case hwmon_temp_crit: + return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, + value); + case hwmon_temp_lcrit_alarm: + return aqr_hwmon_status1(phydev, + VEND1_GENERAL_STAT1_LOW_TEMP_FAIL, + value); + case hwmon_temp_min_alarm: + return aqr_hwmon_status1(phydev, + VEND1_GENERAL_STAT1_LOW_TEMP_WARN, + value); + case hwmon_temp_max_alarm: + return aqr_hwmon_status1(phydev, + VEND1_GENERAL_STAT1_HIGH_TEMP_WARN, + value); + case hwmon_temp_crit_alarm: + return aqr_hwmon_status1(phydev, + VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL, + value); + default: + return -EOPNOTSUPP; + } +} + +static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long value) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + + if (type != hwmon_temp) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_temp_lcrit: + return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, + value); + case hwmon_temp_min: + return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, + value); + case hwmon_temp_max: + return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, + value); + case hwmon_temp_crit: + return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, + value); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_ops aqr_hwmon_ops = { + .is_visible = aqr_hwmon_is_visible, + .read = aqr_hwmon_read, + .write = aqr_hwmon_write, +}; + +static u32 aqr_hwmon_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0, +}; + +static const struct hwmon_channel_info aqr_hwmon_chip = { + .type = hwmon_chip, + .config = aqr_hwmon_chip_config, +}; + +static u32 aqr_hwmon_temp_config[] = { + HWMON_T_INPUT | + HWMON_T_MAX | HWMON_T_MIN | + HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | + HWMON_T_CRIT | HWMON_T_LCRIT | + HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM, + 0, +}; + +static const struct hwmon_channel_info aqr_hwmon_temp = { + .type = hwmon_temp, + .config = aqr_hwmon_temp_config, +}; + +static const struct hwmon_channel_info * const aqr_hwmon_info[] = { + &aqr_hwmon_chip, + &aqr_hwmon_temp, + NULL, +}; + +static const struct hwmon_chip_info aqr_hwmon_chip_info = { + .ops = &aqr_hwmon_ops, + .info = aqr_hwmon_info, +}; + +int aqr_hwmon_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct device *hwmon_dev; + char *hwmon_name; + int i, j; + + hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); + if (!hwmon_name) + return -ENOMEM; + + for (i = j = 0; hwmon_name[i]; i++) { + if (isalnum(hwmon_name[i])) { + if (i != j) + hwmon_name[j] = hwmon_name[i]; + j++; + } + } + hwmon_name[j] = '\0'; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name, + phydev, &aqr_hwmon_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +#endif diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c new file mode 100644 index 00000000000000..334a6904ca5a37 --- /dev/null +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -0,0 +1,882 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Aquantia PHY + * + * Author: Shaohui Xie + * + * Copyright 2015 Freescale Semiconductor, Inc. + */ + +#include +#include +#include +#include +#include + +#include "aquantia.h" + +#define PHY_ID_AQ1202 0x03a1b445 +#define PHY_ID_AQ2104 0x03a1b460 +#define PHY_ID_AQR105 0x03a1b4a2 +#define PHY_ID_AQR106 0x03a1b4d0 +#define PHY_ID_AQR107 0x03a1b4e0 +#define PHY_ID_AQCS109 0x03a1b5c2 +#define PHY_ID_AQR405 0x03a1b4b0 +#define PHY_ID_AQR112 0x03a1b662 +#define PHY_ID_AQR412 0x03a1b712 +#define PHY_ID_AQR113C 0x31c31c12 + +#define MDIO_PHYXS_VEND_IF_STATUS 0xe812 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX 1 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10 + +#define MDIO_AN_VEND_PROV 0xc400 +#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15) +#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14) +#define MDIO_AN_VEND_PROV_5000BASET_FULL BIT(11) +#define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10) +#define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4) +#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0) +#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 + +#define MDIO_AN_TX_VEND_STATUS1 0xc800 +#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1) +#define MDIO_AN_TX_VEND_STATUS1_10BASET 0 +#define MDIO_AN_TX_VEND_STATUS1_100BASETX 1 +#define MDIO_AN_TX_VEND_STATUS1_1000BASET 2 +#define MDIO_AN_TX_VEND_STATUS1_10GBASET 3 +#define MDIO_AN_TX_VEND_STATUS1_2500BASET 4 +#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5 +#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0) + +#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00 +#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1) + +#define MDIO_AN_TX_VEND_INT_STATUS2 0xcc01 +#define MDIO_AN_TX_VEND_INT_STATUS2_MASK BIT(0) + +#define MDIO_AN_TX_VEND_INT_MASK2 0xd401 +#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) + +#define MDIO_AN_RX_LP_STAT1 0xe820 +#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) +#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) +#define MDIO_AN_RX_LP_STAT1_SHORT_REACH BIT(13) +#define MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT BIT(12) +#define MDIO_AN_RX_LP_STAT1_AQ_PHY BIT(2) + +#define MDIO_AN_RX_LP_STAT4 0xe823 +#define MDIO_AN_RX_LP_STAT4_FW_MAJOR GENMASK(15, 8) +#define MDIO_AN_RX_LP_STAT4_FW_MINOR GENMASK(7, 0) + +#define MDIO_AN_RX_VEND_STAT3 0xe832 +#define MDIO_AN_RX_VEND_STAT3_AFR BIT(0) + +/* MDIO_MMD_C22EXT */ +#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292 +#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294 +#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297 +#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313 +#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315 +#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317 +#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318 +#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319 +#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a +#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b + +/* Vendor specific 1, MDIO_MMD_VEND1 */ +#define VEND1_GLOBAL_FW_ID 0x0020 +#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8) +#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0) + +#define VEND1_GLOBAL_GEN_STAT2 0xc831 +#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15) + +/* The following registers all have similar layouts; first the registers... */ +#define VEND1_GLOBAL_CFG_10M 0x0310 +#define VEND1_GLOBAL_CFG_100M 0x031b +#define VEND1_GLOBAL_CFG_1G 0x031c +#define VEND1_GLOBAL_CFG_2_5G 0x031d +#define VEND1_GLOBAL_CFG_5G 0x031e +#define VEND1_GLOBAL_CFG_10G 0x031f +/* ...and now the fields */ +#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7) +#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0 +#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1 +#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2 + +#define VEND1_GLOBAL_RSVD_STAT1 0xc885 +#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4) +#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0) + +#define VEND1_GLOBAL_RSVD_STAT9 0xc88d +#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0) +#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23 + +#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00 +#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01 + +#define VEND1_GLOBAL_INT_STD_MASK 0xff00 +#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15) +#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14) +#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13) +#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12) +#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11) +#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10) +#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9) +#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8) +#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7) +#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6) +#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0) + +#define VEND1_GLOBAL_INT_VEND_MASK 0xff01 +#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15) +#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14) +#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13) +#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12) +#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11) +#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2) +#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) +#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) + +/* Sleep and timeout for checking if the Processor-Intensive + * MDIO operation is finished + */ +#define AQR107_OP_IN_PROG_SLEEP 1000 +#define AQR107_OP_IN_PROG_TIMEOUT 100000 + +struct aqr107_hw_stat { + const char *name; + int reg; + int size; +}; + +#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s } +static const struct aqr107_hw_stat aqr107_hw_stats[] = { + SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26), + SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26), + SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8), + SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26), + SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26), + SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8), + SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8), + SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8), + SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16), + SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22), +}; +#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) + +struct aqr107_priv { + u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; +}; + +static int aqr107_get_sset_count(struct phy_device *phydev) +{ + return AQR107_SGMII_STAT_SZ; +} + +static void aqr107_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) + strscpy(data + i * ETH_GSTRING_LEN, aqr107_hw_stats[i].name, + ETH_GSTRING_LEN); +} + +static u64 aqr107_get_stat(struct phy_device *phydev, int index) +{ + const struct aqr107_hw_stat *stat = aqr107_hw_stats + index; + int len_l = min(stat->size, 16); + int len_h = stat->size - len_l; + u64 ret; + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg); + if (val < 0) + return U64_MAX; + + ret = val & GENMASK(len_l - 1, 0); + if (len_h) { + val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1); + if (val < 0) + return U64_MAX; + + ret += (val & GENMASK(len_h - 1, 0)) << 16; + } + + return ret; +} + +static void aqr107_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + struct aqr107_priv *priv = phydev->priv; + u64 val; + int i; + + for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) { + val = aqr107_get_stat(phydev, i); + if (val == U64_MAX) + phydev_err(phydev, "Reading HW Statistics failed for %s\n", + aqr107_hw_stats[i].name); + else + priv->sgmii_stats[i] += val; + + data[i] = priv->sgmii_stats[i]; + } +} + +static int aqr_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u16 reg; + int ret; + + if (phydev->autoneg == AUTONEG_DISABLE) + return genphy_c45_pma_setup_forced(phydev); + + ret = genphy_c45_an_config_aneg(phydev); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + /* Clause 45 has no standardized support for 1000BaseT, therefore + * use vendor registers for this mode. + */ + reg = 0; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_1000BASET_FULL; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_1000BASET_HALF; + + /* Handle the case when the 2.5G and 5G speeds are not advertised */ + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_2500BASET_FULL; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + phydev->advertising)) + reg |= MDIO_AN_VEND_PROV_5000BASET_FULL; + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, + MDIO_AN_VEND_PROV_1000BASET_HALF | + MDIO_AN_VEND_PROV_1000BASET_FULL | + MDIO_AN_VEND_PROV_2500BASET_FULL | + MDIO_AN_VEND_PROV_5000BASET_FULL, reg); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + return genphy_c45_check_and_restart_aneg(phydev, changed); +} + +static int aqr_config_intr(struct phy_device *phydev) +{ + bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; + int err; + + if (en) { + /* Clear any pending interrupts before enabling them */ + err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2); + if (err < 0) + return err; + } + + err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2, + en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK, + en ? VEND1_GLOBAL_INT_STD_MASK_ALL : 0); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK, + en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 | + VEND1_GLOBAL_INT_VEND_MASK_AN : 0); + if (err < 0) + return err; + + if (!en) { + /* Clear any pending interrupts after we have disabled them */ + err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2); + if (err < 0) + return err; + } + + return 0; +} + +static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_AN, + MDIO_AN_TX_VEND_INT_STATUS2); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MDIO_AN_TX_VEND_INT_STATUS2_MASK)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static int aqr_read_status(struct phy_device *phydev) +{ + int val; + + if (phydev->autoneg == AUTONEG_ENABLE) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); + if (val < 0) + return val; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->lp_advertising, + val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + phydev->lp_advertising, + val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF); + } + + return genphy_c45_read_status(phydev); +} + +static int aqr107_read_rate(struct phy_device *phydev) +{ + u32 config_reg; + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); + if (val < 0) + return val; + + if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) { + case MDIO_AN_TX_VEND_STATUS1_10BASET: + phydev->speed = SPEED_10; + config_reg = VEND1_GLOBAL_CFG_10M; + break; + case MDIO_AN_TX_VEND_STATUS1_100BASETX: + phydev->speed = SPEED_100; + config_reg = VEND1_GLOBAL_CFG_100M; + break; + case MDIO_AN_TX_VEND_STATUS1_1000BASET: + phydev->speed = SPEED_1000; + config_reg = VEND1_GLOBAL_CFG_1G; + break; + case MDIO_AN_TX_VEND_STATUS1_2500BASET: + phydev->speed = SPEED_2500; + config_reg = VEND1_GLOBAL_CFG_2_5G; + break; + case MDIO_AN_TX_VEND_STATUS1_5000BASET: + phydev->speed = SPEED_5000; + config_reg = VEND1_GLOBAL_CFG_5G; + break; + case MDIO_AN_TX_VEND_STATUS1_10GBASET: + phydev->speed = SPEED_10000; + config_reg = VEND1_GLOBAL_CFG_10G; + break; + default: + phydev->speed = SPEED_UNKNOWN; + return 0; + } + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg); + if (val < 0) + return val; + + if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) == + VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE) + phydev->rate_matching = RATE_MATCH_PAUSE; + else + phydev->rate_matching = RATE_MATCH_NONE; + + return 0; +} + +static int aqr107_read_status(struct phy_device *phydev) +{ + int val, ret; + + ret = aqr_read_status(phydev); + if (ret) + return ret; + + if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) + return 0; + + val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); + if (val < 0) + return val; + + switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: + phydev->interface = PHY_INTERFACE_MODE_10GKR; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX: + phydev->interface = PHY_INTERFACE_MODE_1000BASEKX; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI: + phydev->interface = PHY_INTERFACE_MODE_10GBASER; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII: + phydev->interface = PHY_INTERFACE_MODE_USXGMII; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI: + phydev->interface = PHY_INTERFACE_MODE_XAUI; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII: + phydev->interface = PHY_INTERFACE_MODE_SGMII; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI: + phydev->interface = PHY_INTERFACE_MODE_RXAUI; + break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + break; + default: + phydev->interface = PHY_INTERFACE_MODE_NA; + break; + } + + /* Read possibly downshifted rate from vendor register */ + return aqr107_read_rate(phydev); +} + +static int aqr107_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV); + if (val < 0) + return val; + + enable = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_EN, val); + cnt = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); + + *data = enable && cnt ? cnt : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int val = 0; + + if (!FIELD_FIT(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt)) + return -E2BIG; + + if (cnt != DOWNSHIFT_DEV_DISABLE) { + val = MDIO_AN_VEND_PROV_DOWNSHIFT_EN; + val |= FIELD_PREP(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt); + } + + return phy_modify_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, + MDIO_AN_VEND_PROV_DOWNSHIFT_EN | + MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); +} + +static int aqr107_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return aqr107_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int aqr107_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return aqr107_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +/* If we configure settings whilst firmware is still initializing the chip, + * then these settings may be overwritten. Therefore make sure chip + * initialization has completed. Use presence of the firmware ID as + * indicator for initialization having completed. + * The chip also provides a "reset completed" bit, but it's cleared after + * read. Therefore function would time out if called again. + */ +static int aqr107_wait_reset_complete(struct phy_device *phydev) +{ + int val; + + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_FW_ID, val, val != 0, + 20000, 2000000, false); +} + +static void aqr107_chip_info(struct phy_device *phydev) +{ + u8 fw_major, fw_minor, build_id, prov_id; + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); + if (val < 0) + return; + + fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val); + fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val); + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1); + if (val < 0) + return; + + build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); + prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); + + phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n", + fw_major, fw_minor, build_id, prov_id); +} + +static int aqr107_config_init(struct phy_device *phydev) +{ + int ret; + + /* Check that the PHY interface type is compatible */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + phydev->interface != PHY_INTERFACE_MODE_1000BASEKX && + phydev->interface != PHY_INTERFACE_MODE_2500BASEX && + phydev->interface != PHY_INTERFACE_MODE_XGMII && + phydev->interface != PHY_INTERFACE_MODE_USXGMII && + phydev->interface != PHY_INTERFACE_MODE_10GKR && + phydev->interface != PHY_INTERFACE_MODE_10GBASER && + phydev->interface != PHY_INTERFACE_MODE_XAUI && + phydev->interface != PHY_INTERFACE_MODE_RXAUI) + return -ENODEV; + + WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII, + "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n"); + + ret = aqr107_wait_reset_complete(phydev); + if (!ret) + aqr107_chip_info(phydev); + + return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); +} + +static int aqcs109_config_init(struct phy_device *phydev) +{ + int ret; + + /* Check that the PHY interface type is compatible */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + phydev->interface != PHY_INTERFACE_MODE_2500BASEX) + return -ENODEV; + + ret = aqr107_wait_reset_complete(phydev); + if (!ret) + aqr107_chip_info(phydev); + + /* AQCS109 belongs to a chip family partially supporting 10G and 5G. + * PMA speed ability bits are the same for all members of the family, + * AQCS109 however supports speeds up to 2.5G only. + */ + phy_set_max_speed(phydev, SPEED_2500); + + return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); +} + +static void aqr107_link_change_notify(struct phy_device *phydev) +{ + u8 fw_major, fw_minor; + bool downshift, short_reach, afr; + int mode, val; + + if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE) + return; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); + /* call failed or link partner is no Aquantia PHY */ + if (val < 0 || !(val & MDIO_AN_RX_LP_STAT1_AQ_PHY)) + return; + + short_reach = val & MDIO_AN_RX_LP_STAT1_SHORT_REACH; + downshift = val & MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT4); + if (val < 0) + return; + + fw_major = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MAJOR, val); + fw_minor = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MINOR, val); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_VEND_STAT3); + if (val < 0) + return; + + afr = val & MDIO_AN_RX_VEND_STAT3_AFR; + + phydev_dbg(phydev, "Link partner is Aquantia PHY, FW %u.%u%s%s%s\n", + fw_major, fw_minor, + short_reach ? ", short reach mode" : "", + downshift ? ", fast-retrain downshift advertised" : "", + afr ? ", fast reframe advertised" : ""); + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT9); + if (val < 0) + return; + + mode = FIELD_GET(VEND1_GLOBAL_RSVD_STAT9_MODE, val); + if (mode == VEND1_GLOBAL_RSVD_STAT9_1000BT2) + phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n"); +} + +static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) +{ + int val, err; + + /* The datasheet notes to wait at least 1ms after issuing a + * processor intensive operation before checking. + * We cannot use the 'sleep_before_read' parameter of read_poll_timeout + * because that just determines the maximum time slept, not the minimum. + */ + usleep_range(1000, 5000); + + err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + VEND1_GLOBAL_GEN_STAT2, val, + !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), + AQR107_OP_IN_PROG_SLEEP, + AQR107_OP_IN_PROG_TIMEOUT, false); + if (err) { + phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); + return err; + } + + return 0; +} + +static int aqr107_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) +{ + if (iface == PHY_INTERFACE_MODE_10GBASER || + iface == PHY_INTERFACE_MODE_2500BASEX || + iface == PHY_INTERFACE_MODE_NA) + return RATE_MATCH_PAUSE; + return RATE_MATCH_NONE; +} + +static int aqr107_suspend(struct phy_device *phydev) +{ + int err; + + err = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, + MDIO_CTRL1_LPOWER); + if (err) + return err; + + return aqr107_wait_processor_intensive_op(phydev); +} + +static int aqr107_resume(struct phy_device *phydev) +{ + int err; + + err = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, + MDIO_CTRL1_LPOWER); + if (err) + return err; + + return aqr107_wait_processor_intensive_op(phydev); +} + +static int aqr107_probe(struct phy_device *phydev) +{ + phydev->priv = devm_kzalloc(&phydev->mdio.dev, + sizeof(struct aqr107_priv), GFP_KERNEL); + if (!phydev->priv) + return -ENOMEM; + + return aqr_hwmon_probe(phydev); +} + +static struct phy_driver aqr_driver[] = { +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQ1202), + .name = "Aquantia AQ1202", + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQ2104), + .name = "Aquantia AQ2104", + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR105), + .name = "Aquantia AQR105", + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, + .suspend = aqr107_suspend, + .resume = aqr107_resume, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR106), + .name = "Aquantia AQR106", + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR107), + .name = "Aquantia AQR107", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr107_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), + .name = "Aquantia AQCS109", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqcs109_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR405), + .name = "Aquantia AQR405", + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR112), + .name = "Aquantia AQR112", + .probe = aqr107_probe, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .read_status = aqr107_read_status, + .get_rate_matching = aqr107_get_rate_matching, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR412), + .name = "Aquantia AQR412", + .probe = aqr107_probe, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .read_status = aqr107_read_status, + .get_rate_matching = aqr107_get_rate_matching, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), + .name = "Aquantia AQR113C", + .probe = aqr107_probe, + .get_rate_matching = aqr107_get_rate_matching, + .config_init = aqr107_config_init, + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, + .resume = aqr107_resume, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, +}, +}; + +module_phy_driver(aqr_driver); + +static struct mdio_device_id __maybe_unused aqr_tbl[] = { + { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, aqr_tbl); + +MODULE_DESCRIPTION("Aquantia PHY driver"); +MODULE_AUTHOR("Shaohui Xie "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/aquantia_hwmon.c b/drivers/net/phy/aquantia_hwmon.c deleted file mode 100644 index 0da451e46f6915..00000000000000 --- a/drivers/net/phy/aquantia_hwmon.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* HWMON driver for Aquantia PHY - * - * Author: Nikita Yushchenko - * Author: Andrew Lunn - * Author: Heiner Kallweit - */ - -#include -#include -#include -#include - -#include "aquantia.h" - -/* Vendor specific 1, MDIO_MMD_VEND2 */ -#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421 -#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422 -#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423 -#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424 -#define VEND1_THERMAL_STAT1 0xc820 -#define VEND1_THERMAL_STAT2 0xc821 -#define VEND1_THERMAL_STAT2_VALID BIT(0) -#define VEND1_GENERAL_STAT1 0xc830 -#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14) -#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13) -#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12) -#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11) - -#if IS_REACHABLE(CONFIG_HWMON) - -static umode_t aqr_hwmon_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - if (type != hwmon_temp) - return 0; - - switch (attr) { - case hwmon_temp_input: - case hwmon_temp_min_alarm: - case hwmon_temp_max_alarm: - case hwmon_temp_lcrit_alarm: - case hwmon_temp_crit_alarm: - return 0444; - case hwmon_temp_min: - case hwmon_temp_max: - case hwmon_temp_lcrit: - case hwmon_temp_crit: - return 0644; - default: - return 0; - } -} - -static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value) -{ - int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); - - if (temp < 0) - return temp; - - /* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */ - *value = (s16)temp * 1000 / 256; - - return 0; -} - -static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value) -{ - int temp; - - if (value >= 128000 || value < -128000) - return -ERANGE; - - temp = value * 256 / 1000; - - /* temp is in s16 range and we're interested in lower 16 bits only */ - return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp); -} - -static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit) -{ - int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); - - if (val < 0) - return val; - - return !!(val & bit); -} - -static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value) -{ - int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit); - - if (val < 0) - return val; - - *value = val; - - return 0; -} - -static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *value) -{ - struct phy_device *phydev = dev_get_drvdata(dev); - int reg; - - if (type != hwmon_temp) - return -EOPNOTSUPP; - - switch (attr) { - case hwmon_temp_input: - reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2, - VEND1_THERMAL_STAT2_VALID); - if (reg < 0) - return reg; - if (!reg) - return -EBUSY; - - return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value); - - case hwmon_temp_lcrit: - return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, - value); - case hwmon_temp_min: - return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, - value); - case hwmon_temp_max: - return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, - value); - case hwmon_temp_crit: - return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, - value); - case hwmon_temp_lcrit_alarm: - return aqr_hwmon_status1(phydev, - VEND1_GENERAL_STAT1_LOW_TEMP_FAIL, - value); - case hwmon_temp_min_alarm: - return aqr_hwmon_status1(phydev, - VEND1_GENERAL_STAT1_LOW_TEMP_WARN, - value); - case hwmon_temp_max_alarm: - return aqr_hwmon_status1(phydev, - VEND1_GENERAL_STAT1_HIGH_TEMP_WARN, - value); - case hwmon_temp_crit_alarm: - return aqr_hwmon_status1(phydev, - VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL, - value); - default: - return -EOPNOTSUPP; - } -} - -static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long value) -{ - struct phy_device *phydev = dev_get_drvdata(dev); - - if (type != hwmon_temp) - return -EOPNOTSUPP; - - switch (attr) { - case hwmon_temp_lcrit: - return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, - value); - case hwmon_temp_min: - return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, - value); - case hwmon_temp_max: - return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, - value); - case hwmon_temp_crit: - return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, - value); - default: - return -EOPNOTSUPP; - } -} - -static const struct hwmon_ops aqr_hwmon_ops = { - .is_visible = aqr_hwmon_is_visible, - .read = aqr_hwmon_read, - .write = aqr_hwmon_write, -}; - -static u32 aqr_hwmon_chip_config[] = { - HWMON_C_REGISTER_TZ, - 0, -}; - -static const struct hwmon_channel_info aqr_hwmon_chip = { - .type = hwmon_chip, - .config = aqr_hwmon_chip_config, -}; - -static u32 aqr_hwmon_temp_config[] = { - HWMON_T_INPUT | - HWMON_T_MAX | HWMON_T_MIN | - HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | - HWMON_T_CRIT | HWMON_T_LCRIT | - HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM, - 0, -}; - -static const struct hwmon_channel_info aqr_hwmon_temp = { - .type = hwmon_temp, - .config = aqr_hwmon_temp_config, -}; - -static const struct hwmon_channel_info * const aqr_hwmon_info[] = { - &aqr_hwmon_chip, - &aqr_hwmon_temp, - NULL, -}; - -static const struct hwmon_chip_info aqr_hwmon_chip_info = { - .ops = &aqr_hwmon_ops, - .info = aqr_hwmon_info, -}; - -int aqr_hwmon_probe(struct phy_device *phydev) -{ - struct device *dev = &phydev->mdio.dev; - struct device *hwmon_dev; - char *hwmon_name; - int i, j; - - hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); - if (!hwmon_name) - return -ENOMEM; - - for (i = j = 0; hwmon_name[i]; i++) { - if (isalnum(hwmon_name[i])) { - if (i != j) - hwmon_name[j] = hwmon_name[i]; - j++; - } - } - hwmon_name[j] = '\0'; - - hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name, - phydev, &aqr_hwmon_chip_info, NULL); - - return PTR_ERR_OR_ZERO(hwmon_dev); -} - -#endif diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c deleted file mode 100644 index 334a6904ca5a37..00000000000000 --- a/drivers/net/phy/aquantia_main.c +++ /dev/null @@ -1,882 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Driver for Aquantia PHY - * - * Author: Shaohui Xie - * - * Copyright 2015 Freescale Semiconductor, Inc. - */ - -#include -#include -#include -#include -#include - -#include "aquantia.h" - -#define PHY_ID_AQ1202 0x03a1b445 -#define PHY_ID_AQ2104 0x03a1b460 -#define PHY_ID_AQR105 0x03a1b4a2 -#define PHY_ID_AQR106 0x03a1b4d0 -#define PHY_ID_AQR107 0x03a1b4e0 -#define PHY_ID_AQCS109 0x03a1b5c2 -#define PHY_ID_AQR405 0x03a1b4b0 -#define PHY_ID_AQR112 0x03a1b662 -#define PHY_ID_AQR412 0x03a1b712 -#define PHY_ID_AQR113C 0x31c31c12 - -#define MDIO_PHYXS_VEND_IF_STATUS 0xe812 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX 1 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7 -#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10 - -#define MDIO_AN_VEND_PROV 0xc400 -#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15) -#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14) -#define MDIO_AN_VEND_PROV_5000BASET_FULL BIT(11) -#define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10) -#define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4) -#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0) -#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 - -#define MDIO_AN_TX_VEND_STATUS1 0xc800 -#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1) -#define MDIO_AN_TX_VEND_STATUS1_10BASET 0 -#define MDIO_AN_TX_VEND_STATUS1_100BASETX 1 -#define MDIO_AN_TX_VEND_STATUS1_1000BASET 2 -#define MDIO_AN_TX_VEND_STATUS1_10GBASET 3 -#define MDIO_AN_TX_VEND_STATUS1_2500BASET 4 -#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5 -#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0) - -#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00 -#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1) - -#define MDIO_AN_TX_VEND_INT_STATUS2 0xcc01 -#define MDIO_AN_TX_VEND_INT_STATUS2_MASK BIT(0) - -#define MDIO_AN_TX_VEND_INT_MASK2 0xd401 -#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) - -#define MDIO_AN_RX_LP_STAT1 0xe820 -#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) -#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) -#define MDIO_AN_RX_LP_STAT1_SHORT_REACH BIT(13) -#define MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT BIT(12) -#define MDIO_AN_RX_LP_STAT1_AQ_PHY BIT(2) - -#define MDIO_AN_RX_LP_STAT4 0xe823 -#define MDIO_AN_RX_LP_STAT4_FW_MAJOR GENMASK(15, 8) -#define MDIO_AN_RX_LP_STAT4_FW_MINOR GENMASK(7, 0) - -#define MDIO_AN_RX_VEND_STAT3 0xe832 -#define MDIO_AN_RX_VEND_STAT3_AFR BIT(0) - -/* MDIO_MMD_C22EXT */ -#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292 -#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294 -#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297 -#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313 -#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315 -#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317 -#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318 -#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319 -#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a -#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b - -/* Vendor specific 1, MDIO_MMD_VEND1 */ -#define VEND1_GLOBAL_FW_ID 0x0020 -#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8) -#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0) - -#define VEND1_GLOBAL_GEN_STAT2 0xc831 -#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15) - -/* The following registers all have similar layouts; first the registers... */ -#define VEND1_GLOBAL_CFG_10M 0x0310 -#define VEND1_GLOBAL_CFG_100M 0x031b -#define VEND1_GLOBAL_CFG_1G 0x031c -#define VEND1_GLOBAL_CFG_2_5G 0x031d -#define VEND1_GLOBAL_CFG_5G 0x031e -#define VEND1_GLOBAL_CFG_10G 0x031f -/* ...and now the fields */ -#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7) -#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0 -#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1 -#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2 - -#define VEND1_GLOBAL_RSVD_STAT1 0xc885 -#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4) -#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0) - -#define VEND1_GLOBAL_RSVD_STAT9 0xc88d -#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0) -#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23 - -#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00 -#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01 - -#define VEND1_GLOBAL_INT_STD_MASK 0xff00 -#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15) -#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14) -#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13) -#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12) -#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11) -#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10) -#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9) -#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8) -#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7) -#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6) -#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0) - -#define VEND1_GLOBAL_INT_VEND_MASK 0xff01 -#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15) -#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14) -#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13) -#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12) -#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11) -#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2) -#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) -#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) - -/* Sleep and timeout for checking if the Processor-Intensive - * MDIO operation is finished - */ -#define AQR107_OP_IN_PROG_SLEEP 1000 -#define AQR107_OP_IN_PROG_TIMEOUT 100000 - -struct aqr107_hw_stat { - const char *name; - int reg; - int size; -}; - -#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s } -static const struct aqr107_hw_stat aqr107_hw_stats[] = { - SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26), - SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26), - SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8), - SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26), - SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26), - SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8), - SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8), - SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8), - SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16), - SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22), -}; -#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) - -struct aqr107_priv { - u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; -}; - -static int aqr107_get_sset_count(struct phy_device *phydev) -{ - return AQR107_SGMII_STAT_SZ; -} - -static void aqr107_get_strings(struct phy_device *phydev, u8 *data) -{ - int i; - - for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) - strscpy(data + i * ETH_GSTRING_LEN, aqr107_hw_stats[i].name, - ETH_GSTRING_LEN); -} - -static u64 aqr107_get_stat(struct phy_device *phydev, int index) -{ - const struct aqr107_hw_stat *stat = aqr107_hw_stats + index; - int len_l = min(stat->size, 16); - int len_h = stat->size - len_l; - u64 ret; - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg); - if (val < 0) - return U64_MAX; - - ret = val & GENMASK(len_l - 1, 0); - if (len_h) { - val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1); - if (val < 0) - return U64_MAX; - - ret += (val & GENMASK(len_h - 1, 0)) << 16; - } - - return ret; -} - -static void aqr107_get_stats(struct phy_device *phydev, - struct ethtool_stats *stats, u64 *data) -{ - struct aqr107_priv *priv = phydev->priv; - u64 val; - int i; - - for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) { - val = aqr107_get_stat(phydev, i); - if (val == U64_MAX) - phydev_err(phydev, "Reading HW Statistics failed for %s\n", - aqr107_hw_stats[i].name); - else - priv->sgmii_stats[i] += val; - - data[i] = priv->sgmii_stats[i]; - } -} - -static int aqr_config_aneg(struct phy_device *phydev) -{ - bool changed = false; - u16 reg; - int ret; - - if (phydev->autoneg == AUTONEG_DISABLE) - return genphy_c45_pma_setup_forced(phydev); - - ret = genphy_c45_an_config_aneg(phydev); - if (ret < 0) - return ret; - if (ret > 0) - changed = true; - - /* Clause 45 has no standardized support for 1000BaseT, therefore - * use vendor registers for this mode. - */ - reg = 0; - if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, - phydev->advertising)) - reg |= MDIO_AN_VEND_PROV_1000BASET_FULL; - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, - phydev->advertising)) - reg |= MDIO_AN_VEND_PROV_1000BASET_HALF; - - /* Handle the case when the 2.5G and 5G speeds are not advertised */ - if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, - phydev->advertising)) - reg |= MDIO_AN_VEND_PROV_2500BASET_FULL; - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, - phydev->advertising)) - reg |= MDIO_AN_VEND_PROV_5000BASET_FULL; - - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, - MDIO_AN_VEND_PROV_1000BASET_HALF | - MDIO_AN_VEND_PROV_1000BASET_FULL | - MDIO_AN_VEND_PROV_2500BASET_FULL | - MDIO_AN_VEND_PROV_5000BASET_FULL, reg); - if (ret < 0) - return ret; - if (ret > 0) - changed = true; - - return genphy_c45_check_and_restart_aneg(phydev, changed); -} - -static int aqr_config_intr(struct phy_device *phydev) -{ - bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; - int err; - - if (en) { - /* Clear any pending interrupts before enabling them */ - err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2); - if (err < 0) - return err; - } - - err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2, - en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0); - if (err < 0) - return err; - - err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK, - en ? VEND1_GLOBAL_INT_STD_MASK_ALL : 0); - if (err < 0) - return err; - - err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK, - en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 | - VEND1_GLOBAL_INT_VEND_MASK_AN : 0); - if (err < 0) - return err; - - if (!en) { - /* Clear any pending interrupts after we have disabled them */ - err = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_STATUS2); - if (err < 0) - return err; - } - - return 0; -} - -static irqreturn_t aqr_handle_interrupt(struct phy_device *phydev) -{ - int irq_status; - - irq_status = phy_read_mmd(phydev, MDIO_MMD_AN, - MDIO_AN_TX_VEND_INT_STATUS2); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - if (!(irq_status & MDIO_AN_TX_VEND_INT_STATUS2_MASK)) - return IRQ_NONE; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - -static int aqr_read_status(struct phy_device *phydev) -{ - int val; - - if (phydev->autoneg == AUTONEG_ENABLE) { - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); - if (val < 0) - return val; - - linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, - phydev->lp_advertising, - val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL); - linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, - phydev->lp_advertising, - val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF); - } - - return genphy_c45_read_status(phydev); -} - -static int aqr107_read_rate(struct phy_device *phydev) -{ - u32 config_reg; - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); - if (val < 0) - return val; - - if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) { - case MDIO_AN_TX_VEND_STATUS1_10BASET: - phydev->speed = SPEED_10; - config_reg = VEND1_GLOBAL_CFG_10M; - break; - case MDIO_AN_TX_VEND_STATUS1_100BASETX: - phydev->speed = SPEED_100; - config_reg = VEND1_GLOBAL_CFG_100M; - break; - case MDIO_AN_TX_VEND_STATUS1_1000BASET: - phydev->speed = SPEED_1000; - config_reg = VEND1_GLOBAL_CFG_1G; - break; - case MDIO_AN_TX_VEND_STATUS1_2500BASET: - phydev->speed = SPEED_2500; - config_reg = VEND1_GLOBAL_CFG_2_5G; - break; - case MDIO_AN_TX_VEND_STATUS1_5000BASET: - phydev->speed = SPEED_5000; - config_reg = VEND1_GLOBAL_CFG_5G; - break; - case MDIO_AN_TX_VEND_STATUS1_10GBASET: - phydev->speed = SPEED_10000; - config_reg = VEND1_GLOBAL_CFG_10G; - break; - default: - phydev->speed = SPEED_UNKNOWN; - return 0; - } - - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg); - if (val < 0) - return val; - - if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) == - VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE) - phydev->rate_matching = RATE_MATCH_PAUSE; - else - phydev->rate_matching = RATE_MATCH_NONE; - - return 0; -} - -static int aqr107_read_status(struct phy_device *phydev) -{ - int val, ret; - - ret = aqr_read_status(phydev); - if (ret) - return ret; - - if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) - return 0; - - val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); - if (val < 0) - return val; - - switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: - phydev->interface = PHY_INTERFACE_MODE_10GKR; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KX: - phydev->interface = PHY_INTERFACE_MODE_1000BASEKX; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI: - phydev->interface = PHY_INTERFACE_MODE_10GBASER; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII: - phydev->interface = PHY_INTERFACE_MODE_USXGMII; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI: - phydev->interface = PHY_INTERFACE_MODE_XAUI; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII: - phydev->interface = PHY_INTERFACE_MODE_SGMII; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI: - phydev->interface = PHY_INTERFACE_MODE_RXAUI; - break; - case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: - phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - break; - default: - phydev->interface = PHY_INTERFACE_MODE_NA; - break; - } - - /* Read possibly downshifted rate from vendor register */ - return aqr107_read_rate(phydev); -} - -static int aqr107_get_downshift(struct phy_device *phydev, u8 *data) -{ - int val, cnt, enable; - - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV); - if (val < 0) - return val; - - enable = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_EN, val); - cnt = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); - - *data = enable && cnt ? cnt : DOWNSHIFT_DEV_DISABLE; - - return 0; -} - -static int aqr107_set_downshift(struct phy_device *phydev, u8 cnt) -{ - int val = 0; - - if (!FIELD_FIT(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt)) - return -E2BIG; - - if (cnt != DOWNSHIFT_DEV_DISABLE) { - val = MDIO_AN_VEND_PROV_DOWNSHIFT_EN; - val |= FIELD_PREP(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt); - } - - return phy_modify_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, - MDIO_AN_VEND_PROV_DOWNSHIFT_EN | - MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); -} - -static int aqr107_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return aqr107_get_downshift(phydev, data); - default: - return -EOPNOTSUPP; - } -} - -static int aqr107_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return aqr107_set_downshift(phydev, *(const u8 *)data); - default: - return -EOPNOTSUPP; - } -} - -/* If we configure settings whilst firmware is still initializing the chip, - * then these settings may be overwritten. Therefore make sure chip - * initialization has completed. Use presence of the firmware ID as - * indicator for initialization having completed. - * The chip also provides a "reset completed" bit, but it's cleared after - * read. Therefore function would time out if called again. - */ -static int aqr107_wait_reset_complete(struct phy_device *phydev) -{ - int val; - - return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, - VEND1_GLOBAL_FW_ID, val, val != 0, - 20000, 2000000, false); -} - -static void aqr107_chip_info(struct phy_device *phydev) -{ - u8 fw_major, fw_minor, build_id, prov_id; - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); - if (val < 0) - return; - - fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val); - fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val); - - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1); - if (val < 0) - return; - - build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); - prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); - - phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n", - fw_major, fw_minor, build_id, prov_id); -} - -static int aqr107_config_init(struct phy_device *phydev) -{ - int ret; - - /* Check that the PHY interface type is compatible */ - if (phydev->interface != PHY_INTERFACE_MODE_SGMII && - phydev->interface != PHY_INTERFACE_MODE_1000BASEKX && - phydev->interface != PHY_INTERFACE_MODE_2500BASEX && - phydev->interface != PHY_INTERFACE_MODE_XGMII && - phydev->interface != PHY_INTERFACE_MODE_USXGMII && - phydev->interface != PHY_INTERFACE_MODE_10GKR && - phydev->interface != PHY_INTERFACE_MODE_10GBASER && - phydev->interface != PHY_INTERFACE_MODE_XAUI && - phydev->interface != PHY_INTERFACE_MODE_RXAUI) - return -ENODEV; - - WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII, - "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n"); - - ret = aqr107_wait_reset_complete(phydev); - if (!ret) - aqr107_chip_info(phydev); - - return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); -} - -static int aqcs109_config_init(struct phy_device *phydev) -{ - int ret; - - /* Check that the PHY interface type is compatible */ - if (phydev->interface != PHY_INTERFACE_MODE_SGMII && - phydev->interface != PHY_INTERFACE_MODE_2500BASEX) - return -ENODEV; - - ret = aqr107_wait_reset_complete(phydev); - if (!ret) - aqr107_chip_info(phydev); - - /* AQCS109 belongs to a chip family partially supporting 10G and 5G. - * PMA speed ability bits are the same for all members of the family, - * AQCS109 however supports speeds up to 2.5G only. - */ - phy_set_max_speed(phydev, SPEED_2500); - - return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); -} - -static void aqr107_link_change_notify(struct phy_device *phydev) -{ - u8 fw_major, fw_minor; - bool downshift, short_reach, afr; - int mode, val; - - if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE) - return; - - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); - /* call failed or link partner is no Aquantia PHY */ - if (val < 0 || !(val & MDIO_AN_RX_LP_STAT1_AQ_PHY)) - return; - - short_reach = val & MDIO_AN_RX_LP_STAT1_SHORT_REACH; - downshift = val & MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT; - - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT4); - if (val < 0) - return; - - fw_major = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MAJOR, val); - fw_minor = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MINOR, val); - - val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_VEND_STAT3); - if (val < 0) - return; - - afr = val & MDIO_AN_RX_VEND_STAT3_AFR; - - phydev_dbg(phydev, "Link partner is Aquantia PHY, FW %u.%u%s%s%s\n", - fw_major, fw_minor, - short_reach ? ", short reach mode" : "", - downshift ? ", fast-retrain downshift advertised" : "", - afr ? ", fast reframe advertised" : ""); - - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT9); - if (val < 0) - return; - - mode = FIELD_GET(VEND1_GLOBAL_RSVD_STAT9_MODE, val); - if (mode == VEND1_GLOBAL_RSVD_STAT9_1000BT2) - phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n"); -} - -static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) -{ - int val, err; - - /* The datasheet notes to wait at least 1ms after issuing a - * processor intensive operation before checking. - * We cannot use the 'sleep_before_read' parameter of read_poll_timeout - * because that just determines the maximum time slept, not the minimum. - */ - usleep_range(1000, 5000); - - err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, - VEND1_GLOBAL_GEN_STAT2, val, - !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), - AQR107_OP_IN_PROG_SLEEP, - AQR107_OP_IN_PROG_TIMEOUT, false); - if (err) { - phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); - return err; - } - - return 0; -} - -static int aqr107_get_rate_matching(struct phy_device *phydev, - phy_interface_t iface) -{ - if (iface == PHY_INTERFACE_MODE_10GBASER || - iface == PHY_INTERFACE_MODE_2500BASEX || - iface == PHY_INTERFACE_MODE_NA) - return RATE_MATCH_PAUSE; - return RATE_MATCH_NONE; -} - -static int aqr107_suspend(struct phy_device *phydev) -{ - int err; - - err = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, - MDIO_CTRL1_LPOWER); - if (err) - return err; - - return aqr107_wait_processor_intensive_op(phydev); -} - -static int aqr107_resume(struct phy_device *phydev) -{ - int err; - - err = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, - MDIO_CTRL1_LPOWER); - if (err) - return err; - - return aqr107_wait_processor_intensive_op(phydev); -} - -static int aqr107_probe(struct phy_device *phydev) -{ - phydev->priv = devm_kzalloc(&phydev->mdio.dev, - sizeof(struct aqr107_priv), GFP_KERNEL); - if (!phydev->priv) - return -ENOMEM; - - return aqr_hwmon_probe(phydev); -} - -static struct phy_driver aqr_driver[] = { -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQ1202), - .name = "Aquantia AQ1202", - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQ2104), - .name = "Aquantia AQ2104", - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR105), - .name = "Aquantia AQR105", - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, - .suspend = aqr107_suspend, - .resume = aqr107_resume, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR106), - .name = "Aquantia AQR106", - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR107), - .name = "Aquantia AQR107", - .probe = aqr107_probe, - .get_rate_matching = aqr107_get_rate_matching, - .config_init = aqr107_config_init, - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr107_read_status, - .get_tunable = aqr107_get_tunable, - .set_tunable = aqr107_set_tunable, - .suspend = aqr107_suspend, - .resume = aqr107_resume, - .get_sset_count = aqr107_get_sset_count, - .get_strings = aqr107_get_strings, - .get_stats = aqr107_get_stats, - .link_change_notify = aqr107_link_change_notify, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), - .name = "Aquantia AQCS109", - .probe = aqr107_probe, - .get_rate_matching = aqr107_get_rate_matching, - .config_init = aqcs109_config_init, - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr107_read_status, - .get_tunable = aqr107_get_tunable, - .set_tunable = aqr107_set_tunable, - .suspend = aqr107_suspend, - .resume = aqr107_resume, - .get_sset_count = aqr107_get_sset_count, - .get_strings = aqr107_get_strings, - .get_stats = aqr107_get_stats, - .link_change_notify = aqr107_link_change_notify, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR405), - .name = "Aquantia AQR405", - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR112), - .name = "Aquantia AQR112", - .probe = aqr107_probe, - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .get_tunable = aqr107_get_tunable, - .set_tunable = aqr107_set_tunable, - .suspend = aqr107_suspend, - .resume = aqr107_resume, - .read_status = aqr107_read_status, - .get_rate_matching = aqr107_get_rate_matching, - .get_sset_count = aqr107_get_sset_count, - .get_strings = aqr107_get_strings, - .get_stats = aqr107_get_stats, - .link_change_notify = aqr107_link_change_notify, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR412), - .name = "Aquantia AQR412", - .probe = aqr107_probe, - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .get_tunable = aqr107_get_tunable, - .set_tunable = aqr107_set_tunable, - .suspend = aqr107_suspend, - .resume = aqr107_resume, - .read_status = aqr107_read_status, - .get_rate_matching = aqr107_get_rate_matching, - .get_sset_count = aqr107_get_sset_count, - .get_strings = aqr107_get_strings, - .get_stats = aqr107_get_stats, - .link_change_notify = aqr107_link_change_notify, -}, -{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), - .name = "Aquantia AQR113C", - .probe = aqr107_probe, - .get_rate_matching = aqr107_get_rate_matching, - .config_init = aqr107_config_init, - .config_aneg = aqr_config_aneg, - .config_intr = aqr_config_intr, - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr107_read_status, - .get_tunable = aqr107_get_tunable, - .set_tunable = aqr107_set_tunable, - .suspend = aqr107_suspend, - .resume = aqr107_resume, - .get_sset_count = aqr107_get_sset_count, - .get_strings = aqr107_get_strings, - .get_stats = aqr107_get_stats, - .link_change_notify = aqr107_link_change_notify, -}, -}; - -module_phy_driver(aqr_driver); - -static struct mdio_device_id __maybe_unused aqr_tbl[] = { - { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, - { } -}; - -MODULE_DEVICE_TABLE(mdio, aqr_tbl); - -MODULE_DESCRIPTION("Aquantia PHY driver"); -MODULE_AUTHOR("Shaohui Xie "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c deleted file mode 100644 index ef203b0807e588..00000000000000 --- a/drivers/net/phy/at803x.c +++ /dev/null @@ -1,2248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * drivers/net/phy/at803x.c - * - * Driver for Qualcomm Atheros AR803x PHY - * - * Author: Matus Ujhelyi - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 -#define AT803X_SFC_ASSERT_CRS BIT(11) -#define AT803X_SFC_FORCE_LINK BIT(10) -#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) -#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 -#define AT803X_SFC_MANUAL_MDIX 0x1 -#define AT803X_SFC_MANUAL_MDI 0x0 -#define AT803X_SFC_SQE_TEST BIT(2) -#define AT803X_SFC_POLARITY_REVERSAL BIT(1) -#define AT803X_SFC_DISABLE_JABBER BIT(0) - -#define AT803X_SPECIFIC_STATUS 0x11 -#define AT803X_SS_SPEED_MASK GENMASK(15, 14) -#define AT803X_SS_SPEED_1000 2 -#define AT803X_SS_SPEED_100 1 -#define AT803X_SS_SPEED_10 0 -#define AT803X_SS_DUPLEX BIT(13) -#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) -#define AT803X_SS_MDIX BIT(6) - -#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) -#define QCA808X_SS_SPEED_2500 4 - -#define AT803X_INTR_ENABLE 0x12 -#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) -#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) -#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) -#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) -#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) -#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) -#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) -#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) -#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) -#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) -#define AT803X_INTR_ENABLE_WOL BIT(0) - -#define AT803X_INTR_STATUS 0x13 - -#define AT803X_SMART_SPEED 0x14 -#define AT803X_SMART_SPEED_ENABLE BIT(5) -#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) -#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) -#define AT803X_CDT 0x16 -#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) -#define AT803X_CDT_ENABLE_TEST BIT(0) -#define AT803X_CDT_STATUS 0x1c -#define AT803X_CDT_STATUS_STAT_NORMAL 0 -#define AT803X_CDT_STATUS_STAT_SHORT 1 -#define AT803X_CDT_STATUS_STAT_OPEN 2 -#define AT803X_CDT_STATUS_STAT_FAIL 3 -#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) -#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) -#define AT803X_LED_CONTROL 0x18 - -#define AT803X_PHY_MMD3_WOL_CTRL 0x8012 -#define AT803X_WOL_EN BIT(5) -#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C -#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B -#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A -#define AT803X_REG_CHIP_CONFIG 0x1f -#define AT803X_BT_BX_REG_SEL 0x8000 - -#define AT803X_DEBUG_ADDR 0x1D -#define AT803X_DEBUG_DATA 0x1E - -#define AT803X_MODE_CFG_MASK 0x0F -#define AT803X_MODE_CFG_BASET_RGMII 0x00 -#define AT803X_MODE_CFG_BASET_SGMII 0x01 -#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 -#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 -#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 -#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 -#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 -#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 -#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B -#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E -#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F - -#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ -#define AT803X_PSSR_MR_AN_COMPLETE 0x0200 - -#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 -#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) -#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) -#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) - -#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 -#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) - -#define AT803X_DEBUG_REG_HIB_CTRL 0x0b -#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) -#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) -#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) - -#define AT803X_DEBUG_REG_3C 0x3C - -#define AT803X_DEBUG_REG_GREEN 0x3D -#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) - -#define AT803X_DEBUG_REG_1F 0x1F -#define AT803X_DEBUG_PLL_ON BIT(2) -#define AT803X_DEBUG_RGMII_1V8 BIT(3) - -#define MDIO_AZ_DEBUG 0x800D - -/* AT803x supports either the XTAL input pad, an internal PLL or the - * DSP as clock reference for the clock output pad. The XTAL reference - * is only used for 25 MHz output, all other frequencies need the PLL. - * The DSP as a clock reference is used in synchronous ethernet - * applications. - * - * By default the PLL is only enabled if there is a link. Otherwise - * the PHY will go into low power state and disabled the PLL. You can - * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always - * enabled. - */ -#define AT803X_MMD7_CLK25M 0x8016 -#define AT803X_CLK_OUT_MASK GENMASK(4, 2) -#define AT803X_CLK_OUT_25MHZ_XTAL 0 -#define AT803X_CLK_OUT_25MHZ_DSP 1 -#define AT803X_CLK_OUT_50MHZ_PLL 2 -#define AT803X_CLK_OUT_50MHZ_DSP 3 -#define AT803X_CLK_OUT_62_5MHZ_PLL 4 -#define AT803X_CLK_OUT_62_5MHZ_DSP 5 -#define AT803X_CLK_OUT_125MHZ_PLL 6 -#define AT803X_CLK_OUT_125MHZ_DSP 7 - -/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask - * but doesn't support choosing between XTAL/PLL and DSP. - */ -#define AT8035_CLK_OUT_MASK GENMASK(4, 3) - -#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) -#define AT803X_CLK_OUT_STRENGTH_FULL 0 -#define AT803X_CLK_OUT_STRENGTH_HALF 1 -#define AT803X_CLK_OUT_STRENGTH_QUARTER 2 - -#define AT803X_DEFAULT_DOWNSHIFT 5 -#define AT803X_MIN_DOWNSHIFT 2 -#define AT803X_MAX_DOWNSHIFT 9 - -#define AT803X_MMD3_SMARTEEE_CTL1 0x805b -#define AT803X_MMD3_SMARTEEE_CTL2 0x805c -#define AT803X_MMD3_SMARTEEE_CTL3 0x805d -#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8) - -#define ATH9331_PHY_ID 0x004dd041 -#define ATH8030_PHY_ID 0x004dd076 -#define ATH8031_PHY_ID 0x004dd074 -#define ATH8032_PHY_ID 0x004dd023 -#define ATH8035_PHY_ID 0x004dd072 -#define AT8030_PHY_ID_MASK 0xffffffef - -#define QCA8081_PHY_ID 0x004dd101 - -#define QCA8327_A_PHY_ID 0x004dd033 -#define QCA8327_B_PHY_ID 0x004dd034 -#define QCA8337_PHY_ID 0x004dd036 -#define QCA9561_PHY_ID 0x004dd042 -#define QCA8K_PHY_ID_MASK 0xffffffff - -#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) - -#define AT803X_PAGE_FIBER 0 -#define AT803X_PAGE_COPPER 1 - -/* don't turn off internal PLL */ -#define AT803X_KEEP_PLL_ENABLED BIT(0) -#define AT803X_DISABLE_SMARTEEE BIT(1) - -/* disable hibernation mode */ -#define AT803X_DISABLE_HIBERNATION_MODE BIT(2) - -/* ADC threshold */ -#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 -#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) -#define QCA808X_ADC_THRESHOLD_80MV 0 -#define QCA808X_ADC_THRESHOLD_100MV 0xf0 -#define QCA808X_ADC_THRESHOLD_200MV 0x0f -#define QCA808X_ADC_THRESHOLD_300MV 0xff - -/* CLD control */ -#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 -#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) -#define QCA808X_8023AZ_AFE_EN 0x90 - -/* AZ control */ -#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 -#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 -#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E -#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E -#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 -#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 - -#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c -#define QCA808X_TOP_OPTION1_DATA 0x0 - -#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 -#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 -#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 -#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad -#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 -#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 -#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 -#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 -#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 -#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 -#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 -#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 - -/* master/slave seed config */ -#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 -#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) -#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) -#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 - -/* Hibernation yields lower power consumpiton in contrast with normal operation mode. - * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. - */ -#define QCA808X_DBG_AN_TEST 0xb -#define QCA808X_HIBERNATION_EN BIT(15) - -#define QCA808X_CDT_ENABLE_TEST BIT(15) -#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) -#define QCA808X_CDT_LENGTH_UNIT BIT(10) - -#define QCA808X_MMD3_CDT_STATUS 0x8064 -#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 -#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 -#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 -#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 -#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0) - -#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) -#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) -#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) -#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) -#define QCA808X_CDT_STATUS_STAT_FAIL 0 -#define QCA808X_CDT_STATUS_STAT_NORMAL 1 -#define QCA808X_CDT_STATUS_STAT_OPEN 2 -#define QCA808X_CDT_STATUS_STAT_SHORT 3 - -/* QCA808X 1G chip type */ -#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d -#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) - -#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 -#define QCA8081_PHY_FIFO_RSTN BIT(11) - -MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); -MODULE_AUTHOR("Matus Ujhelyi"); -MODULE_LICENSE("GPL"); - -enum stat_access_type { - PHY, - MMD -}; - -struct at803x_hw_stat { - const char *string; - u8 reg; - u32 mask; - enum stat_access_type access_type; -}; - -static struct at803x_hw_stat at803x_hw_stats[] = { - { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, - { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, - { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, -}; - -struct at803x_priv { - int flags; - u16 clk_25m_reg; - u16 clk_25m_mask; - u8 smarteee_lpi_tw_1g; - u8 smarteee_lpi_tw_100m; - bool is_fiber; - bool is_1000basex; - struct regulator_dev *vddio_rdev; - struct regulator_dev *vddh_rdev; - u64 stats[ARRAY_SIZE(at803x_hw_stats)]; -}; - -struct at803x_context { - u16 bmcr; - u16 advertise; - u16 control1000; - u16 int_enable; - u16 smart_speed; - u16 led_control; -}; - -static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_write(phydev, AT803X_DEBUG_DATA, data); -} - -static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_read(phydev, AT803X_DEBUG_DATA); -} - -static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, - u16 clear, u16 set) -{ - u16 val; - int ret; - - ret = at803x_debug_reg_read(phydev, reg); - if (ret < 0) - return ret; - - val = ret & 0xffff; - val &= ~clear; - val |= set; - - return phy_write(phydev, AT803X_DEBUG_DATA, val); -} - -static int at803x_write_page(struct phy_device *phydev, int page) -{ - int mask; - int set; - - if (page == AT803X_PAGE_COPPER) { - set = AT803X_BT_BX_REG_SEL; - mask = 0; - } else { - set = 0; - mask = AT803X_BT_BX_REG_SEL; - } - - return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set); -} - -static int at803x_read_page(struct phy_device *phydev) -{ - int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG); - - if (ccr < 0) - return ccr; - - if (ccr & AT803X_BT_BX_REG_SEL) - return AT803X_PAGE_COPPER; - - return AT803X_PAGE_FIBER; -} - -static int at803x_enable_rx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, - AT803X_DEBUG_RX_CLK_DLY_EN); -} - -static int at803x_enable_tx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, - AT803X_DEBUG_TX_CLK_DLY_EN); -} - -static int at803x_disable_rx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - AT803X_DEBUG_RX_CLK_DLY_EN, 0); -} - -static int at803x_disable_tx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, - AT803X_DEBUG_TX_CLK_DLY_EN, 0); -} - -/* save relevant PHY registers to private copy */ -static void at803x_context_save(struct phy_device *phydev, - struct at803x_context *context) -{ - context->bmcr = phy_read(phydev, MII_BMCR); - context->advertise = phy_read(phydev, MII_ADVERTISE); - context->control1000 = phy_read(phydev, MII_CTRL1000); - context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); - context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); - context->led_control = phy_read(phydev, AT803X_LED_CONTROL); -} - -/* restore relevant PHY registers from private copy */ -static void at803x_context_restore(struct phy_device *phydev, - const struct at803x_context *context) -{ - phy_write(phydev, MII_BMCR, context->bmcr); - phy_write(phydev, MII_ADVERTISE, context->advertise); - phy_write(phydev, MII_CTRL1000, context->control1000); - phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); - phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); - phy_write(phydev, AT803X_LED_CONTROL, context->led_control); -} - -static int at803x_set_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int ret, irq_enabled; - - if (wol->wolopts & WAKE_MAGIC) { - struct net_device *ndev = phydev->attached_dev; - const u8 *mac; - unsigned int i; - static const unsigned int offsets[] = { - AT803X_LOC_MAC_ADDR_32_47_OFFSET, - AT803X_LOC_MAC_ADDR_16_31_OFFSET, - AT803X_LOC_MAC_ADDR_0_15_OFFSET, - }; - - if (!ndev) - return -ENODEV; - - mac = (const u8 *) ndev->dev_addr; - - if (!is_valid_ether_addr(mac)) - return -EINVAL; - - for (i = 0; i < 3; i++) - phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], - mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); - - /* Enable WOL function for 1588 */ - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - 0, AT803X_WOL_EN); - if (ret) - return ret; - } - /* Enable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); - if (ret) - return ret; - } else { - /* Disable WoL function for 1588 */ - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - AT803X_WOL_EN, 0); - if (ret) - return ret; - } - /* Disable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); - if (ret) - return ret; - } - - /* Clear WOL status */ - ret = phy_read(phydev, AT803X_INTR_STATUS); - if (ret < 0) - return ret; - - /* Check if there are other interrupts except for WOL triggered when PHY is - * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can - * be passed up to the interrupt PIN. - */ - irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (irq_enabled < 0) - return irq_enabled; - - irq_enabled &= ~AT803X_INTR_ENABLE_WOL; - if (ret & irq_enabled && !phy_polling_mode(phydev)) - phy_trigger_machine(phydev); - - return 0; -} - -static void at803x_get_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int value; - - wol->supported = WAKE_MAGIC; - wol->wolopts = 0; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - if (value < 0) - return; - - if (value & AT803X_INTR_ENABLE_WOL) - wol->wolopts |= WAKE_MAGIC; -} - -static int at803x_get_sset_count(struct phy_device *phydev) -{ - return ARRAY_SIZE(at803x_hw_stats); -} - -static void at803x_get_strings(struct phy_device *phydev, u8 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) { - strscpy(data + i * ETH_GSTRING_LEN, - at803x_hw_stats[i].string, ETH_GSTRING_LEN); - } -} - -static u64 at803x_get_stat(struct phy_device *phydev, int i) -{ - struct at803x_hw_stat stat = at803x_hw_stats[i]; - struct at803x_priv *priv = phydev->priv; - int val; - u64 ret; - - if (stat.access_type == MMD) - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); - else - val = phy_read(phydev, stat.reg); - - if (val < 0) { - ret = U64_MAX; - } else { - val = val & stat.mask; - priv->stats[i] += val; - ret = priv->stats[i]; - } - - return ret; -} - -static void at803x_get_stats(struct phy_device *phydev, - struct ethtool_stats *stats, u64 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) - data[i] = at803x_get_stat(phydev, i); -} - -static int at803x_suspend(struct phy_device *phydev) -{ - int value; - int wol_enabled; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - wol_enabled = value & AT803X_INTR_ENABLE_WOL; - - if (wol_enabled) - value = BMCR_ISOLATE; - else - value = BMCR_PDOWN; - - phy_modify(phydev, MII_BMCR, 0, value); - - return 0; -} - -static int at803x_resume(struct phy_device *phydev) -{ - return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); -} - -static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, - unsigned int selector) -{ - struct phy_device *phydev = rdev_get_drvdata(rdev); - - if (selector) - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - 0, AT803X_DEBUG_RGMII_1V8); - else - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - AT803X_DEBUG_RGMII_1V8, 0); -} - -static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) -{ - struct phy_device *phydev = rdev_get_drvdata(rdev); - int val; - - val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); - if (val < 0) - return val; - - return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; -} - -static const struct regulator_ops vddio_regulator_ops = { - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel, - .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel, -}; - -static const unsigned int vddio_voltage_table[] = { - 1500000, - 1800000, -}; - -static const struct regulator_desc vddio_desc = { - .name = "vddio", - .of_match = of_match_ptr("vddio-regulator"), - .n_voltages = ARRAY_SIZE(vddio_voltage_table), - .volt_table = vddio_voltage_table, - .ops = &vddio_regulator_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, -}; - -static const struct regulator_ops vddh_regulator_ops = { -}; - -static const struct regulator_desc vddh_desc = { - .name = "vddh", - .of_match = of_match_ptr("vddh-regulator"), - .n_voltages = 1, - .fixed_uV = 2500000, - .ops = &vddh_regulator_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, -}; - -static int at8031_register_regulators(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - struct device *dev = &phydev->mdio.dev; - struct regulator_config config = { }; - - config.dev = dev; - config.driver_data = phydev; - - priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); - if (IS_ERR(priv->vddio_rdev)) { - phydev_err(phydev, "failed to register VDDIO regulator\n"); - return PTR_ERR(priv->vddio_rdev); - } - - priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); - if (IS_ERR(priv->vddh_rdev)) { - phydev_err(phydev, "failed to register VDDH regulator\n"); - return PTR_ERR(priv->vddh_rdev); - } - - return 0; -} - -static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -{ - struct phy_device *phydev = upstream; - __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); - __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); - DECLARE_PHY_INTERFACE_MASK(interfaces); - phy_interface_t iface; - - linkmode_zero(phy_support); - phylink_set(phy_support, 1000baseX_Full); - phylink_set(phy_support, 1000baseT_Full); - phylink_set(phy_support, Autoneg); - phylink_set(phy_support, Pause); - phylink_set(phy_support, Asym_Pause); - - linkmode_zero(sfp_support); - sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces); - /* Some modules support 10G modes as well as others we support. - * Mask out non-supported modes so the correct interface is picked. - */ - linkmode_and(sfp_support, phy_support, sfp_support); - - if (linkmode_empty(sfp_support)) { - dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); - return -EINVAL; - } - - iface = sfp_select_interface(phydev->sfp_bus, sfp_support); - - /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes - * interface for use with SFP modules. - * However, some copper modules detected as having a preferred SGMII - * interface do default to and function in 1000Base-X mode, so just - * print a warning and allow such modules, as they may have some chance - * of working. - */ - if (iface == PHY_INTERFACE_MODE_SGMII) - dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); - else if (iface != PHY_INTERFACE_MODE_1000BASEX) - return -EINVAL; - - return 0; -} - -static const struct sfp_upstream_ops at803x_sfp_ops = { - .attach = phy_sfp_attach, - .detach = phy_sfp_detach, - .module_insert = at803x_sfp_insert, -}; - -static int at803x_parse_dt(struct phy_device *phydev) -{ - struct device_node *node = phydev->mdio.dev.of_node; - struct at803x_priv *priv = phydev->priv; - u32 freq, strength, tw; - unsigned int sel; - int ret; - - if (!IS_ENABLED(CONFIG_OF_MDIO)) - return 0; - - if (of_property_read_bool(node, "qca,disable-smarteee")) - priv->flags |= AT803X_DISABLE_SMARTEEE; - - if (of_property_read_bool(node, "qca,disable-hibernation-mode")) - priv->flags |= AT803X_DISABLE_HIBERNATION_MODE; - - if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) { - if (!tw || tw > 255) { - phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n"); - return -EINVAL; - } - priv->smarteee_lpi_tw_1g = tw; - } - - if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) { - if (!tw || tw > 255) { - phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n"); - return -EINVAL; - } - priv->smarteee_lpi_tw_100m = tw; - } - - ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); - if (!ret) { - switch (freq) { - case 25000000: - sel = AT803X_CLK_OUT_25MHZ_XTAL; - break; - case 50000000: - sel = AT803X_CLK_OUT_50MHZ_PLL; - break; - case 62500000: - sel = AT803X_CLK_OUT_62_5MHZ_PLL; - break; - case 125000000: - sel = AT803X_CLK_OUT_125MHZ_PLL; - break; - default: - phydev_err(phydev, "invalid qca,clk-out-frequency\n"); - return -EINVAL; - } - - priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel); - priv->clk_25m_mask |= AT803X_CLK_OUT_MASK; - - /* Fixup for the AR8030/AR8035. This chip has another mask and - * doesn't support the DSP reference. Eg. the lowest bit of the - * mask. The upper two bits select the same frequencies. Mask - * the lowest bit here. - * - * Warning: - * There was no datasheet for the AR8030 available so this is - * just a guess. But the AR8035 is listed as pin compatible - * to the AR8030 so there might be a good chance it works on - * the AR8030 too. - */ - if (phydev->drv->phy_id == ATH8030_PHY_ID || - phydev->drv->phy_id == ATH8035_PHY_ID) { - priv->clk_25m_reg &= AT8035_CLK_OUT_MASK; - priv->clk_25m_mask &= AT8035_CLK_OUT_MASK; - } - } - - ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); - if (!ret) { - priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; - switch (strength) { - case AR803X_STRENGTH_FULL: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; - break; - case AR803X_STRENGTH_HALF: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; - break; - case AR803X_STRENGTH_QUARTER: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; - break; - default: - phydev_err(phydev, "invalid qca,clk-out-strength\n"); - return -EINVAL; - } - } - - /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping - * options. - */ - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - if (of_property_read_bool(node, "qca,keep-pll-enabled")) - priv->flags |= AT803X_KEEP_PLL_ENABLED; - - ret = at8031_register_regulators(phydev); - if (ret < 0) - return ret; - - ret = devm_regulator_get_enable_optional(&phydev->mdio.dev, - "vddio"); - if (ret) { - phydev_err(phydev, "failed to get VDDIO regulator\n"); - return ret; - } - - /* Only AR8031/8033 support 1000Base-X for SFP modules */ - ret = phy_sfp_probe(phydev, &at803x_sfp_ops); - if (ret < 0) - return ret; - } - - return 0; -} - -static int at803x_probe(struct phy_device *phydev) -{ - struct device *dev = &phydev->mdio.dev; - struct at803x_priv *priv; - int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - phydev->priv = priv; - - ret = at803x_parse_dt(phydev); - if (ret) - return ret; - - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); - int mode_cfg; - - if (ccr < 0) - return ccr; - mode_cfg = ccr & AT803X_MODE_CFG_MASK; - - switch (mode_cfg) { - case AT803X_MODE_CFG_BX1000_RGMII_50OHM: - case AT803X_MODE_CFG_BX1000_RGMII_75OHM: - priv->is_1000basex = true; - fallthrough; - case AT803X_MODE_CFG_FX100_RGMII_50OHM: - case AT803X_MODE_CFG_FX100_RGMII_75OHM: - priv->is_fiber = true; - break; - } - - /* Disable WoL in 1588 register which is enabled - * by default - */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - AT803X_WOL_EN, 0); - if (ret) - return ret; - } - - return 0; -} - -static int at803x_get_features(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int err; - - err = genphy_read_abilities(phydev); - if (err) - return err; - - if (phydev->drv->phy_id != ATH8031_PHY_ID) - return 0; - - /* AR8031/AR8033 have different status registers - * for copper and fiber operation. However, the - * extended status register is the same for both - * operation modes. - * - * As a result of that, ESTATUS_1000_XFULL is set - * to 1 even when operating in copper TP mode. - * - * Remove this mode from the supported link modes - * when not operating in 1000BaseX mode. - */ - if (!priv->is_1000basex) - linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, - phydev->supported); - - return 0; -} - -static int at803x_smarteee_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - u16 mask = 0, val = 0; - int ret; - - if (priv->flags & AT803X_DISABLE_SMARTEEE) - return phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_MMD3_SMARTEEE_CTL3, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0); - - if (priv->smarteee_lpi_tw_1g) { - mask |= 0xff00; - val |= priv->smarteee_lpi_tw_1g << 8; - } - if (priv->smarteee_lpi_tw_100m) { - mask |= 0x00ff; - val |= priv->smarteee_lpi_tw_100m; - } - if (!mask) - return 0; - - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1, - mask, val); - if (ret) - return ret; - - return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN); -} - -static int at803x_clk_out_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - if (!priv->clk_25m_mask) - return 0; - - return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, - priv->clk_25m_mask, priv->clk_25m_reg); -} - -static int at8031_pll_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - /* The default after hardware reset is PLL OFF. After a soft reset, the - * values are retained. - */ - if (priv->flags & AT803X_KEEP_PLL_ENABLED) - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - 0, AT803X_DEBUG_PLL_ON); - else - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - AT803X_DEBUG_PLL_ON, 0); -} - -static int at803x_hibernation_mode_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - /* The default after hardware reset is hibernation mode enabled. After - * software reset, the value is retained. - */ - if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE)) - return 0; - - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, - AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0); -} - -static int at803x_config_init(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int ret; - - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - /* Some bootloaders leave the fiber page selected. - * Switch to the appropriate page (fiber or copper), as otherwise we - * read the PHY capabilities from the wrong page. - */ - phy_lock_mdio_bus(phydev); - ret = at803x_write_page(phydev, - priv->is_fiber ? AT803X_PAGE_FIBER : - AT803X_PAGE_COPPER); - phy_unlock_mdio_bus(phydev); - if (ret) - return ret; - - ret = at8031_pll_config(phydev); - if (ret < 0) - return ret; - } - - /* The RX and TX delay default is: - * after HW reset: RX delay enabled and TX delay disabled - * after SW reset: RX delay enabled, while TX delay retains the - * value before reset. - */ - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - ret = at803x_enable_rx_delay(phydev); - else - ret = at803x_disable_rx_delay(phydev); - if (ret < 0) - return ret; - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - ret = at803x_enable_tx_delay(phydev); - else - ret = at803x_disable_tx_delay(phydev); - if (ret < 0) - return ret; - - ret = at803x_smarteee_config(phydev); - if (ret < 0) - return ret; - - ret = at803x_clk_out_config(phydev); - if (ret < 0) - return ret; - - ret = at803x_hibernation_mode_config(phydev); - if (ret < 0) - return ret; - - /* Ar803x extended next page bit is enabled by default. Cisco - * multigig switches read this bit and attempt to negotiate 10Gbps - * rates even if the next page bit is disabled. This is incorrect - * behaviour but we still need to accommodate it. XNP is only needed - * for 10Gbps support, so disable XNP. - */ - return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); -} - -static int at803x_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, AT803X_INTR_STATUS); - - return (err < 0) ? err : 0; -} - -static int at803x_config_intr(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int err; - int value; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - if (err) - return err; - - value |= AT803X_INTR_ENABLE_AUTONEG_ERR; - value |= AT803X_INTR_ENABLE_SPEED_CHANGED; - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; - value |= AT803X_INTR_ENABLE_LINK_FAIL; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; - if (priv->is_fiber) { - value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; - } - - err = phy_write(phydev, AT803X_INTR_ENABLE, value); - } else { - err = phy_write(phydev, AT803X_INTR_ENABLE, 0); - if (err) - return err; - - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - } - - return err; -} - -static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) -{ - int irq_status, int_enabled; - - irq_status = phy_read(phydev, AT803X_INTR_STATUS); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* Read the current enabled interrupts */ - int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (int_enabled < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* See if this was one of our enabled interrupts */ - if (!(irq_status & int_enabled)) - return IRQ_NONE; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - -static void at803x_link_change_notify(struct phy_device *phydev) -{ - /* - * Conduct a hardware reset for AT8030 every time a link loss is - * signalled. This is necessary to circumvent a hardware bug that - * occurs when the cable is unplugged while TX packets are pending - * in the FIFO. In such cases, the FIFO enters an error mode it - * cannot recover from by software. - */ - if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) { - struct at803x_context context; - - at803x_context_save(phydev, &context); - - phy_device_reset(phydev, 1); - msleep(1); - phy_device_reset(phydev, 0); - msleep(1); - - at803x_context_restore(phydev, &context); - - phydev_dbg(phydev, "%s(): phy was reset\n", __func__); - } -} - -static int at803x_read_specific_status(struct phy_device *phydev) -{ - int ss; - - /* Read the AT8035 PHY-Specific Status register, which indicates the - * speed and duplex that the PHY is actually using, irrespective of - * whether we are in autoneg mode or not. - */ - ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); - if (ss < 0) - return ss; - - if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { - int sfc, speed; - - sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); - if (sfc < 0) - return sfc; - - /* qca8081 takes the different bits for speed value from at803x */ - if (phydev->drv->phy_id == QCA8081_PHY_ID) - speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss); - else - speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss); - - switch (speed) { - case AT803X_SS_SPEED_10: - phydev->speed = SPEED_10; - break; - case AT803X_SS_SPEED_100: - phydev->speed = SPEED_100; - break; - case AT803X_SS_SPEED_1000: - phydev->speed = SPEED_1000; - break; - case QCA808X_SS_SPEED_2500: - phydev->speed = SPEED_2500; - break; - } - if (ss & AT803X_SS_DUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - if (ss & AT803X_SS_MDIX) - phydev->mdix = ETH_TP_MDI_X; - else - phydev->mdix = ETH_TP_MDI; - - switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { - case AT803X_SFC_MANUAL_MDI: - phydev->mdix_ctrl = ETH_TP_MDI; - break; - case AT803X_SFC_MANUAL_MDIX: - phydev->mdix_ctrl = ETH_TP_MDI_X; - break; - case AT803X_SFC_AUTOMATIC_CROSSOVER: - phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - break; - } - } - - return 0; -} - -static int at803x_read_status(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int err, old_link = phydev->link; - - if (priv->is_1000basex) - return genphy_c37_read_status(phydev); - - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); - if (err) - return err; - - /* why bother the PHY if nothing can have changed */ - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) - return 0; - - phydev->speed = SPEED_UNKNOWN; - phydev->duplex = DUPLEX_UNKNOWN; - phydev->pause = 0; - phydev->asym_pause = 0; - - err = genphy_read_lpa(phydev); - if (err < 0) - return err; - - err = at803x_read_specific_status(phydev); - if (err < 0) - return err; - - if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) - phy_resolve_aneg_pause(phydev); - - return 0; -} - -static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) -{ - u16 val; - - switch (ctrl) { - case ETH_TP_MDI: - val = AT803X_SFC_MANUAL_MDI; - break; - case ETH_TP_MDI_X: - val = AT803X_SFC_MANUAL_MDIX; - break; - case ETH_TP_MDI_AUTO: - val = AT803X_SFC_AUTOMATIC_CROSSOVER; - break; - default: - return 0; - } - - return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, - AT803X_SFC_MDI_CROSSOVER_MODE_M, - FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); -} - -static int at803x_config_aneg(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int ret; - - ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); - if (ret < 0) - return ret; - - /* Changes of the midx bits are disruptive to the normal operation; - * therefore any changes to these registers must be followed by a - * software reset to take effect. - */ - if (ret == 1) { - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - } - - if (priv->is_1000basex) - return genphy_c37_config_aneg(phydev); - - /* Do not restart auto-negotiation by setting ret to 0 defautly, - * when calling __genphy_config_aneg later. - */ - ret = 0; - - if (phydev->drv->phy_id == QCA8081_PHY_ID) { - int phy_ctrl = 0; - - /* The reg MII_BMCR also needs to be configured for force mode, the - * genphy_config_aneg is also needed. - */ - if (phydev->autoneg == AUTONEG_DISABLE) - genphy_c45_pma_setup_forced(phydev); - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) - phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; - - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); - if (ret < 0) - return ret; - } - - return __genphy_config_aneg(phydev, ret); -} - -static int at803x_get_downshift(struct phy_device *phydev, u8 *d) -{ - int val; - - val = phy_read(phydev, AT803X_SMART_SPEED); - if (val < 0) - return val; - - if (val & AT803X_SMART_SPEED_ENABLE) - *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; - else - *d = DOWNSHIFT_DEV_DISABLE; - - return 0; -} - -static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) -{ - u16 mask, set; - int ret; - - switch (cnt) { - case DOWNSHIFT_DEV_DEFAULT_COUNT: - cnt = AT803X_DEFAULT_DOWNSHIFT; - fallthrough; - case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: - set = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER | - FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); - mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; - break; - case DOWNSHIFT_DEV_DISABLE: - set = 0; - mask = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER; - break; - default: - return -EINVAL; - } - - ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); - - /* After changing the smart speed settings, we need to perform a - * software reset, use phy_init_hw() to make sure we set the - * reapply any values which might got lost during software reset. - */ - if (ret == 1) - ret = phy_init_hw(phydev); - - return ret; -} - -static int at803x_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_get_downshift(phydev, data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_set_downshift(phydev, *(const u8 *)data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_cable_test_result_trans(u16 status) -{ - switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { - case AT803X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case AT803X_CDT_STATUS_STAT_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case AT803X_CDT_STATUS_STAT_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case AT803X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static bool at803x_cdt_test_failed(u16 status) -{ - return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == - AT803X_CDT_STATUS_STAT_FAIL; -} - -static bool at803x_cdt_fault_length_valid(u16 status) -{ - switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { - case AT803X_CDT_STATUS_STAT_OPEN: - case AT803X_CDT_STATUS_STAT_SHORT: - return true; - } - return false; -} - -static int at803x_cdt_fault_length(u16 status) -{ - int dt; - - /* According to the datasheet the distance to the fault is - * DELTA_TIME * 0.824 meters. - * - * The author suspect the correct formula is: - * - * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 - * - * where c is the speed of light, VF is the velocity factor of - * the twisted pair cable, 125MHz the counter frequency and - * we need to divide by 2 because the hardware will measure the - * round trip time to the fault and back to the PHY. - * - * With a VF of 0.69 we get the factor 0.824 mentioned in the - * datasheet. - */ - dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status); - - return (dt * 824) / 10; -} - -static int at803x_cdt_start(struct phy_device *phydev, int pair) -{ - u16 cdt; - - /* qca8081 takes the different bit 15 to enable CDT test */ - if (phydev->drv->phy_id == QCA8081_PHY_ID) - cdt = QCA808X_CDT_ENABLE_TEST | - QCA808X_CDT_LENGTH_UNIT | - QCA808X_CDT_INTER_CHECK_DIS; - else - cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | - AT803X_CDT_ENABLE_TEST; - - return phy_write(phydev, AT803X_CDT, cdt); -} - -static int at803x_cdt_wait_for_completion(struct phy_device *phydev) -{ - int val, ret; - u16 cdt_en; - - if (phydev->drv->phy_id == QCA8081_PHY_ID) - cdt_en = QCA808X_CDT_ENABLE_TEST; - else - cdt_en = AT803X_CDT_ENABLE_TEST; - - /* One test run takes about 25ms */ - ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, - !(val & cdt_en), - 30000, 100000, true); - - return ret < 0 ? ret : 0; -} - -static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) -{ - static const int ethtool_pair[] = { - ETHTOOL_A_CABLE_PAIR_A, - ETHTOOL_A_CABLE_PAIR_B, - ETHTOOL_A_CABLE_PAIR_C, - ETHTOOL_A_CABLE_PAIR_D, - }; - int ret, val; - - ret = at803x_cdt_start(phydev, pair); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev); - if (ret) - return ret; - - val = phy_read(phydev, AT803X_CDT_STATUS); - if (val < 0) - return val; - - if (at803x_cdt_test_failed(val)) - return 0; - - ethnl_cable_test_result(phydev, ethtool_pair[pair], - at803x_cable_test_result_trans(val)); - - if (at803x_cdt_fault_length_valid(val)) - ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], - at803x_cdt_fault_length(val)); - - return 1; -} - -static int at803x_cable_test_get_status(struct phy_device *phydev, - bool *finished) -{ - unsigned long pair_mask; - int retries = 20; - int pair, ret; - - if (phydev->phy_id == ATH9331_PHY_ID || - phydev->phy_id == ATH8032_PHY_ID || - phydev->phy_id == QCA9561_PHY_ID) - pair_mask = 0x3; - else - pair_mask = 0xf; - - *finished = false; - - /* According to the datasheet the CDT can be performed when - * there is no link partner or when the link partner is - * auto-negotiating. Starting the test will restart the AN - * automatically. It seems that doing this repeatedly we will - * get a slot where our link partner won't disturb our - * measurement. - */ - while (pair_mask && retries--) { - for_each_set_bit(pair, &pair_mask, 4) { - ret = at803x_cable_test_one_pair(phydev, pair); - if (ret < 0) - return ret; - if (ret) - clear_bit(pair, &pair_mask); - } - if (pair_mask) - msleep(250); - } - - *finished = true; - - return 0; -} - -static int at803x_cable_test_start(struct phy_device *phydev) -{ - /* Enable auto-negotiation, but advertise no capabilities, no link - * will be established. A restart of the auto-negotiation is not - * required, because the cable test will automatically break the link. - */ - phy_write(phydev, MII_BMCR, BMCR_ANENABLE); - phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); - if (phydev->phy_id != ATH9331_PHY_ID && - phydev->phy_id != ATH8032_PHY_ID && - phydev->phy_id != QCA9561_PHY_ID) - phy_write(phydev, MII_CTRL1000, 0); - - /* we do all the (time consuming) work later */ - return 0; -} - -static int qca83xx_config_init(struct phy_device *phydev) -{ - u8 switch_revision; - - switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; - - switch (switch_revision) { - case 1: - /* For 100M waveform */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); - /* Turn on Gigabit clock */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); - break; - - case 2: - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); - fallthrough; - case 4: - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); - at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); - break; - } - - /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. - * Disable on init and enable only with 100m speed following - * qca original source code. - */ - if (phydev->drv->phy_id == QCA8327_A_PHY_ID || - phydev->drv->phy_id == QCA8327_B_PHY_ID) - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - - /* Following original QCA sourcecode set port to prefer master */ - phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); - - return 0; -} - -static void qca83xx_link_change_notify(struct phy_device *phydev) -{ - /* QCA8337 doesn't require DAC Amplitude adjustement */ - if (phydev->drv->phy_id == QCA8337_PHY_ID) - return; - - /* Set DAC Amplitude adjustment to +6% for 100m on link running */ - if (phydev->state == PHY_RUNNING) { - if (phydev->speed == SPEED_100) - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, - QCA8327_DEBUG_MANU_CTRL_EN); - } else { - /* Reset DAC Amplitude adjustment */ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - } -} - -static int qca83xx_resume(struct phy_device *phydev) -{ - int ret, val; - - /* Skip reset if not suspended */ - if (!phydev->suspended) - return 0; - - /* Reinit the port, reset values set by suspend */ - qca83xx_config_init(phydev); - - /* Reset the port on port resume */ - phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - - /* On resume from suspend the switch execute a reset and - * restart auto-negotiation. Wait for reset to complete. - */ - ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), - 50000, 600000, true); - if (ret) - return ret; - - msleep(1); - - return 0; -} - -static int qca83xx_suspend(struct phy_device *phydev) -{ - u16 mask = 0; - - /* Only QCA8337 support actual suspend. - * QCA8327 cause port unreliability when phy suspend - * is set. - */ - if (phydev->drv->phy_id == QCA8337_PHY_ID) { - genphy_suspend(phydev); - } else { - mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); - phy_modify(phydev, MII_BMCR, mask, 0); - } - - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, - AT803X_DEBUG_GATE_CLK_IN1000, 0); - - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, - AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | - AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); - - return 0; -} - -static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) -{ - int ret; - - /* Enable fast retrain */ - ret = genphy_c45_fast_retrain(phydev, true); - if (ret) - return ret; - - phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, - QCA808X_TOP_OPTION1_DATA); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, - QCA808X_MSE_THRESHOLD_20DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, - QCA808X_MSE_THRESHOLD_17DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, - QCA808X_MSE_THRESHOLD_27DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, - QCA808X_MSE_THRESHOLD_28DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, - QCA808X_MMD3_DEBUG_1_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, - QCA808X_MMD3_DEBUG_4_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, - QCA808X_MMD3_DEBUG_5_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, - QCA808X_MMD3_DEBUG_3_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, - QCA808X_MMD3_DEBUG_6_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, - QCA808X_MMD3_DEBUG_2_VALUE); - - return 0; -} - -static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) -{ - u16 seed_value; - - if (!enable) - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); - - seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, - FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | - QCA808X_MASTER_SLAVE_SEED_ENABLE); -} - -static bool qca808x_is_prefer_master(struct phy_device *phydev) -{ - return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || - (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); -} - -static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) -{ - return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); -} - -static int qca808x_config_init(struct phy_device *phydev) -{ - int ret; - - /* Active adc&vga on 802.3az for the link 1000M and 100M */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, - QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); - if (ret) - return ret; - - /* Adjust the threshold on 802.3az for the link 1000M */ - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, - QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL); - if (ret) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - /* Config the fast retrain for the link 2500M */ - ret = qca808x_phy_fast_retrain_config(phydev); - if (ret) - return ret; - - ret = genphy_read_master_slave(phydev); - if (ret < 0) - return ret; - - if (!qca808x_is_prefer_master(phydev)) { - /* Enable seed and configure lower ramdom seed to make phy - * linked as slave mode. - */ - ret = qca808x_phy_ms_seed_enable(phydev, true); - if (ret) - return ret; - } - } - - /* Configure adc threshold as 100mv for the link 10M */ - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, - QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV); -} - -static int qca808x_read_status(struct phy_device *phydev) -{ - int ret; - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); - if (ret < 0) - return ret; - - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, - ret & MDIO_AN_10GBT_STAT_LP2_5G); - - ret = genphy_read_status(phydev); - if (ret) - return ret; - - ret = at803x_read_specific_status(phydev); - if (ret < 0) - return ret; - - if (phydev->link) { - if (phydev->speed == SPEED_2500) - phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - else - phydev->interface = PHY_INTERFACE_MODE_SGMII; - } else { - /* generate seed as a lower random value to make PHY linked as SLAVE easily, - * except for master/slave configuration fault detected or the master mode - * preferred. - * - * the reason for not putting this code into the function link_change_notify is - * the corner case where the link partner is also the qca8081 PHY and the seed - * value is configured as the same value, the link can't be up and no link change - * occurs. - */ - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || - qca808x_is_prefer_master(phydev)) { - qca808x_phy_ms_seed_enable(phydev, false); - } else { - qca808x_phy_ms_seed_enable(phydev, true); - } - } - } - - return 0; -} - -static int qca808x_soft_reset(struct phy_device *phydev) -{ - int ret; - - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) - ret = qca808x_phy_ms_seed_enable(phydev, true); - - return ret; -} - -static bool qca808x_cdt_fault_length_valid(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_SHORT: - case QCA808X_CDT_STATUS_STAT_OPEN: - return true; - default: - return false; - } -} - -static int qca808x_cable_test_result_trans(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case QCA808X_CDT_STATUS_STAT_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case QCA808X_CDT_STATUS_STAT_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case QCA808X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair) -{ - int val; - u32 cdt_length_reg = 0; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; - break; - case ETHTOOL_A_CABLE_PAIR_B: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; - break; - case ETHTOOL_A_CABLE_PAIR_C: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; - break; - case ETHTOOL_A_CABLE_PAIR_D: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; - break; - default: - return -EINVAL; - } - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); - if (val < 0) - return val; - - return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10; -} - -static int qca808x_cable_test_start(struct phy_device *phydev) -{ - int ret; - - /* perform CDT with the following configs: - * 1. disable hibernation. - * 2. force PHY working in MDI mode. - * 3. for PHY working in 1000BaseT. - * 4. configure the threshold. - */ - - ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); - if (ret < 0) - return ret; - - ret = at803x_config_mdix(phydev, ETH_TP_MDI); - if (ret < 0) - return ret; - - /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ - phydev->duplex = DUPLEX_FULL; - phydev->speed = SPEED_1000; - ret = genphy_c45_pma_setup_forced(phydev); - if (ret < 0) - return ret; - - ret = genphy_setup_forced(phydev); - if (ret < 0) - return ret; - - /* configure the thresholds for open, short, pair ok test */ - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); - - return 0; -} - -static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) -{ - int ret, val; - int pair_a, pair_b, pair_c, pair_d; - - *finished = false; - - ret = at803x_cdt_start(phydev, 0); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev); - if (ret) - return ret; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); - if (val < 0) - return val; - - pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val); - pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val); - pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val); - pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val); - - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, - qca808x_cable_test_result_trans(pair_a)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, - qca808x_cable_test_result_trans(pair_b)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, - qca808x_cable_test_result_trans(pair_c)); - ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, - qca808x_cable_test_result_trans(pair_d)); - - if (qca808x_cdt_fault_length_valid(pair_a)) - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, - qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A)); - if (qca808x_cdt_fault_length_valid(pair_b)) - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B, - qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B)); - if (qca808x_cdt_fault_length_valid(pair_c)) - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C, - qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C)); - if (qca808x_cdt_fault_length_valid(pair_d)) - ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D, - qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D)); - - *finished = true; - - return 0; -} - -static int qca808x_get_features(struct phy_device *phydev) -{ - int ret; - - ret = genphy_c45_pma_read_abilities(phydev); - if (ret) - return ret; - - /* The autoneg ability is not existed in bit3 of MMD7.1, - * but it is supported by qca808x PHY, so we add it here - * manually. - */ - linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); - - /* As for the qca8081 1G version chip, the 2500baseT ability is also - * existed in the bit0 of MMD1.21, we need to remove it manually if - * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. - */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); - if (ret < 0) - return ret; - - if (QCA808X_PHY_CHIP_TYPE_1G & ret) - linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); - - return 0; -} - -static void qca808x_link_change_notify(struct phy_device *phydev) -{ - /* Assert interface sgmii fifo on link down, deassert it on link up, - * the interface device address is always phy address added by 1. - */ - mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, - MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, - QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); -} - -static struct phy_driver at803x_driver[] = { -{ - /* Qualcomm Atheros AR8035 */ - PHY_ID_MATCH_EXACT(ATH8035_PHY_ID), - .name = "Qualcomm Atheros AR8035", - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .config_aneg = at803x_config_aneg, - .config_init = at803x_config_init, - .soft_reset = genphy_soft_reset, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_GBIT_FEATURES */ - .read_status = at803x_read_status, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at803x_cable_test_get_status, -}, { - /* Qualcomm Atheros AR8030 */ - .phy_id = ATH8030_PHY_ID, - .name = "Qualcomm Atheros AR8030", - .phy_id_mask = AT8030_PHY_ID_MASK, - .probe = at803x_probe, - .config_init = at803x_config_init, - .link_change_notify = at803x_link_change_notify, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, -}, { - /* Qualcomm Atheros AR8031/AR8033 */ - PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), - .name = "Qualcomm Atheros AR8031/AR8033", - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .config_init = at803x_config_init, - .config_aneg = at803x_config_aneg, - .soft_reset = genphy_soft_reset, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - .read_page = at803x_read_page, - .write_page = at803x_write_page, - .get_features = at803x_get_features, - .read_status = at803x_read_status, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at803x_cable_test_get_status, -}, { - /* Qualcomm Atheros AR8032 */ - PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), - .name = "Qualcomm Atheros AR8032", - .probe = at803x_probe, - .flags = PHY_POLL_CABLE_TEST, - .config_init = at803x_config_init, - .link_change_notify = at803x_link_change_notify, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at803x_cable_test_get_status, -}, { - /* ATHEROS AR9331 */ - PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), - .name = "Qualcomm Atheros AR9331 built-in PHY", - .probe = at803x_probe, - .suspend = at803x_suspend, - .resume = at803x_resume, - .flags = PHY_POLL_CABLE_TEST, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at803x_cable_test_get_status, - .read_status = at803x_read_status, - .soft_reset = genphy_soft_reset, - .config_aneg = at803x_config_aneg, -}, { - /* Qualcomm Atheros QCA9561 */ - PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), - .name = "Qualcomm Atheros QCA9561 built-in PHY", - .probe = at803x_probe, - .suspend = at803x_suspend, - .resume = at803x_resume, - .flags = PHY_POLL_CABLE_TEST, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at803x_cable_test_get_status, - .read_status = at803x_read_status, - .soft_reset = genphy_soft_reset, - .config_aneg = at803x_config_aneg, -}, { - /* QCA8337 */ - .phy_id = QCA8337_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8337 internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, - .suspend = qca83xx_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-A from switch QCA8327-AL1A */ - .phy_id = QCA8327_A_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-A internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, - .suspend = qca83xx_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-B from switch QCA8327-BL1A */ - .phy_id = QCA8327_B_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-B internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, - .suspend = qca83xx_suspend, - .resume = qca83xx_resume, -}, { - /* Qualcomm QCA8081 */ - PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), - .name = "Qualcomm QCA8081", - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .get_features = qca808x_get_features, - .config_aneg = at803x_config_aneg, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_status = qca808x_read_status, - .config_init = qca808x_config_init, - .soft_reset = qca808x_soft_reset, - .cable_test_start = qca808x_cable_test_start, - .cable_test_get_status = qca808x_cable_test_get_status, - .link_change_notify = qca808x_link_change_notify, -}, }; - -module_phy_driver(at803x_driver); - -static struct mdio_device_id __maybe_unused atheros_tbl[] = { - { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, - { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, - { } -}; - -MODULE_DEVICE_TABLE(mdio, atheros_tbl); diff --git a/drivers/net/phy/ax88796b_rust.rs b/drivers/net/phy/ax88796b_rust.rs new file mode 100644 index 00000000000000..5c92572962dce7 --- /dev/null +++ b/drivers/net/phy/ax88796b_rust.rs @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2023 FUJITA Tomonori + +//! Rust Asix PHYs driver +//! +//! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c) +use kernel::{ + c_str, + net::phy::{self, DeviceId, Driver}, + prelude::*, + uapi, +}; + +kernel::module_phy_driver! { + drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B], + device_table: [ + DeviceId::new_with_driver::(), + DeviceId::new_with_driver::(), + DeviceId::new_with_driver::() + ], + name: "rust_asix_phy", + author: "FUJITA Tomonori ", + description: "Rust Asix PHYs driver", + license: "GPL", +} + +const MII_BMCR: u16 = uapi::MII_BMCR as u16; +const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16; +const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16; + +// Performs a software PHY reset using the standard +// BMCR_RESET bit and poll for the reset bit to be cleared. +// Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation +// such as used on the Individual Computers' X-Surf 100 Zorro card. +fn asix_soft_reset(dev: &mut phy::Device) -> Result { + dev.write(uapi::MII_BMCR as u16, 0)?; + dev.genphy_soft_reset() +} + +struct PhyAX88772A; + +#[vtable] +impl Driver for PhyAX88772A { + const FLAGS: u32 = phy::flags::IS_INTERNAL; + const NAME: &'static CStr = c_str!("Asix Electronics AX88772A"); + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861); + + // AX88772A is not working properly with some old switches (NETGEAR EN 108TP): + // after autoneg is done and the link status is reported as active, the MII_LPA + // register is 0. This issue is not reproducible on AX88772C. + fn read_status(dev: &mut phy::Device) -> Result { + dev.genphy_update_link()?; + if !dev.is_link_up() { + return Ok(0); + } + // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve + // linkmode so use MII_BMCR as default values. + let ret = dev.read(MII_BMCR)?; + + if ret & BMCR_SPEED100 != 0 { + dev.set_speed(uapi::SPEED_100); + } else { + dev.set_speed(uapi::SPEED_10); + } + + let duplex = if ret & BMCR_FULLDPLX != 0 { + phy::DuplexMode::Full + } else { + phy::DuplexMode::Half + }; + dev.set_duplex(duplex); + + dev.genphy_read_lpa()?; + + if dev.is_autoneg_enabled() && dev.is_autoneg_completed() { + dev.resolve_aneg_linkmode(); + } + + Ok(0) + } + + fn suspend(dev: &mut phy::Device) -> Result { + dev.genphy_suspend() + } + + fn resume(dev: &mut phy::Device) -> Result { + dev.genphy_resume() + } + + fn soft_reset(dev: &mut phy::Device) -> Result { + asix_soft_reset(dev) + } + + fn link_change_notify(dev: &mut phy::Device) { + // Reset PHY, otherwise MII_LPA will provide outdated information. + // This issue is reproducible only with some link partner PHYs. + if dev.state() == phy::DeviceState::NoLink { + let _ = dev.init_hw(); + let _ = dev.start_aneg(); + } + } +} + +struct PhyAX88772C; + +#[vtable] +impl Driver for PhyAX88772C { + const FLAGS: u32 = phy::flags::IS_INTERNAL; + const NAME: &'static CStr = c_str!("Asix Electronics AX88772C"); + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881); + + fn suspend(dev: &mut phy::Device) -> Result { + dev.genphy_suspend() + } + + fn resume(dev: &mut phy::Device) -> Result { + dev.genphy_resume() + } + + fn soft_reset(dev: &mut phy::Device) -> Result { + asix_soft_reset(dev) + } +} + +struct PhyAX88796B; + +#[vtable] +impl Driver for PhyAX88796B { + const NAME: &'static CStr = c_str!("Asix Electronics AX88796B"); + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841); + + fn soft_reset(dev: &mut phy::Device) -> Result { + asix_soft_reset(dev) + } +} diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 5f056d7db83eed..760785160ab49e 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -31,6 +31,7 @@ #define DP83869_RGMIICTL 0x0032 #define DP83869_STRAP_STS1 0x006e #define DP83869_RGMIIDCTL 0x0086 +#define DP83869_ANA_PLL_PROG_PI 0x00c6 #define DP83869_RXFCFG 0x0134 #define DP83869_RXFPMD1 0x0136 #define DP83869_RXFPMD2 0x0137 @@ -814,12 +815,22 @@ static int dp83869_config_init(struct phy_device *phydev) dp83869_config_port_mirroring(phydev); /* Clock output selection if muxing property is set */ - if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) + if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { + /* + * Table 7-121 in datasheet says we have to set register 0xc6 + * to value 0x10 before CLK_O_SEL can be modified. + */ + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_ANA_PLL_PROG_PI, 0x10); + if (ret) + return ret; + ret = phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, dp83869->clk_output_sel << DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); + } if (phy_interface_is_rgmii(phydev)) { ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig new file mode 100644 index 00000000000000..2c274fbbe410df --- /dev/null +++ b/drivers/net/phy/qcom/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +config AT803X_PHY + tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" + depends on REGULATOR + help + Currently supports the AR8030, AR8031, AR8033, AR8035 and internal + QCA8337(Internal qca8k PHY) model diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile new file mode 100644 index 00000000000000..6a68da8aaa7bfd --- /dev/null +++ b/drivers/net/phy/qcom/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_AT803X_PHY) += at803x.o diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c new file mode 100644 index 00000000000000..0b01b6ff0a4b50 --- /dev/null +++ b/drivers/net/phy/qcom/at803x.c @@ -0,0 +1,2248 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * drivers/net/phy/at803x.c + * + * Driver for Qualcomm Atheros AR803x PHY + * + * Author: Matus Ujhelyi + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 +#define AT803X_SFC_ASSERT_CRS BIT(11) +#define AT803X_SFC_FORCE_LINK BIT(10) +#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) +#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 +#define AT803X_SFC_MANUAL_MDIX 0x1 +#define AT803X_SFC_MANUAL_MDI 0x0 +#define AT803X_SFC_SQE_TEST BIT(2) +#define AT803X_SFC_POLARITY_REVERSAL BIT(1) +#define AT803X_SFC_DISABLE_JABBER BIT(0) + +#define AT803X_SPECIFIC_STATUS 0x11 +#define AT803X_SS_SPEED_MASK GENMASK(15, 14) +#define AT803X_SS_SPEED_1000 2 +#define AT803X_SS_SPEED_100 1 +#define AT803X_SS_SPEED_10 0 +#define AT803X_SS_DUPLEX BIT(13) +#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) +#define AT803X_SS_MDIX BIT(6) + +#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) +#define QCA808X_SS_SPEED_2500 4 + +#define AT803X_INTR_ENABLE 0x12 +#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) +#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) +#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) +#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) +#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) +#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) +#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) +#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) +#define AT803X_INTR_ENABLE_WOL BIT(0) + +#define AT803X_INTR_STATUS 0x13 + +#define AT803X_SMART_SPEED 0x14 +#define AT803X_SMART_SPEED_ENABLE BIT(5) +#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) +#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) +#define AT803X_CDT 0x16 +#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) +#define AT803X_CDT_ENABLE_TEST BIT(0) +#define AT803X_CDT_STATUS 0x1c +#define AT803X_CDT_STATUS_STAT_NORMAL 0 +#define AT803X_CDT_STATUS_STAT_SHORT 1 +#define AT803X_CDT_STATUS_STAT_OPEN 2 +#define AT803X_CDT_STATUS_STAT_FAIL 3 +#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) +#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) +#define AT803X_LED_CONTROL 0x18 + +#define AT803X_PHY_MMD3_WOL_CTRL 0x8012 +#define AT803X_WOL_EN BIT(5) +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A +#define AT803X_REG_CHIP_CONFIG 0x1f +#define AT803X_BT_BX_REG_SEL 0x8000 + +#define AT803X_DEBUG_ADDR 0x1D +#define AT803X_DEBUG_DATA 0x1E + +#define AT803X_MODE_CFG_MASK 0x0F +#define AT803X_MODE_CFG_BASET_RGMII 0x00 +#define AT803X_MODE_CFG_BASET_SGMII 0x01 +#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 +#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 +#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 +#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 +#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 +#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 +#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B +#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E +#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F + +#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ +#define AT803X_PSSR_MR_AN_COMPLETE 0x0200 + +#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 +#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) +#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) +#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) + +#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 +#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) + +#define AT803X_DEBUG_REG_HIB_CTRL 0x0b +#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) +#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) +#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) + +#define AT803X_DEBUG_REG_3C 0x3C + +#define AT803X_DEBUG_REG_GREEN 0x3D +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) + +#define AT803X_DEBUG_REG_1F 0x1F +#define AT803X_DEBUG_PLL_ON BIT(2) +#define AT803X_DEBUG_RGMII_1V8 BIT(3) + +#define MDIO_AZ_DEBUG 0x800D + +/* AT803x supports either the XTAL input pad, an internal PLL or the + * DSP as clock reference for the clock output pad. The XTAL reference + * is only used for 25 MHz output, all other frequencies need the PLL. + * The DSP as a clock reference is used in synchronous ethernet + * applications. + * + * By default the PLL is only enabled if there is a link. Otherwise + * the PHY will go into low power state and disabled the PLL. You can + * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always + * enabled. + */ +#define AT803X_MMD7_CLK25M 0x8016 +#define AT803X_CLK_OUT_MASK GENMASK(4, 2) +#define AT803X_CLK_OUT_25MHZ_XTAL 0 +#define AT803X_CLK_OUT_25MHZ_DSP 1 +#define AT803X_CLK_OUT_50MHZ_PLL 2 +#define AT803X_CLK_OUT_50MHZ_DSP 3 +#define AT803X_CLK_OUT_62_5MHZ_PLL 4 +#define AT803X_CLK_OUT_62_5MHZ_DSP 5 +#define AT803X_CLK_OUT_125MHZ_PLL 6 +#define AT803X_CLK_OUT_125MHZ_DSP 7 + +/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask + * but doesn't support choosing between XTAL/PLL and DSP. + */ +#define AT8035_CLK_OUT_MASK GENMASK(4, 3) + +#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) +#define AT803X_CLK_OUT_STRENGTH_FULL 0 +#define AT803X_CLK_OUT_STRENGTH_HALF 1 +#define AT803X_CLK_OUT_STRENGTH_QUARTER 2 + +#define AT803X_DEFAULT_DOWNSHIFT 5 +#define AT803X_MIN_DOWNSHIFT 2 +#define AT803X_MAX_DOWNSHIFT 9 + +#define AT803X_MMD3_SMARTEEE_CTL1 0x805b +#define AT803X_MMD3_SMARTEEE_CTL2 0x805c +#define AT803X_MMD3_SMARTEEE_CTL3 0x805d +#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8) + +#define ATH9331_PHY_ID 0x004dd041 +#define ATH8030_PHY_ID 0x004dd076 +#define ATH8031_PHY_ID 0x004dd074 +#define ATH8032_PHY_ID 0x004dd023 +#define ATH8035_PHY_ID 0x004dd072 +#define AT8030_PHY_ID_MASK 0xffffffef + +#define QCA8081_PHY_ID 0x004dd101 + +#define QCA8327_A_PHY_ID 0x004dd033 +#define QCA8327_B_PHY_ID 0x004dd034 +#define QCA8337_PHY_ID 0x004dd036 +#define QCA9561_PHY_ID 0x004dd042 +#define QCA8K_PHY_ID_MASK 0xffffffff + +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) + +#define AT803X_PAGE_FIBER 0 +#define AT803X_PAGE_COPPER 1 + +/* don't turn off internal PLL */ +#define AT803X_KEEP_PLL_ENABLED BIT(0) +#define AT803X_DISABLE_SMARTEEE BIT(1) + +/* disable hibernation mode */ +#define AT803X_DISABLE_HIBERNATION_MODE BIT(2) + +/* ADC threshold */ +#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 +#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) +#define QCA808X_ADC_THRESHOLD_80MV 0 +#define QCA808X_ADC_THRESHOLD_100MV 0xf0 +#define QCA808X_ADC_THRESHOLD_200MV 0x0f +#define QCA808X_ADC_THRESHOLD_300MV 0xff + +/* CLD control */ +#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 +#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) +#define QCA808X_8023AZ_AFE_EN 0x90 + +/* AZ control */ +#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 +#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 +#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E +#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E +#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 +#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 + +#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c +#define QCA808X_TOP_OPTION1_DATA 0x0 + +#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 +#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 +#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 +#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad +#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 +#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 +#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 +#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 +#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 +#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 +#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 +#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 + +/* master/slave seed config */ +#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 +#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) +#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) +#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 + +/* Hibernation yields lower power consumpiton in contrast with normal operation mode. + * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. + */ +#define QCA808X_DBG_AN_TEST 0xb +#define QCA808X_HIBERNATION_EN BIT(15) + +#define QCA808X_CDT_ENABLE_TEST BIT(15) +#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) +#define QCA808X_CDT_LENGTH_UNIT BIT(10) + +#define QCA808X_MMD3_CDT_STATUS 0x8064 +#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 +#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 +#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 +#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 +#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0) + +#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) +#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) +#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) +#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) +#define QCA808X_CDT_STATUS_STAT_FAIL 0 +#define QCA808X_CDT_STATUS_STAT_NORMAL 1 +#define QCA808X_CDT_STATUS_STAT_OPEN 2 +#define QCA808X_CDT_STATUS_STAT_SHORT 3 + +/* QCA808X 1G chip type */ +#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d +#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) + +#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 +#define QCA8081_PHY_FIFO_RSTN BIT(11) + +MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_LICENSE("GPL"); + +enum stat_access_type { + PHY, + MMD +}; + +struct at803x_hw_stat { + const char *string; + u8 reg; + u32 mask; + enum stat_access_type access_type; +}; + +static struct at803x_hw_stat at803x_hw_stats[] = { + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, +}; + +struct at803x_priv { + int flags; + u16 clk_25m_reg; + u16 clk_25m_mask; + u8 smarteee_lpi_tw_1g; + u8 smarteee_lpi_tw_100m; + bool is_fiber; + bool is_1000basex; + struct regulator_dev *vddio_rdev; + struct regulator_dev *vddh_rdev; + u64 stats[ARRAY_SIZE(at803x_hw_stats)]; +}; + +struct at803x_context { + u16 bmcr; + u16 advertise; + u16 control1000; + u16 int_enable; + u16 smart_speed; + u16 led_control; +}; + +static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_write(phydev, AT803X_DEBUG_DATA, data); +} + +static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_read(phydev, AT803X_DEBUG_DATA); +} + +static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set) +{ + u16 val; + int ret; + + ret = at803x_debug_reg_read(phydev, reg); + if (ret < 0) + return ret; + + val = ret & 0xffff; + val &= ~clear; + val |= set; + + return phy_write(phydev, AT803X_DEBUG_DATA, val); +} + +static int at803x_write_page(struct phy_device *phydev, int page) +{ + int mask; + int set; + + if (page == AT803X_PAGE_COPPER) { + set = AT803X_BT_BX_REG_SEL; + mask = 0; + } else { + set = 0; + mask = AT803X_BT_BX_REG_SEL; + } + + return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set); +} + +static int at803x_read_page(struct phy_device *phydev) +{ + int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG); + + if (ccr < 0) + return ccr; + + if (ccr & AT803X_BT_BX_REG_SEL) + return AT803X_PAGE_COPPER; + + return AT803X_PAGE_FIBER; +} + +static int at803x_enable_rx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, + AT803X_DEBUG_RX_CLK_DLY_EN); +} + +static int at803x_enable_tx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, + AT803X_DEBUG_TX_CLK_DLY_EN); +} + +static int at803x_disable_rx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + AT803X_DEBUG_RX_CLK_DLY_EN, 0); +} + +static int at803x_disable_tx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, + AT803X_DEBUG_TX_CLK_DLY_EN, 0); +} + +/* save relevant PHY registers to private copy */ +static void at803x_context_save(struct phy_device *phydev, + struct at803x_context *context) +{ + context->bmcr = phy_read(phydev, MII_BMCR); + context->advertise = phy_read(phydev, MII_ADVERTISE); + context->control1000 = phy_read(phydev, MII_CTRL1000); + context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); + context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); + context->led_control = phy_read(phydev, AT803X_LED_CONTROL); +} + +/* restore relevant PHY registers from private copy */ +static void at803x_context_restore(struct phy_device *phydev, + const struct at803x_context *context) +{ + phy_write(phydev, MII_BMCR, context->bmcr); + phy_write(phydev, MII_ADVERTISE, context->advertise); + phy_write(phydev, MII_CTRL1000, context->control1000); + phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); + phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); + phy_write(phydev, AT803X_LED_CONTROL, context->led_control); +} + +static int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret, irq_enabled; + + if (wol->wolopts & WAKE_MAGIC) { + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i; + static const unsigned int offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return -ENODEV; + + mac = (const u8 *) ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + for (i = 0; i < 3; i++) + phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); + + /* Enable WOL function for 1588 */ + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + 0, AT803X_WOL_EN); + if (ret) + return ret; + } + /* Enable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); + if (ret) + return ret; + } else { + /* Disable WoL function for 1588 */ + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); + if (ret) + return ret; + } + /* Disable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); + if (ret) + return ret; + } + + /* Clear WOL status */ + ret = phy_read(phydev, AT803X_INTR_STATUS); + if (ret < 0) + return ret; + + /* Check if there are other interrupts except for WOL triggered when PHY is + * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can + * be passed up to the interrupt PIN. + */ + irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (irq_enabled < 0) + return irq_enabled; + + irq_enabled &= ~AT803X_INTR_ENABLE_WOL; + if (ret & irq_enabled && !phy_polling_mode(phydev)) + phy_trigger_machine(phydev); + + return 0; +} + +static void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int value; + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + if (value < 0) + return; + + if (value & AT803X_INTR_ENABLE_WOL) + wol->wolopts |= WAKE_MAGIC; +} + +static int at803x_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(at803x_hw_stats); +} + +static void at803x_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) { + strscpy(data + i * ETH_GSTRING_LEN, + at803x_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +static u64 at803x_get_stat(struct phy_device *phydev, int i) +{ + struct at803x_hw_stat stat = at803x_hw_stats[i]; + struct at803x_priv *priv = phydev->priv; + int val; + u64 ret; + + if (stat.access_type == MMD) + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); + else + val = phy_read(phydev, stat.reg); + + if (val < 0) { + ret = U64_MAX; + } else { + val = val & stat.mask; + priv->stats[i] += val; + ret = priv->stats[i]; + } + + return ret; +} + +static void at803x_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) + data[i] = at803x_get_stat(phydev, i); +} + +static int at803x_suspend(struct phy_device *phydev) +{ + int value; + int wol_enabled; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + wol_enabled = value & AT803X_INTR_ENABLE_WOL; + + if (wol_enabled) + value = BMCR_ISOLATE; + else + value = BMCR_PDOWN; + + phy_modify(phydev, MII_BMCR, 0, value); + + return 0; +} + +static int at803x_resume(struct phy_device *phydev) +{ + return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); +} + +static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + + if (selector) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_RGMII_1V8); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_RGMII_1V8, 0); +} + +static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + int val; + + val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); + if (val < 0) + return val; + + return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; +} + +static const struct regulator_ops vddio_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel, + .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel, +}; + +static const unsigned int vddio_voltage_table[] = { + 1500000, + 1800000, +}; + +static const struct regulator_desc vddio_desc = { + .name = "vddio", + .of_match = of_match_ptr("vddio-regulator"), + .n_voltages = ARRAY_SIZE(vddio_voltage_table), + .volt_table = vddio_voltage_table, + .ops = &vddio_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static const struct regulator_ops vddh_regulator_ops = { +}; + +static const struct regulator_desc vddh_desc = { + .name = "vddh", + .of_match = of_match_ptr("vddh-regulator"), + .n_voltages = 1, + .fixed_uV = 2500000, + .ops = &vddh_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int at8031_register_regulators(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct regulator_config config = { }; + + config.dev = dev; + config.driver_data = phydev; + + priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); + if (IS_ERR(priv->vddio_rdev)) { + phydev_err(phydev, "failed to register VDDIO regulator\n"); + return PTR_ERR(priv->vddio_rdev); + } + + priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); + if (IS_ERR(priv->vddh_rdev)) { + phydev_err(phydev, "failed to register VDDH regulator\n"); + return PTR_ERR(priv->vddh_rdev); + } + + return 0; +} + +static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); + __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); + DECLARE_PHY_INTERFACE_MASK(interfaces); + phy_interface_t iface; + + linkmode_zero(phy_support); + phylink_set(phy_support, 1000baseX_Full); + phylink_set(phy_support, 1000baseT_Full); + phylink_set(phy_support, Autoneg); + phylink_set(phy_support, Pause); + phylink_set(phy_support, Asym_Pause); + + linkmode_zero(sfp_support); + sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces); + /* Some modules support 10G modes as well as others we support. + * Mask out non-supported modes so the correct interface is picked. + */ + linkmode_and(sfp_support, phy_support, sfp_support); + + if (linkmode_empty(sfp_support)) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + + iface = sfp_select_interface(phydev->sfp_bus, sfp_support); + + /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes + * interface for use with SFP modules. + * However, some copper modules detected as having a preferred SGMII + * interface do default to and function in 1000Base-X mode, so just + * print a warning and allow such modules, as they may have some chance + * of working. + */ + if (iface == PHY_INTERFACE_MODE_SGMII) + dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); + else if (iface != PHY_INTERFACE_MODE_1000BASEX) + return -EINVAL; + + return 0; +} + +static const struct sfp_upstream_ops at803x_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = at803x_sfp_insert, +}; + +static int at803x_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct at803x_priv *priv = phydev->priv; + u32 freq, strength, tw; + unsigned int sel; + int ret; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) + return 0; + + if (of_property_read_bool(node, "qca,disable-smarteee")) + priv->flags |= AT803X_DISABLE_SMARTEEE; + + if (of_property_read_bool(node, "qca,disable-hibernation-mode")) + priv->flags |= AT803X_DISABLE_HIBERNATION_MODE; + + if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) { + if (!tw || tw > 255) { + phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n"); + return -EINVAL; + } + priv->smarteee_lpi_tw_1g = tw; + } + + if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) { + if (!tw || tw > 255) { + phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n"); + return -EINVAL; + } + priv->smarteee_lpi_tw_100m = tw; + } + + ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); + if (!ret) { + switch (freq) { + case 25000000: + sel = AT803X_CLK_OUT_25MHZ_XTAL; + break; + case 50000000: + sel = AT803X_CLK_OUT_50MHZ_PLL; + break; + case 62500000: + sel = AT803X_CLK_OUT_62_5MHZ_PLL; + break; + case 125000000: + sel = AT803X_CLK_OUT_125MHZ_PLL; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-frequency\n"); + return -EINVAL; + } + + priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel); + priv->clk_25m_mask |= AT803X_CLK_OUT_MASK; + + /* Fixup for the AR8030/AR8035. This chip has another mask and + * doesn't support the DSP reference. Eg. the lowest bit of the + * mask. The upper two bits select the same frequencies. Mask + * the lowest bit here. + * + * Warning: + * There was no datasheet for the AR8030 available so this is + * just a guess. But the AR8035 is listed as pin compatible + * to the AR8030 so there might be a good chance it works on + * the AR8030 too. + */ + if (phydev->drv->phy_id == ATH8030_PHY_ID || + phydev->drv->phy_id == ATH8035_PHY_ID) { + priv->clk_25m_reg &= AT8035_CLK_OUT_MASK; + priv->clk_25m_mask &= AT8035_CLK_OUT_MASK; + } + } + + ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); + if (!ret) { + priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; + switch (strength) { + case AR803X_STRENGTH_FULL: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; + break; + case AR803X_STRENGTH_HALF: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; + break; + case AR803X_STRENGTH_QUARTER: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-strength\n"); + return -EINVAL; + } + } + + /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping + * options. + */ + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + if (of_property_read_bool(node, "qca,keep-pll-enabled")) + priv->flags |= AT803X_KEEP_PLL_ENABLED; + + ret = at8031_register_regulators(phydev); + if (ret < 0) + return ret; + + ret = devm_regulator_get_enable_optional(&phydev->mdio.dev, + "vddio"); + if (ret) { + phydev_err(phydev, "failed to get VDDIO regulator\n"); + return ret; + } + + /* Only AR8031/8033 support 1000Base-X for SFP modules */ + ret = phy_sfp_probe(phydev, &at803x_sfp_ops); + if (ret < 0) + return ret; + } + + return 0; +} + +static int at803x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct at803x_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + ret = at803x_parse_dt(phydev); + if (ret) + return ret; + + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + int mode_cfg; + + if (ccr < 0) + return ccr; + mode_cfg = ccr & AT803X_MODE_CFG_MASK; + + switch (mode_cfg) { + case AT803X_MODE_CFG_BX1000_RGMII_50OHM: + case AT803X_MODE_CFG_BX1000_RGMII_75OHM: + priv->is_1000basex = true; + fallthrough; + case AT803X_MODE_CFG_FX100_RGMII_50OHM: + case AT803X_MODE_CFG_FX100_RGMII_75OHM: + priv->is_fiber = true; + break; + } + + /* Disable WoL in 1588 register which is enabled + * by default + */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); + if (ret) + return ret; + } + + return 0; +} + +static int at803x_get_features(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int err; + + err = genphy_read_abilities(phydev); + if (err) + return err; + + if (phydev->drv->phy_id != ATH8031_PHY_ID) + return 0; + + /* AR8031/AR8033 have different status registers + * for copper and fiber operation. However, the + * extended status register is the same for both + * operation modes. + * + * As a result of that, ESTATUS_1000_XFULL is set + * to 1 even when operating in copper TP mode. + * + * Remove this mode from the supported link modes + * when not operating in 1000BaseX mode. + */ + if (!priv->is_1000basex) + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported); + + return 0; +} + +static int at803x_smarteee_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + u16 mask = 0, val = 0; + int ret; + + if (priv->flags & AT803X_DISABLE_SMARTEEE) + return phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_MMD3_SMARTEEE_CTL3, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0); + + if (priv->smarteee_lpi_tw_1g) { + mask |= 0xff00; + val |= priv->smarteee_lpi_tw_1g << 8; + } + if (priv->smarteee_lpi_tw_100m) { + mask |= 0x00ff; + val |= priv->smarteee_lpi_tw_100m; + } + if (!mask) + return 0; + + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1, + mask, val); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN); +} + +static int at803x_clk_out_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + if (!priv->clk_25m_mask) + return 0; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, + priv->clk_25m_mask, priv->clk_25m_reg); +} + +static int at8031_pll_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is PLL OFF. After a soft reset, the + * values are retained. + */ + if (priv->flags & AT803X_KEEP_PLL_ENABLED) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_PLL_ON); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_PLL_ON, 0); +} + +static int at803x_hibernation_mode_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is hibernation mode enabled. After + * software reset, the value is retained. + */ + if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE)) + return 0; + + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0); +} + +static int at803x_config_init(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int ret; + + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + /* Some bootloaders leave the fiber page selected. + * Switch to the appropriate page (fiber or copper), as otherwise we + * read the PHY capabilities from the wrong page. + */ + phy_lock_mdio_bus(phydev); + ret = at803x_write_page(phydev, + priv->is_fiber ? AT803X_PAGE_FIBER : + AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; + + ret = at8031_pll_config(phydev); + if (ret < 0) + return ret; + } + + /* The RX and TX delay default is: + * after HW reset: RX delay enabled and TX delay disabled + * after SW reset: RX delay enabled, while TX delay retains the + * value before reset. + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + ret = at803x_enable_rx_delay(phydev); + else + ret = at803x_disable_rx_delay(phydev); + if (ret < 0) + return ret; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + ret = at803x_enable_tx_delay(phydev); + else + ret = at803x_disable_tx_delay(phydev); + if (ret < 0) + return ret; + + ret = at803x_smarteee_config(phydev); + if (ret < 0) + return ret; + + ret = at803x_clk_out_config(phydev); + if (ret < 0) + return ret; + + ret = at803x_hibernation_mode_config(phydev); + if (ret < 0) + return ret; + + /* Ar803x extended next page bit is enabled by default. Cisco + * multigig switches read this bit and attempt to negotiate 10Gbps + * rates even if the next page bit is disabled. This is incorrect + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ + return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); +} + +static int at803x_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, AT803X_INTR_STATUS); + + return (err < 0) ? err : 0; +} + +static int at803x_config_intr(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int err; + int value; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + if (err) + return err; + + value |= AT803X_INTR_ENABLE_AUTONEG_ERR; + value |= AT803X_INTR_ENABLE_SPEED_CHANGED; + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; + if (priv->is_fiber) { + value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; + } + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } else { + err = phy_write(phydev, AT803X_INTR_ENABLE, 0); + if (err) + return err; + + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + } + + return err; +} + +static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, int_enabled; + + irq_status = phy_read(phydev, AT803X_INTR_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Read the current enabled interrupts */ + int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (int_enabled < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* See if this was one of our enabled interrupts */ + if (!(irq_status & int_enabled)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + +static void at803x_link_change_notify(struct phy_device *phydev) +{ + /* + * Conduct a hardware reset for AT8030 every time a link loss is + * signalled. This is necessary to circumvent a hardware bug that + * occurs when the cable is unplugged while TX packets are pending + * in the FIFO. In such cases, the FIFO enters an error mode it + * cannot recover from by software. + */ + if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) { + struct at803x_context context; + + at803x_context_save(phydev, &context); + + phy_device_reset(phydev, 1); + msleep(1); + phy_device_reset(phydev, 0); + msleep(1); + + at803x_context_restore(phydev, &context); + + phydev_dbg(phydev, "%s(): phy was reset\n", __func__); + } +} + +static int at803x_read_specific_status(struct phy_device *phydev) +{ + int ss; + + /* Read the AT8035 PHY-Specific Status register, which indicates the + * speed and duplex that the PHY is actually using, irrespective of + * whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { + int sfc, speed; + + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); + if (sfc < 0) + return sfc; + + /* qca8081 takes the different bits for speed value from at803x */ + if (phydev->drv->phy_id == QCA8081_PHY_ID) + speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss); + else + speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss); + + switch (speed) { + case AT803X_SS_SPEED_10: + phydev->speed = SPEED_10; + break; + case AT803X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case AT803X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + case QCA808X_SS_SPEED_2500: + phydev->speed = SPEED_2500; + break; + } + if (ss & AT803X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (ss & AT803X_SS_MDIX) + phydev->mdix = ETH_TP_MDI_X; + else + phydev->mdix = ETH_TP_MDI; + + switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { + case AT803X_SFC_MANUAL_MDI: + phydev->mdix_ctrl = ETH_TP_MDI; + break; + case AT803X_SFC_MANUAL_MDIX: + phydev->mdix_ctrl = ETH_TP_MDI_X; + break; + case AT803X_SFC_AUTOMATIC_CROSSOVER: + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + break; + } + } + + return 0; +} + +static int at803x_read_status(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int err, old_link = phydev->link; + + if (priv->is_1000basex) + return genphy_c37_read_status(phydev); + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + err = genphy_read_lpa(phydev); + if (err < 0) + return err; + + err = at803x_read_specific_status(phydev); + if (err < 0) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + return 0; +} + +static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) +{ + u16 val; + + switch (ctrl) { + case ETH_TP_MDI: + val = AT803X_SFC_MANUAL_MDI; + break; + case ETH_TP_MDI_X: + val = AT803X_SFC_MANUAL_MDIX; + break; + case ETH_TP_MDI_AUTO: + val = AT803X_SFC_AUTOMATIC_CROSSOVER; + break; + default: + return 0; + } + + return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, + AT803X_SFC_MDI_CROSSOVER_MODE_M, + FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); +} + +static int at803x_config_aneg(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int ret; + + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); + if (ret < 0) + return ret; + + /* Changes of the midx bits are disruptive to the normal operation; + * therefore any changes to these registers must be followed by a + * software reset to take effect. + */ + if (ret == 1) { + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + } + + if (priv->is_1000basex) + return genphy_c37_config_aneg(phydev); + + /* Do not restart auto-negotiation by setting ret to 0 defautly, + * when calling __genphy_config_aneg later. + */ + ret = 0; + + if (phydev->drv->phy_id == QCA8081_PHY_ID) { + int phy_ctrl = 0; + + /* The reg MII_BMCR also needs to be configured for force mode, the + * genphy_config_aneg is also needed. + */ + if (phydev->autoneg == AUTONEG_DISABLE) + genphy_c45_pma_setup_forced(phydev); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) + phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); + if (ret < 0) + return ret; + } + + return __genphy_config_aneg(phydev, ret); +} + +static int at803x_get_downshift(struct phy_device *phydev, u8 *d) +{ + int val; + + val = phy_read(phydev, AT803X_SMART_SPEED); + if (val < 0) + return val; + + if (val & AT803X_SMART_SPEED_ENABLE) + *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; + else + *d = DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) +{ + u16 mask, set; + int ret; + + switch (cnt) { + case DOWNSHIFT_DEV_DEFAULT_COUNT: + cnt = AT803X_DEFAULT_DOWNSHIFT; + fallthrough; + case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: + set = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER | + FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); + mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; + break; + case DOWNSHIFT_DEV_DISABLE: + set = 0; + mask = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER; + break; + default: + return -EINVAL; + } + + ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); + + /* After changing the smart speed settings, we need to perform a + * software reset, use phy_init_hw() to make sure we set the + * reapply any values which might got lost during software reset. + */ + if (ret == 1) + ret = phy_init_hw(phydev); + + return ret; +} + +static int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +static int at803x_cable_test_result_trans(u16 status) +{ + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { + case AT803X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case AT803X_CDT_STATUS_STAT_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case AT803X_CDT_STATUS_STAT_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case AT803X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static bool at803x_cdt_test_failed(u16 status) +{ + return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == + AT803X_CDT_STATUS_STAT_FAIL; +} + +static bool at803x_cdt_fault_length_valid(u16 status) +{ + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { + case AT803X_CDT_STATUS_STAT_OPEN: + case AT803X_CDT_STATUS_STAT_SHORT: + return true; + } + return false; +} + +static int at803x_cdt_fault_length(u16 status) +{ + int dt; + + /* According to the datasheet the distance to the fault is + * DELTA_TIME * 0.824 meters. + * + * The author suspect the correct formula is: + * + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 + * + * where c is the speed of light, VF is the velocity factor of + * the twisted pair cable, 125MHz the counter frequency and + * we need to divide by 2 because the hardware will measure the + * round trip time to the fault and back to the PHY. + * + * With a VF of 0.69 we get the factor 0.824 mentioned in the + * datasheet. + */ + dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status); + + return (dt * 824) / 10; +} + +static int at803x_cdt_start(struct phy_device *phydev, int pair) +{ + u16 cdt; + + /* qca8081 takes the different bit 15 to enable CDT test */ + if (phydev->drv->phy_id == QCA8081_PHY_ID) + cdt = QCA808X_CDT_ENABLE_TEST | + QCA808X_CDT_LENGTH_UNIT | + QCA808X_CDT_INTER_CHECK_DIS; + else + cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | + AT803X_CDT_ENABLE_TEST; + + return phy_write(phydev, AT803X_CDT, cdt); +} + +static int at803x_cdt_wait_for_completion(struct phy_device *phydev) +{ + int val, ret; + u16 cdt_en; + + if (phydev->drv->phy_id == QCA8081_PHY_ID) + cdt_en = QCA808X_CDT_ENABLE_TEST; + else + cdt_en = AT803X_CDT_ENABLE_TEST; + + /* One test run takes about 25ms */ + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, + !(val & cdt_en), + 30000, 100000, true); + + return ret < 0 ? ret : 0; +} + +static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) +{ + static const int ethtool_pair[] = { + ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_PAIR_B, + ETHTOOL_A_CABLE_PAIR_C, + ETHTOOL_A_CABLE_PAIR_D, + }; + int ret, val; + + ret = at803x_cdt_start(phydev, pair); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev); + if (ret) + return ret; + + val = phy_read(phydev, AT803X_CDT_STATUS); + if (val < 0) + return val; + + if (at803x_cdt_test_failed(val)) + return 0; + + ethnl_cable_test_result(phydev, ethtool_pair[pair], + at803x_cable_test_result_trans(val)); + + if (at803x_cdt_fault_length_valid(val)) + ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], + at803x_cdt_fault_length(val)); + + return 1; +} + +static int at803x_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + unsigned long pair_mask; + int retries = 20; + int pair, ret; + + if (phydev->phy_id == ATH9331_PHY_ID || + phydev->phy_id == ATH8032_PHY_ID || + phydev->phy_id == QCA9561_PHY_ID) + pair_mask = 0x3; + else + pair_mask = 0xf; + + *finished = false; + + /* According to the datasheet the CDT can be performed when + * there is no link partner or when the link partner is + * auto-negotiating. Starting the test will restart the AN + * automatically. It seems that doing this repeatedly we will + * get a slot where our link partner won't disturb our + * measurement. + */ + while (pair_mask && retries--) { + for_each_set_bit(pair, &pair_mask, 4) { + ret = at803x_cable_test_one_pair(phydev, pair); + if (ret < 0) + return ret; + if (ret) + clear_bit(pair, &pair_mask); + } + if (pair_mask) + msleep(250); + } + + *finished = true; + + return 0; +} + +static int at803x_cable_test_start(struct phy_device *phydev) +{ + /* Enable auto-negotiation, but advertise no capabilities, no link + * will be established. A restart of the auto-negotiation is not + * required, because the cable test will automatically break the link. + */ + phy_write(phydev, MII_BMCR, BMCR_ANENABLE); + phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); + if (phydev->phy_id != ATH9331_PHY_ID && + phydev->phy_id != ATH8032_PHY_ID && + phydev->phy_id != QCA9561_PHY_ID) + phy_write(phydev, MII_CTRL1000, 0); + + /* we do all the (time consuming) work later */ + return 0; +} + +static int qca83xx_config_init(struct phy_device *phydev) +{ + u8 switch_revision; + + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; + + switch (switch_revision) { + case 1: + /* For 100M waveform */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); + /* Turn on Gigabit clock */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); + break; + + case 2: + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + fallthrough; + case 4: + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); + at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); + break; + } + + /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. + * Disable on init and enable only with 100m speed following + * qca original source code. + */ + if (phydev->drv->phy_id == QCA8327_A_PHY_ID || + phydev->drv->phy_id == QCA8327_B_PHY_ID) + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + + /* Following original QCA sourcecode set port to prefer master */ + phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); + + return 0; +} + +static void qca83xx_link_change_notify(struct phy_device *phydev) +{ + /* QCA8337 doesn't require DAC Amplitude adjustement */ + if (phydev->drv->phy_id == QCA8337_PHY_ID) + return; + + /* Set DAC Amplitude adjustment to +6% for 100m on link running */ + if (phydev->state == PHY_RUNNING) { + if (phydev->speed == SPEED_100) + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, + QCA8327_DEBUG_MANU_CTRL_EN); + } else { + /* Reset DAC Amplitude adjustment */ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + } +} + +static int qca83xx_resume(struct phy_device *phydev) +{ + int ret, val; + + /* Skip reset if not suspended */ + if (!phydev->suspended) + return 0; + + /* Reinit the port, reset values set by suspend */ + qca83xx_config_init(phydev); + + /* Reset the port on port resume */ + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + + /* On resume from suspend the switch execute a reset and + * restart auto-negotiation. Wait for reset to complete. + */ + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret) + return ret; + + msleep(1); + + return 0; +} + +static int qca83xx_suspend(struct phy_device *phydev) +{ + u16 mask = 0; + + /* Only QCA8337 support actual suspend. + * QCA8327 cause port unreliability when phy suspend + * is set. + */ + if (phydev->drv->phy_id == QCA8337_PHY_ID) { + genphy_suspend(phydev); + } else { + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); + phy_modify(phydev, MII_BMCR, mask, 0); + } + + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, + AT803X_DEBUG_GATE_CLK_IN1000, 0); + + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); + + return 0; +} + +static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) +{ + int ret; + + /* Enable fast retrain */ + ret = genphy_c45_fast_retrain(phydev, true); + if (ret) + return ret; + + phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, + QCA808X_TOP_OPTION1_DATA); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, + QCA808X_MSE_THRESHOLD_20DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, + QCA808X_MSE_THRESHOLD_17DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, + QCA808X_MSE_THRESHOLD_27DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, + QCA808X_MSE_THRESHOLD_28DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, + QCA808X_MMD3_DEBUG_1_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, + QCA808X_MMD3_DEBUG_4_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, + QCA808X_MMD3_DEBUG_5_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, + QCA808X_MMD3_DEBUG_3_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, + QCA808X_MMD3_DEBUG_6_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, + QCA808X_MMD3_DEBUG_2_VALUE); + + return 0; +} + +static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) +{ + u16 seed_value; + + if (!enable) + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); + + seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, + FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | + QCA808X_MASTER_SLAVE_SEED_ENABLE); +} + +static bool qca808x_is_prefer_master(struct phy_device *phydev) +{ + return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || + (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); +} + +static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) +{ + return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); +} + +static int qca808x_config_init(struct phy_device *phydev) +{ + int ret; + + /* Active adc&vga on 802.3az for the link 1000M and 100M */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, + QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); + if (ret) + return ret; + + /* Adjust the threshold on 802.3az for the link 1000M */ + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL); + if (ret) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + /* Config the fast retrain for the link 2500M */ + ret = qca808x_phy_fast_retrain_config(phydev); + if (ret) + return ret; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) + return ret; + + if (!qca808x_is_prefer_master(phydev)) { + /* Enable seed and configure lower ramdom seed to make phy + * linked as slave mode. + */ + ret = qca808x_phy_ms_seed_enable(phydev, true); + if (ret) + return ret; + } + } + + /* Configure adc threshold as 100mv for the link 10M */ + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, + QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV); +} + +static int qca808x_read_status(struct phy_device *phydev) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (ret < 0) + return ret; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, + ret & MDIO_AN_10GBT_STAT_LP2_5G); + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + ret = at803x_read_specific_status(phydev); + if (ret < 0) + return ret; + + if (phydev->link) { + if (phydev->speed == SPEED_2500) + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + else + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } else { + /* generate seed as a lower random value to make PHY linked as SLAVE easily, + * except for master/slave configuration fault detected or the master mode + * preferred. + * + * the reason for not putting this code into the function link_change_notify is + * the corner case where the link partner is also the qca8081 PHY and the seed + * value is configured as the same value, the link can't be up and no link change + * occurs. + */ + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || + qca808x_is_prefer_master(phydev)) { + qca808x_phy_ms_seed_enable(phydev, false); + } else { + qca808x_phy_ms_seed_enable(phydev, true); + } + } + } + + return 0; +} + +static int qca808x_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) + ret = qca808x_phy_ms_seed_enable(phydev, true); + + return ret; +} + +static bool qca808x_cdt_fault_length_valid(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_SHORT: + case QCA808X_CDT_STATUS_STAT_OPEN: + return true; + default: + return false; + } +} + +static int qca808x_cable_test_result_trans(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case QCA808X_CDT_STATUS_STAT_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case QCA808X_CDT_STATUS_STAT_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA808X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair) +{ + int val; + u32 cdt_length_reg = 0; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; + break; + case ETHTOOL_A_CABLE_PAIR_B: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; + break; + case ETHTOOL_A_CABLE_PAIR_C: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; + break; + case ETHTOOL_A_CABLE_PAIR_D: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; + break; + default: + return -EINVAL; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); + if (val < 0) + return val; + + return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10; +} + +static int qca808x_cable_test_start(struct phy_device *phydev) +{ + int ret; + + /* perform CDT with the following configs: + * 1. disable hibernation. + * 2. force PHY working in MDI mode. + * 3. for PHY working in 1000BaseT. + * 4. configure the threshold. + */ + + ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); + if (ret < 0) + return ret; + + ret = at803x_config_mdix(phydev, ETH_TP_MDI); + if (ret < 0) + return ret; + + /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + ret = genphy_c45_pma_setup_forced(phydev); + if (ret < 0) + return ret; + + ret = genphy_setup_forced(phydev); + if (ret < 0) + return ret; + + /* configure the thresholds for open, short, pair ok test */ + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); + + return 0; +} + +static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) +{ + int ret, val; + int pair_a, pair_b, pair_c, pair_d; + + *finished = false; + + ret = at803x_cdt_start(phydev, 0); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev); + if (ret) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); + if (val < 0) + return val; + + pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val); + pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val); + pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val); + pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val); + + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, + qca808x_cable_test_result_trans(pair_a)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, + qca808x_cable_test_result_trans(pair_b)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, + qca808x_cable_test_result_trans(pair_c)); + ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, + qca808x_cable_test_result_trans(pair_d)); + + if (qca808x_cdt_fault_length_valid(pair_a)) + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A, + qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A)); + if (qca808x_cdt_fault_length_valid(pair_b)) + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B, + qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B)); + if (qca808x_cdt_fault_length_valid(pair_c)) + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C, + qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C)); + if (qca808x_cdt_fault_length_valid(pair_d)) + ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D, + qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D)); + + *finished = true; + + return 0; +} + +static int qca808x_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + /* The autoneg ability is not existed in bit3 of MMD7.1, + * but it is supported by qca808x PHY, so we add it here + * manually. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + + /* As for the qca8081 1G version chip, the 2500baseT ability is also + * existed in the bit0 of MMD1.21, we need to remove it manually if + * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. + */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); + if (ret < 0) + return ret; + + if (QCA808X_PHY_CHIP_TYPE_1G & ret) + linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); + + return 0; +} + +static void qca808x_link_change_notify(struct phy_device *phydev) +{ + /* Assert interface sgmii fifo on link down, deassert it on link up, + * the interface device address is always phy address added by 1. + */ + mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, + MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, + QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); +} + +static struct phy_driver at803x_driver[] = { +{ + /* Qualcomm Atheros AR8035 */ + PHY_ID_MATCH_EXACT(ATH8035_PHY_ID), + .name = "Qualcomm Atheros AR8035", + .flags = PHY_POLL_CABLE_TEST, + .probe = at803x_probe, + .config_aneg = at803x_config_aneg, + .config_init = at803x_config_init, + .soft_reset = genphy_soft_reset, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_GBIT_FEATURES */ + .read_status = at803x_read_status, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at803x_cable_test_get_status, +}, { + /* Qualcomm Atheros AR8030 */ + .phy_id = ATH8030_PHY_ID, + .name = "Qualcomm Atheros AR8030", + .phy_id_mask = AT8030_PHY_ID_MASK, + .probe = at803x_probe, + .config_init = at803x_config_init, + .link_change_notify = at803x_link_change_notify, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, +}, { + /* Qualcomm Atheros AR8031/AR8033 */ + PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), + .name = "Qualcomm Atheros AR8031/AR8033", + .flags = PHY_POLL_CABLE_TEST, + .probe = at803x_probe, + .config_init = at803x_config_init, + .config_aneg = at803x_config_aneg, + .soft_reset = genphy_soft_reset, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + .read_page = at803x_read_page, + .write_page = at803x_write_page, + .get_features = at803x_get_features, + .read_status = at803x_read_status, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at803x_cable_test_get_status, +}, { + /* Qualcomm Atheros AR8032 */ + PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), + .name = "Qualcomm Atheros AR8032", + .probe = at803x_probe, + .flags = PHY_POLL_CABLE_TEST, + .config_init = at803x_config_init, + .link_change_notify = at803x_link_change_notify, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at803x_cable_test_get_status, +}, { + /* ATHEROS AR9331 */ + PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), + .name = "Qualcomm Atheros AR9331 built-in PHY", + .probe = at803x_probe, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at803x_cable_test_get_status, + .read_status = at803x_read_status, + .soft_reset = genphy_soft_reset, + .config_aneg = at803x_config_aneg, +}, { + /* Qualcomm Atheros QCA9561 */ + PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), + .name = "Qualcomm Atheros QCA9561 built-in PHY", + .probe = at803x_probe, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at803x_cable_test_get_status, + .read_status = at803x_read_status, + .soft_reset = genphy_soft_reset, + .config_aneg = at803x_config_aneg, +}, { + /* QCA8337 */ + .phy_id = QCA8337_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8337 internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, + .suspend = qca83xx_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-A from switch QCA8327-AL1A */ + .phy_id = QCA8327_A_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-A internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, + .suspend = qca83xx_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-B from switch QCA8327-BL1A */ + .phy_id = QCA8327_B_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-B internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, + .suspend = qca83xx_suspend, + .resume = qca83xx_resume, +}, { + /* Qualcomm QCA8081 */ + PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), + .name = "Qualcomm QCA8081", + .flags = PHY_POLL_CABLE_TEST, + .probe = at803x_probe, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .get_features = qca808x_get_features, + .config_aneg = at803x_config_aneg, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_status = qca808x_read_status, + .config_init = qca808x_config_init, + .soft_reset = qca808x_soft_reset, + .cable_test_start = qca808x_cable_test_start, + .cable_test_get_status = qca808x_cable_test_get_status, + .link_change_notify = qca808x_link_change_notify, +}, }; + +module_phy_driver(at803x_driver); + +static struct mdio_device_id __maybe_unused atheros_tbl[] = { + { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, + { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, atheros_tbl); diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 46ac51217114bd..2b5843d14cbb84 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1062,6 +1062,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct ppp_net *pn; int __user *p = (int __user *)arg; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + return -EPERM; + switch (cmd) { case PPPIOCNEWUNIT: /* Create a new ppp unit */ @@ -2242,7 +2245,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) */ static void __ppp_decompress_proto(struct sk_buff *skb) { - if (skb->data[0] & 0x01) + if (ppp_skb_is_compressed_proto(skb)) *(u8 *)skb_push(skb, 1) = 0x00; } diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 96cca4ee470a4b..bc726b54ca745d 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, if (skb_mac_header_len(skb) < ETH_HLEN) goto drop; - if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) + if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) goto drop; ph = pppoe_hdr(skb); @@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->len < len) goto drop; + /* skb->data points to the PPP protocol header after skb_pull_rcsum. + * Drop PFC frames. + */ + if (ppp_skb_is_compressed_proto(skb)) + goto drop; + if (pskb_trim_rcsum(skb, len)) goto drop; diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index bf9e801cc61cce..ef586ab250747a 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -80,9 +80,9 @@ #include static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); +static long decode(unsigned char **cpp, const unsigned char *end); static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); +static long pull16(unsigned char **cpp, const unsigned char *end); /* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression) @@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) return cp; } -/* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) +/* Pull a 16-bit integer in host order from buffer in network byte order. + * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. + */ +static long +pull16(unsigned char **cpp, const unsigned char *end) { - short rval; + long rval; + if (*cpp + 2 > end) + return -1; rval = *(*cpp)++; rval <<= 8; rval |= *(*cpp)++; return rval; } -/* Decode a number */ +/* Decode a number. Returns -1 if the buffer is exhausted. */ static long -decode(unsigned char **cpp) +decode(unsigned char **cpp, const unsigned char *end) { int x; + if (*cpp >= end) + return -1; x = *(*cpp)++; - if(x == 0){ - return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ - } else { - return x & 0xff; /* -1 if PULLCHAR returned error */ - } + if (x == 0) + return pull16(cpp, end); + return x & 0xff; } /* @@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) struct cstate *cs; int len, hdrlen; unsigned char *cp = icp; + const unsigned char *end = icp + isize; /* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++; @@ -506,6 +511,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) comp->sls_i_error++; return 0; } + if (!comp->rstate) + goto bad; changes = *cp++; if(changes & NEW_C){ /* Make sure the state index is in range, then grab the state. @@ -534,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) thp = &cs->cs_tcp; ip = &cs->cs_ip; + if (cp + 2 > end) + goto bad; thp->check = *(__sum16 *)cp; cp += 2; @@ -564,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) default: if(changes & NEW_U){ thp->urg = 1; - if((x = decode(&cp)) == -1) { + if((x = decode(&cp, end)) == -1) { goto bad; } thp->urg_ptr = htons(x); } else thp->urg = 0; if(changes & NEW_W){ - if((x = decode(&cp)) == -1) { + if((x = decode(&cp, end)) == -1) { goto bad; } thp->window = htons( ntohs(thp->window) + x); } if(changes & NEW_A){ - if((x = decode(&cp)) == -1) { + if((x = decode(&cp, end)) == -1) { goto bad; } thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); } if(changes & NEW_S){ - if((x = decode(&cp)) == -1) { + if((x = decode(&cp, end)) == -1) { goto bad; } thp->seq = htonl( ntohl(thp->seq) + x); @@ -591,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) break; } if(changes & NEW_I){ - if((x = decode(&cp)) == -1) { + if((x = decode(&cp, end)) == -1) { goto bad; } ip->id = htons (ntohs (ip->id) + x); @@ -649,6 +658,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) struct cstate *cs; unsigned int ihl; + if (!comp->rstate) { + comp->sls_i_error++; + return slhc_toss(comp); + } /* The packet is shorter than a legal IP header. * Also make sure isize is positive. */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 91cf24fb5531fb..d39d66e25b01b9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3859,7 +3859,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) case RTL_VER_15: ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); ocp_data &= ~OOBS_POLLING; - ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); break; default: break; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index e40b0669d9f4ba..647f28b367b991 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); + unsigned int skb_len; int count, res; /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ @@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } + skb_len = skb->len; + netif_stop_queue(netdev); dev->tx_skb = skb; usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), @@ -709,9 +712,16 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, netdev->stats.tx_errors++; netif_start_queue(netdev); } + /* + * The URB was not submitted, so write_bulk_callback() will + * never run to free dev->tx_skb. Drop the skb here and + * clear tx_skb to avoid leaving a stale pointer. + */ + dev->tx_skb = NULL; + dev_kfree_skb_any(skb); } else { netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; + netdev->stats.tx_bytes += skb_len; netif_trans_update(netdev); } diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 64114e98d75d0e..9f7b05a010519a 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1126,6 +1126,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, err: port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; + synchronize_net(); return ret; } @@ -1145,10 +1146,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, } /* inverse of do_vrf_add_slave */ -static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) +static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, + bool needs_sync) { netdev_upper_dev_unlink(port_dev, dev); port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; + /* Make sure that concurrent RCU readers that identified the device + * as a VRF port see a VRF master or no master at all. + */ + if (needs_sync) + synchronize_net(); cycle_netdev(port_dev, NULL); @@ -1157,7 +1164,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) { - return do_vrf_del_slave(dev, port_dev); + return do_vrf_del_slave(dev, port_dev, true); } static void vrf_dev_uninit(struct net_device *dev) @@ -1714,7 +1721,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) struct list_head *iter; netdev_for_each_lower_dev(dev, port_dev, iter) - vrf_del_slave(dev, port_dev); + do_vrf_del_slave(dev, port_dev, false); vrf_map_unregister_dev(dev); @@ -1845,7 +1852,7 @@ static int vrf_device_event(struct notifier_block *unused, goto out; vrf_dev = netdev_master_upper_dev_get(dev); - vrf_del_slave(vrf_dev, dev); + do_vrf_del_slave(vrf_dev, dev, false); } out: return NOTIFY_DONE; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 2ef92ef25517e8..4dbb1898f3065c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -1006,18 +1006,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, SI_ENUM_BASE_DEFAULT, 0); + if (IS_ERR(core)) + return PTR_ERR(core); + brcmf_chip_sb_corerev(ci, core); core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, BCM4329_CORE_BUS_BASE, 0); + if (IS_ERR(core)) + return PTR_ERR(core); + brcmf_chip_sb_corerev(ci, core); core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, BCM4329_CORE_SOCRAM_BASE, 0); + if (IS_ERR(core)) + return PTR_ERR(core); + brcmf_chip_sb_corerev(ci, core); core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, BCM4329_CORE_ARM_BASE, 0); + if (IS_ERR(core)) + return PTR_ERR(core); + brcmf_chip_sb_corerev(ci, core); core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); + if (IS_ERR(core)) + return PTR_ERR(core); + brcmf_chip_sb_corerev(ci, core); } else if (socitype == SOCI_AI) { ci->iscoreup = brcmf_chip_ai_iscoreup; diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index 34b4b34276d6d3..042b1fe5f0d676 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { spin_unlock_bh(&priv->wmm.ra_list_spinlock); + mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); return -1; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 7ba789834e8df3..1e473f490b4bd3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1174,21 +1174,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, } EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); -void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - u32 addr; - - addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; - - if (enable) - mt76_set(dev, addr, MT_WTBL_W3_RTS); - else - mt76_clear(dev, addr, MT_WTBL_W3_RTS); -} -EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); - static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index dab16b5fc38611..b908ccfa487785 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -597,9 +597,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_ERP_CTS_PROT) - mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); - if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { mt7615_mcu_add_bss_info(phy, vif, NULL, true); mt7615_mcu_sta_add(phy, vif, NULL, true); @@ -612,6 +609,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, BSS_CHANGED_BEACON_ENABLED)) mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, + info->use_cts_prot); + if (changed & BSS_CHANGED_PS) mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 94adb22f8570f5..d5071981014eed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2560,3 +2560,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), &req, sizeof(req), false); } + +int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot) +{ + struct mt7615_dev *dev = phy->dev; + struct { + u8 prot_idx; + u8 band; + u8 rsv[2]; + + bool long_nav; + bool prot_mm; + bool prot_gf; + bool prot_bw40; + bool prot_rifs; + bool prot_bw80; + bool prot_bw160; + u8 prot_erp_mask; + } __packed req = { + .prot_idx = 0x2, + .band = phy != &dev->phy, + }; + + switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + req.prot_mm = true; + req.prot_gf = true; + fallthrough; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + req.prot_bw40 = true; + break; + } + + if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + req.prot_gf = true; + + if (use_cts_prot) { + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; + + req.prot_erp_mask = BIT(i); + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, + sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index fa83b255e180c3..39388acfb94ba3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -466,8 +466,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); -void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable); void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, @@ -522,7 +520,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); - +int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot); int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 806b3887c541c8..9e6d55c91b269f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -455,8 +455,6 @@ enum mt7615_reg_base { #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) -#define MT_WTBL_W3_RTS BIT(22) - #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) #define MT_WTBL_W5_SHORT_GI_20 BIT(8) #define MT_WTBL_W5_SHORT_GI_40 BIT(9) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 6a637d4f42360d..a24b2fd3c7b82c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -1121,8 +1121,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) return; wcid = (struct mt76_wcid *)sta->drv_priv; - if (!test_and_set_bit(tid, &wcid->ampdu_state)) - ieee80211_start_tx_ba_session(sta, tid, 0); + if (!test_and_set_bit(tid, &wcid->ampdu_state)) { + if (ieee80211_start_tx_ba_session(sta, tid, 0)) + clear_bit(tid, &wcid->ampdu_state); + } } EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index e9068718b3d1f6..529a3640944b55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -1254,6 +1254,7 @@ free_phy2: void mt7915_unregister_device(struct mt7915_dev *dev) { + cancel_work_sync(&dev->dump_work); mt7915_unregister_ext_phy(dev); mt7915_coredump_unregister(dev); mt7915_unregister_thermal(&dev->phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 92d7dc8e3cc55e..e2983dbf05a90e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -228,19 +228,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } -void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, - struct ieee80211_vif *vif, bool enable) -{ - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - u32 addr; - - addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); - if (enable) - mt76_set(dev, addr, BIT(5)); - else - mt76_clear(dev, addr, BIT(5)); -} - static void mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, struct mt7915_sta *msta, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index c312a0fa199aee..bad92fa4c8fc64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) if (ret) goto out; - ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, + ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, phy->mt76->band_idx); if (ret) goto out; @@ -623,8 +623,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, if (set_sta == 1) mt7915_mcu_add_sta(dev, vif, NULL, true); - if (changed & BSS_CHANGED_ERP_CTS_PROT) - mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, + info->use_cts_prot); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index fae9ec98da3b9d..f826089396e489 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3730,6 +3730,68 @@ out: return ret; } +int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot) +{ + struct mt7915_dev *dev = phy->dev; + int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct bss_info_prot *prot; + struct sk_buff *skb; + struct tlv *tlv; + enum { + PROT_NONMEMBER = BIT(1), + PROT_20MHZ = BIT(2), + PROT_NONHT_MIXED = BIT(3), + PROT_LEGACY_ERP = BIT(5), + PROT_NONGF_STA = BIT(7), + }; + u32 rts_threshold; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + NULL, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, + sizeof(*prot)); + prot = (struct bss_info_prot *)tlv; + + switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot->prot_mode = cpu_to_le32(PROT_20MHZ); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); + break; + } + + if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); + + if (use_cts_prot) + prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); + + /* reuse current RTS setting */ + rts_threshold = phy->mt76->hw->wiphy->rts_threshold; + if (rts_threshold == (u32)-1) + prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); + else + prot->rts_len_thres = cpu_to_le32(rts_threshold); + + prot->rts_pkt_thres = 0x2; + + prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + if (!prot->he_rts_thres) + prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(BSS_INFO_UPDATE), true); +} + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct cfg80211_he_bss_color *he_bss_color) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 1592b5d6751a0f..acc1371a94b10a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -399,6 +399,17 @@ struct bss_info_inband_discovery { __le16 prob_rsp_len; } __packed __aligned(4); +struct bss_info_prot { + __le16 tag; + __le16 len; + __le32 prot_type; + __le32 prot_mode; + __le32 rts_len_thres; + __le16 he_rts_thres; + u8 rts_pkt_thres; + u8 rsv[5]; +} __packed; + enum { BSS_INFO_BCN_CSA, BSS_INFO_BCN_BCC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 14d4bbeae9d63f..b16c798ec2824a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -83,6 +83,8 @@ #define MT7915_CRIT_TEMP 110 #define MT7915_MAX_TEMP 120 +#define MT7915_RTS_LEN_THRES 0x92b + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -453,6 +455,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v u32 changed); int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable, u32 changed); +int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot); int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 3dd503b363ce00..9270a68e6a38d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -528,7 +528,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; - if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) + if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 8ab55fc705f076..9f8c312b64d75c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -204,7 +204,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, event = (struct mt7996_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); /* skip invalid event */ - if (mcu_cmd != event->cid) + if (mcu_cmd != le16_to_cpu(event->cid)) ret = -EAGAIN; } else { skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 58504b80eae8b0..fee79666fe1620 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { }; struct mt7996_mcu_uni_event { - u8 cid; - u8 __rsv[3]; + __le16 cid; + u8 __rsv[2]; __le32 status; /* 0: success, others: fail */ } __packed; diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 40112b2c37775d..b978d31e47ca91 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1675,6 +1675,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) synchronize_irq(rtlpci->pdev->irq); tasklet_kill(&rtlpriv->works.irq_tasklet); + tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); cancel_work_sync(&rtlpriv->works.lps_change_work); } diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 457c1dd31bf9d9..3da2f623c01c69 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2434,7 +2434,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, { struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; const struct rtw89_chip_info *chip = rtwdev->chip; - u8 sc_xi_val, sc_xo_val; + u8 sc_xi_val = 0, sc_xo_val = 0; if (!force && cfo->crystal_cap == crystal_cap) return; diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 9e1a34e23af26e..6b8311f526a5e3 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -311,6 +311,7 @@ #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) +#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) @@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) if (ret) return ret; - if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) + if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) *is_rf_field = true; else *is_rf_field = false; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 40d9be6468b5ed..87d30aaa35f10c 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1715,6 +1715,7 @@ release_cq: static const struct blk_mq_ops nvme_mq_admin_ops = { .queue_rq = nvme_queue_rq, .complete = nvme_pci_complete_rq, + .commit_rqs = nvme_commit_rqs, .init_hctx = nvme_admin_init_hctx, .init_request = nvme_pci_init_request, .timeout = nvme_timeout, diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 4d1f260ae60abc..5f85c4a812abcd 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -335,7 +335,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); -static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) +static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) { struct bio_vec *iov = cmd->iov; struct scatterlist *sg; @@ -348,22 +348,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) offset = cmd->rbytes_done; cmd->sg_idx = offset / PAGE_SIZE; sg_offset = offset % PAGE_SIZE; - if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } + if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) + return -EPROTO; + sg = &cmd->req.sg[cmd->sg_idx]; sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; while (length) { - if (!sg_remaining) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } - if (!sg->length || sg->length <= sg_offset) { - nvmet_tcp_fatal_error(cmd->queue); - return; - } + if (!sg_remaining) + return -EPROTO; + + if (!sg->length || sg->length <= sg_offset) + return -EPROTO; + u32 iov_len = min_t(u32, length, sg->length - sg_offset); bvec_set_page(iov, sg_page(sg), iov_len, @@ -378,6 +375,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, nr_pages, cmd->pdu_len); + return 0; } static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) @@ -945,7 +943,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) return 0; } -static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, +static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) { size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); @@ -961,19 +959,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, if (!nvme_is_write(cmd->req.cmd) || !data_len || data_len > cmd->req.port->inline_data_size) { nvmet_prepare_receive_pdu(queue); - return; + return 0; } ret = nvmet_tcp_map_data(cmd); if (unlikely(ret)) { pr_err("queue %d: failed to map data\n", queue->idx); nvmet_tcp_fatal_error(queue); - return; + return -EPROTO; } queue->rcv_state = NVMET_TCP_RECV_DATA; - nvmet_tcp_build_pdu_iovec(cmd); cmd->flags |= NVMET_TCP_F_INIT_FAILED; + ret = nvmet_tcp_build_pdu_iovec(cmd); + if (unlikely(ret)) + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); + + return ret; } static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) @@ -1025,7 +1027,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) goto err_proto; } cmd->pdu_recv = 0; - nvmet_tcp_build_pdu_iovec(cmd); + if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { + pr_err("queue %d: failed to build PDU iovec\n", queue->idx); + goto err_proto; + } queue->cmd = cmd; queue->rcv_state = NVMET_TCP_RECV_DATA; @@ -1088,8 +1093,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) req->cmd->common.opcode, le32_to_cpu(req->cmd->common.dptr.sgl.length)); - nvmet_tcp_handle_req_failure(queue, queue->cmd, req); - return 0; + return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); } ret = nvmet_tcp_map_data(queue->cmd); @@ -1106,8 +1110,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) if (nvmet_tcp_need_data_in(queue->cmd)) { if (nvmet_tcp_has_inline_data(queue->cmd)) { queue->rcv_state = NVMET_TCP_RECV_DATA; - nvmet_tcp_build_pdu_iovec(queue->cmd); - return 0; + ret = nvmet_tcp_build_pdu_iovec(queue->cmd); + if (unlikely(ret)) + pr_err("queue %d: failed to build PDU iovec\n", + queue->idx); + return ret; } /* send back R2T */ nvmet_tcp_queue_response(&queue->cmd->req); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 46b12e157bebe9..504450a8b6a45c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -426,13 +426,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg static inline u32 dw_pcie_enable_ecrc(u32 val) { /* - * DesignWare core version 4.90A has a design issue where the 'TD' - * bit in the Control register-1 of the ATU outbound region acts - * like an override for the ECRC setting, i.e., the presence of TLP - * Digest (ECRC) in the outgoing TLPs is solely determined by this - * bit. This is contrary to the PCIe spec which says that the - * enablement of the ECRC is solely determined by the AER - * registers. + * DWC versions 0x3530302a and 0x3536322a have a design issue where + * the 'TD' bit in the Control register-1 of the ATU outbound + * region acts like an override for the ECRC setting, i.e., the + * presence of TLP Digest (ECRC) in the outgoing TLPs is solely + * determined by this bit. This is contrary to the PCIe spec which + * says that the enablement of the ECRC is solely determined by the + * AER registers. * * Because of this, even when the ECRC is enabled through AER * registers, the transactions going through ATU won't have TLP @@ -502,7 +502,7 @@ static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) && dw_pcie_ver_is_ge(pci, 460A)) val |= PCIE_ATU_INCREASE_REGION_SIZE; - if (dw_pcie_ver_is(pci, 490A)) + if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A)) val = dw_pcie_enable_ecrc(val); dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index fec9473869bce0..1ffa31797a17ca 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -31,8 +31,10 @@ #define DW_PCIE_VER_470A 0x3437302a #define DW_PCIE_VER_480A 0x3438302a #define DW_PCIE_VER_490A 0x3439302a +#define DW_PCIE_VER_500A 0x3530302a #define DW_PCIE_VER_520A 0x3532302a #define DW_PCIE_VER_540A 0x3534302a +#define DW_PCIE_VER_562A 0x3536322a #define __dw_pcie_ver_cmp(_pci, _ver, _op) \ ((_pci)->version _op DW_PCIE_VER_ ## _ver) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index ce2a7a6dab90c5..89109e380635c9 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -37,8 +37,8 @@ #include #include "../../pci.h" -#define TEGRA194_DWC_IP_VER 0x490A -#define TEGRA234_DWC_IP_VER 0x562A +#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A +#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A #define APPL_PINMUX 0x0 #define APPL_PINMUX_PEX_RST BIT(0) @@ -139,7 +139,11 @@ #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 -#define LTSSM_STATE_PRE_DETECT 5 +#define LTSSM_STATE_DETECT_QUIET 0x00 +#define LTSSM_STATE_DETECT_ACT 0x08 +#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 +#define LTSSM_STATE_DETECT_WAIT 0x30 +#define LTSSM_STATE_L2_IDLE 0xa8 #define APPL_RADM_STATUS 0xE4 #define APPL_PM_XMT_TURNOFF_STATE BIT(0) @@ -205,9 +209,8 @@ #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 -#define PME_ACK_TIMEOUT 10000 - -#define LTSSM_TIMEOUT 50000 /* 50ms */ +#define LTSSM_DELAY_US 10000 /* 10 ms */ +#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ #define GEN3_GEN4_EQ_PRESET_INIT 5 @@ -1052,7 +1055,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) { struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); - disable_irq(pcie->pex_rst_irq); + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) + disable_irq(pcie->pex_rst_irq); } static const struct dw_pcie_ops tegra_dw_pcie_ops = { @@ -1193,9 +1197,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) return err; } - pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, - "nvidia,refclk-select", - GPIOD_OUT_HIGH); + pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, + "nvidia,refclk-select", + GPIOD_OUT_HIGH); if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); const char *level = KERN_ERR; @@ -1285,44 +1289,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, return 0; } -static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) -{ - struct dw_pcie_rp *pp = &pcie->pci.pp; - struct pci_bus *child, *root_bus = NULL; - struct pci_dev *pdev; - - /* - * link doesn't go into L2 state with some of the endpoints with Tegra - * if they are not in D0 state. So, need to make sure that immediate - * downstream devices are in D0 state before sending PME_TurnOff to put - * link into L2 state. - * This is as per PCI Express Base r4.0 v1.0 September 27-2017, - * 5.2 Link State Power Management (Page #428). - */ - - list_for_each_entry(child, &pp->bridge->bus->children, node) { - /* Bring downstream devices to D0 if they are not already in */ - if (child->parent == pp->bridge->bus) { - root_bus = child; - break; - } - } - - if (!root_bus) { - dev_err(pcie->dev, "Failed to find downstream devices\n"); - return; - } - - list_for_each_entry(pdev, &root_bus->devices, bus_list) { - if (PCI_SLOT(pdev->devfn) == 0) { - if (pci_set_power_state(pdev, PCI_D0)) - dev_err(pcie->dev, - "Failed to transition %s to D0 state\n", - dev_name(&pdev->dev)); - } - } -} - static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) { pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); @@ -1583,9 +1549,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) val |= APPL_PM_XMT_TURNOFF_STATE; appl_writel(pcie, val, APPL_RADM_STATUS); - return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, - val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, - 1, PME_ACK_TIMEOUT); + return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, + PCIE_PME_TO_L2_TIMEOUT_US/10, + PCIE_PME_TO_L2_TIMEOUT_US); } static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) @@ -1620,23 +1587,22 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) data &= ~APPL_PINMUX_PEX_RST; appl_writel(pcie, data, APPL_PINMUX); + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + /* - * Some cards do not go to detect state even after de-asserting - * PERST#. So, de-assert LTSSM to bring link to detect state. + * Deassert LTSSM state to stop the state toggling between + * Polling and Detect. */ data = readl(pcie->appl_base + APPL_CTRL); data &= ~APPL_CTRL_LTSSM_EN; writel(data, pcie->appl_base + APPL_CTRL); - - err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, - data, - ((data & - APPL_DEBUG_LTSSM_STATE_MASK) >> - APPL_DEBUG_LTSSM_STATE_SHIFT) == - LTSSM_STATE_PRE_DETECT, - 1, LTSSM_TIMEOUT); - if (err) - dev_info(pcie->dev, "Link didn't go to detect state\n"); } /* * DBI registers may not be accessible after this as PLL-E would be @@ -1652,7 +1618,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) { - tegra_pcie_downstream_dev_to_D0(pcie); dw_pcie_host_deinit(&pcie->pci.pp); tegra_pcie_dw_pme_turnoff(pcie); tegra_pcie_unconfig_controller(pcie); @@ -1718,19 +1683,24 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) if (pcie->ep_state == EP_STATE_DISABLED) return; - /* Disable LTSSM */ + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + /* + * Deassert LTSSM state to stop the state toggling between + * Polling and Detect. + */ val = appl_readl(pcie, APPL_CTRL); val &= ~APPL_CTRL_LTSSM_EN; appl_writel(pcie, val, APPL_CTRL); - ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, - ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> - APPL_DEBUG_LTSSM_STATE_SHIFT) == - LTSSM_STATE_PRE_DETECT, - 1, LTSSM_TIMEOUT); - if (ret) - dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); - reset_control_assert(pcie->core_rst); tegra_pcie_disable_phy(pcie); @@ -1869,6 +1839,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) reset_control_deassert(pcie->core_rst); + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); + if (pcie->update_fc_fixup) { val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; @@ -2333,16 +2307,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); } -static int tegra_pcie_dw_suspend_late(struct device *dev) +static int tegra_pcie_dw_suspend(struct device *dev) { struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); - u32 val; if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { - dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); - return -EPERM; + if (pcie->ep_state == EP_STATE_ENABLED) { + dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); + return -EPERM; + } + + disable_irq(pcie->pex_rst_irq); + return 0; } + return 0; +} + +static int tegra_pcie_dw_suspend_late(struct device *dev) +{ + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + u32 val; + if (!pcie->link_state) return 0; @@ -2362,10 +2348,12 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) { struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) + return 0; + if (!pcie->link_state) return 0; - tegra_pcie_downstream_dev_to_D0(pcie); tegra_pcie_dw_pme_turnoff(pcie); tegra_pcie_unconfig_controller(pcie); @@ -2377,6 +2365,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); int ret; + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) + return 0; + if (!pcie->link_state) return 0; @@ -2409,8 +2400,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) u32 val; if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { - dev_err(dev, "Suspend is not supported in EP mode"); - return -ENOTSUPP; + enable_irq(pcie->pex_rst_irq); + return 0; } if (!pcie->link_state) @@ -2439,7 +2430,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) return; debugfs_remove_recursive(pcie->debugfs); - tegra_pcie_downstream_dev_to_D0(pcie); disable_irq(pcie->pci.pp.irq); if (IS_ENABLED(CONFIG_PCI_MSI)) @@ -2516,6 +2506,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { }; static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { + .suspend = tegra_pcie_dw_suspend, .suspend_late = tegra_pcie_dw_suspend_late, .suspend_noirq = tegra_pcie_dw_suspend_noirq, .resume_noirq = tegra_pcie_dw_resume_noirq, diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 975b3024fb08cd..822d9b8e09f60d 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -760,14 +760,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) struct platform_device *pdev = to_platform_device(dev); int err; - err = mtk_pcie_init_irq_domains(pcie); - if (err) - return err; - pcie->irq = platform_get_irq(pdev, 0); if (pcie->irq < 0) return pcie->irq; + err = mtk_pcie_init_irq_domains(pcie); + if (err) + return err; + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a21192ec5689b5..e7648a1abfdbf3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3956,8 +3956,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) */ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) { - struct pci_bus *bus = dev->bus; - struct pci_dev *bridge; + struct pci_dev *root, *bridge; u32 cap, ctl2; /* @@ -3987,35 +3986,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) return -EINVAL; } - while (bus->parent) { - bridge = bus->self; + root = pcie_find_root_port(dev); + if (!root) + return -EINVAL; - pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); + pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); + if ((cap & cap_mask) != cap_mask) + return -EINVAL; + bridge = pci_upstream_bridge(dev); + while (bridge != root) { switch (pci_pcie_type(bridge)) { - /* Ensure switch ports support AtomicOp routing */ case PCI_EXP_TYPE_UPSTREAM: - case PCI_EXP_TYPE_DOWNSTREAM: - if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) - return -EINVAL; - break; - - /* Ensure root port supports all the sizes we care about */ - case PCI_EXP_TYPE_ROOT_PORT: - if ((cap & cap_mask) != cap_mask) - return -EINVAL; - break; - } - - /* Ensure upstream ports don't block AtomicOps on egress */ - if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { + /* Upstream ports must not block AtomicOps on egress */ pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl2); if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) return -EINVAL; + fallthrough; + + /* All switch ports need to route AtomicOps */ + case PCI_EXP_TYPE_DOWNSTREAM: + pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, + &cap); + if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) + return -EINVAL; + break; } - bus = bus->parent; + bridge = pci_upstream_bridge(bridge); } pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index da494fe451baf0..efc439c7488622 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, int any; u_char *b, hole, most; - dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); + pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); /* First, what does a floating port look like? */ b = kzalloc(256, GFP_KERNEL); @@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, struct socket_data *s_data = s->resource_data; u_long i, j, bad, fail, step; - dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", - base, base+num-1); + pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", + dev_name(&s->dev), base, base+num-1); bad = fail = 0; step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); /* don't allow too large steps */ diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 0cfa74365733ca..a4940199f2ad06 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -853,7 +853,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, int ret = -EINVAL; int i; enum pin_config_param param; - enum pin_config_param argument; + unsigned int argument; for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index d2488d80912c9f..727f3c5605ced2 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -1253,6 +1253,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) { struct gpio_irq_chip *girq = &chip->gpio_chip.irq; DECLARE_BITMAP(pending_irqs, MAX_LINE); + struct device *dev = chip->dev; int ret; mutex_init(&chip->irq_lock); @@ -1261,10 +1262,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) /* Read IRQ status register to clear all pending interrupts */ ret = cy8c95x0_irq_pending(chip, pending_irqs); - if (ret) { - dev_err(chip->dev, "failed to clear irq status register\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); /* Mask all interrupts */ bitmap_fill(chip->irq_mask, MAX_LINE); @@ -1279,17 +1278,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) girq->handler = handle_simple_irq; girq->threaded = true; - ret = devm_request_threaded_irq(chip->dev, irq, - NULL, cy8c95x0_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - dev_name(chip->dev), chip); - if (ret) { - dev_err(chip->dev, "failed to request irq %d\n", irq); - return ret; - } - dev_info(chip->dev, "Registered threaded IRQ\n"); - - return 0; + return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(chip->dev), chip); } static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) @@ -1305,11 +1296,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) pd->owner = THIS_MODULE; chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); - if (IS_ERR(chip->pctldev)) - return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), - "can't register controller\n"); - - return 0; + return PTR_ERR_OR_ZERO(chip->pctldev); } static int cy8c95x0_detect(struct i2c_client *client, diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c index bf827ab081a1d6..f87b5964e8b310 100644 --- a/drivers/pinctrl/pinctrl-pic32.c +++ b/drivers/pinctrl/pinctrl-pic32.c @@ -2173,16 +2173,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(pctl->reg_base)) return PTR_ERR(pctl->reg_base); - pctl->clk = devm_clk_get(&pdev->dev, NULL); + pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(pctl->clk)) { ret = PTR_ERR(pctl->clk); - dev_err(&pdev->dev, "clk get failed\n"); - return ret; - } - - ret = clk_prepare_enable(pctl->clk); - if (ret) { - dev_err(&pdev->dev, "clk enable failed\n"); + dev_err(&pdev->dev, "Failed to get and enable clock\n"); return ret; } @@ -2238,16 +2232,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - bank->clk = devm_clk_get(&pdev->dev, NULL); + bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(bank->clk)) { ret = PTR_ERR(bank->clk); - dev_err(&pdev->dev, "clk get failed\n"); - return ret; - } - - ret = clk_prepare_enable(bank->clk); - if (ret) { - dev_err(&pdev->dev, "clk enable failed\n"); + dev_err(&pdev->dev, "Failed to get and enable clock\n"); return ret; } diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c index d1cf8f3463ce3b..e248567c0a1823 100644 --- a/drivers/platform/chrome/chromeos_tbmc.c +++ b/drivers/platform/chrome/chromeos_tbmc.c @@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev) return 0; } +static void chromeos_tbmc_remove(struct acpi_device *adev) +{ + device_init_wakeup(&adev->dev, false); +} + static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { { ACPI_DRV_NAME, 0 }, { } @@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = { .ids = chromeos_tbmc_acpi_device_ids, .ops = { .add = chromeos_tbmc_add, + .remove = chromeos_tbmc_remove, .notify = chromeos_tbmc_notify, }, .drv.pm = &chromeos_tbmc_pm_ops, diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c index 2755601f979cd5..7c7622f8f87167 100644 --- a/drivers/platform/surface/surfacepro3_button.c +++ b/drivers/platform/surface/surfacepro3_button.c @@ -243,6 +243,7 @@ static void surface_button_remove(struct acpi_device *device) { struct surface_button *button = acpi_driver_data(device); + device_init_wakeup(&device->dev, false); input_unregister_device(button->input); kfree(button); } diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c index fc2f58b4cbc6ef..7e44ba3015627d 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c @@ -6,10 +6,32 @@ * Copyright (c) 2020 Dell Inc. */ +#include + #include "dell-wmi-sysman.h" get_instance_id(enumeration); +static int append_enum_string(char *dest, const char *src) +{ + size_t dest_len = strlen(dest); + ssize_t copied; + + if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) + return -EINVAL; + + copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); + if (copied < 0) + return -EINVAL; + + dest_len += copied; + copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); + if (copied < 0) + return -EINVAL; + + return 0; +} + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int instance_id = get_enumeration_instance_id(kobj); @@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, return -EINVAL; if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) return -EINVAL; - strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, - enumeration_obj[next_obj++].string.pointer); - strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); + if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, + enumeration_obj[next_obj++].string.pointer)) + return -EINVAL; } if (next_obj >= enum_property_count) @@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, return -EINVAL; if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) return -EINVAL; - strcat(wmi_priv.enumeration_data[instance_id].possible_values, - enumeration_obj[next_obj++].string.pointer); - strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); + if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, + enumeration_obj[next_obj++].string.pointer)) + return -EINVAL; } return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c index fee20866b41e41..9039e494131fd6 100644 --- a/drivers/platform/x86/dell/dell_rbu.c +++ b/drivers/platform/x86/dell/dell_rbu.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, char *buffer, loff_t pos, size_t count) { unsigned long temp; + + if (kstrtoul(buffer, 10, &temp)) + return -EINVAL; + spin_lock(&rbu_data.lock); packet_empty_list(); - sscanf(buffer, "%lu", &temp); if (temp < 0xffffffff) rbu_data.packetsize = temp; diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index ad907c558997a4..f6dcf8d6a1dbbb 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -1081,9 +1081,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) } result = device_create_file(&pcc->platform->dev, &dev_attr_cdpower); - pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); if (result) goto out_platform; + + pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); } else { pcc->platform = NULL; } @@ -1117,10 +1118,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) i8042_remove_filter(panasonic_i8042_filter); if (pcc->platform) { + pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); platform_device_unregister(pcc->platform); } - pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c index 368918e562f55b..606d6bdccf94af 100644 --- a/drivers/pmdomain/imx/scu-pd.c +++ b/drivers/pmdomain/imx/scu-pd.c @@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void) return; imx_con_rsrc = specs.args[0]; + of_node_put(specs.np); } static int imx_sc_get_pd_power(struct device *dev, u32 rsrc) diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c index b8ceb3c2b81c25..f4e52e92dcbf61 100644 --- a/drivers/pmdomain/ti/omap_prm.c +++ b/drivers/pmdomain/ti/omap_prm.c @@ -651,6 +651,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, if (pd_args.args_count != 0) dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", prmd->pd.name, pd_args.args_count); + of_node_put(pd_args.np); genpd_data = dev_gpd_data(dev); genpd_data->data = NULL; diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 3fee27914ba805..5f3a3e60a19d09 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) client->irq = 0; } } + if (client->irq <= 0) + clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); if (err) { diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 0abd77f4b66462..2988a699e3ef2b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -219,16 +219,16 @@ EXPORT_SYMBOL_GPL(chsc_sadc); static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) { - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); if (sch->driver && sch->driver->chp_event) if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0) goto out_unreg; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return 0; out_unreg: sch->lpm = 0; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); css_schedule_eval(sch->schid); return 0; } @@ -258,10 +258,10 @@ void chsc_chp_offline(struct chp_id chpid) static int __s390_process_res_acc(struct subchannel *sch, void *data) { - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); if (sch->driver && sch->driver->chp_event) sch->driver->chp_event(sch, data, CHP_ONLINE); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return 0; } @@ -292,10 +292,10 @@ static void s390_process_res_acc(struct chp_link *link) static int process_fces_event(struct subchannel *sch, void *data) { - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); if (sch->driver && sch->driver->chp_event) sch->driver->chp_event(sch, data, CHP_FCES_EVENT); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return 0; } @@ -769,11 +769,11 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, memset(&link, 0, sizeof(struct chp_link)); link.chpid = chpid; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); if (sch->driver && sch->driver->chp_event) sch->driver->chp_event(sch, &link, on ? CHP_VARY_ON : CHP_VARY_OFF); - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); } static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data) diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 180ab899289c55..902237d0baefea 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -211,10 +211,10 @@ static int chsc_async(struct chsc_async_area *chsc_area, chsc_area->header.key = PAGE_DEFAULT_KEY >> 4; while ((sch = chsc_get_next_subchannel(sch))) { - spin_lock(sch->lock); + spin_lock(&sch->lock); private = dev_get_drvdata(&sch->dev); if (private->request) { - spin_unlock(sch->lock); + spin_unlock(&sch->lock); ret = -EBUSY; continue; } @@ -239,7 +239,7 @@ static int chsc_async(struct chsc_async_area *chsc_area, default: ret = -ENODEV; } - spin_unlock(sch->lock); + spin_unlock(&sch->lock); CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n", sch->schid.ssid, sch->schid.sch_no, cc); if (ret == -EINPROGRESS) diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 81ef9002f06400..7843c69abee6c0 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -550,7 +550,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) return IRQ_HANDLED; } sch = phys_to_virt(tpi_info->intparm); - spin_lock(sch->lock); + spin_lock(&sch->lock); /* Store interrupt response block to lowcore. */ if (tsch(tpi_info->schid, irb) == 0) { /* Keep subchannel information word up to date. */ @@ -562,7 +562,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) inc_irq_stat(IRQIO_CIO); } else inc_irq_stat(IRQIO_CIO); - spin_unlock(sch->lock); + spin_unlock(&sch->lock); return IRQ_HANDLED; } @@ -667,7 +667,7 @@ struct subchannel *cio_probe_console(void) if (IS_ERR(sch)) return sch; - lockdep_set_class(sch->lock, &console_sch_key); + lockdep_set_class(&sch->lock, &console_sch_key); isc_register(CONSOLE_ISC); sch->config.isc = CONSOLE_ISC; sch->config.intparm = (u32)virt_to_phys(sch); diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index fa8df50bb49e38..23374604c6b01a 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -83,7 +83,7 @@ enum sch_todo { /* subchannel data structure used by I/O subroutines */ struct subchannel { struct subchannel_id schid; - spinlock_t *lock; /* subchannel lock */ + spinlock_t lock; /* subchannel lock */ struct mutex reg_mutex; enum { SUBCHANNEL_TYPE_IO = 0, @@ -103,11 +103,6 @@ struct subchannel { struct work_struct todo_work; struct schib_config config; u64 dma_mask; - /* - * Driver name to force a match. Do not set directly, because core - * frees it. Use driver_set_override() to set or clear it. - */ - const char *driver_override; } __attribute__ ((aligned(8))); DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index e50592c3d30ca0..97a2c23f4ce0fb 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -148,16 +148,10 @@ out: static void css_sch_todo(struct work_struct *work); -static int css_sch_create_locks(struct subchannel *sch) +static void css_sch_create_locks(struct subchannel *sch) { - sch->lock = kmalloc(sizeof(*sch->lock), GFP_KERNEL); - if (!sch->lock) - return -ENOMEM; - - spin_lock_init(sch->lock); + spin_lock_init(&sch->lock); mutex_init(&sch->reg_mutex); - - return 0; } static void css_subchannel_release(struct device *dev) @@ -166,8 +160,6 @@ static void css_subchannel_release(struct device *dev) sch->config.intparm = 0; cio_commit_config(sch); - kfree(sch->driver_override); - kfree(sch->lock); kfree(sch); } @@ -219,9 +211,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, sch->schib = *schib; sch->st = schib->pmcw.st; - ret = css_sch_create_locks(sch); - if (ret) - goto err; + css_sch_create_locks(sch); INIT_WORK(&sch->todo_work, css_sch_todo); sch->dev.release = &css_subchannel_release; @@ -233,19 +223,17 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, */ ret = dma_set_coherent_mask(&sch->dev, DMA_BIT_MASK(31)); if (ret) - goto err_lock; + goto err; /* * But we don't have such restrictions imposed on the stuff that * is handled by the streaming API. */ ret = dma_set_mask(&sch->dev, DMA_BIT_MASK(64)); if (ret) - goto err_lock; + goto err; return sch; -err_lock: - kfree(sch->lock); err: put_device(&sch->dev); return ERR_PTR(ret); @@ -320,7 +308,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, { struct subchannel *sch = to_subchannel(dev); - return sprintf(buf, "%01x\n", sch->st); + return sysfs_emit(buf, "%01x\n", sch->st); } static DEVICE_ATTR_RO(type); @@ -330,42 +318,14 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, { struct subchannel *sch = to_subchannel(dev); - return sprintf(buf, "css:t%01X\n", sch->st); + return sysfs_emit(buf, "css:t%01X\n", sch->st); } static DEVICE_ATTR_RO(modalias); -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct subchannel *sch = to_subchannel(dev); - int ret; - - ret = driver_set_override(dev, &sch->driver_override, buf, count); - if (ret) - return ret; - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct subchannel *sch = to_subchannel(dev); - ssize_t len; - - device_lock(dev); - len = snprintf(buf, PAGE_SIZE, "%s\n", sch->driver_override); - device_unlock(dev); - return len; -} -static DEVICE_ATTR_RW(driver_override); - static struct attribute *subch_attrs[] = { &dev_attr_type.attr, &dev_attr_modalias.attr, - &dev_attr_driver_override.attr, NULL, }; @@ -407,8 +367,8 @@ static ssize_t pimpampom_show(struct device *dev, struct subchannel *sch = to_subchannel(dev); struct pmcw *pmcw = &sch->schib.pmcw; - return sprintf(buf, "%02x %02x %02x\n", - pmcw->pim, pmcw->pam, pmcw->pom); + return sysfs_emit(buf, "%02x %02x %02x\n", + pmcw->pim, pmcw->pam, pmcw->pom); } static DEVICE_ATTR_RO(pimpampom); @@ -604,12 +564,12 @@ static void css_sch_todo(struct work_struct *work) sch = container_of(work, struct subchannel, todo_work); /* Find out todo. */ - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); todo = sch->todo; CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid, sch->schid.sch_no, todo); sch->todo = SCH_TODO_NOTHING; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); /* Perform todo. */ switch (todo) { case SCH_TODO_NOTHING: @@ -617,9 +577,9 @@ static void css_sch_todo(struct work_struct *work) case SCH_TODO_EVAL: ret = css_evaluate_known_subchannel(sch, 1); if (ret == -EAGAIN) { - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); css_sched_sch_todo(sch, todo); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); } break; case SCH_TODO_UNREG: @@ -892,7 +852,7 @@ static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a, if (!css->id_valid) return -EINVAL; - return sprintf(buf, "%x\n", css->cssid); + return sysfs_emit(buf, "%x\n", css->cssid); } static DEVICE_ATTR_RO(real_cssid); @@ -915,7 +875,7 @@ static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a, int ret; mutex_lock(&css->mutex); - ret = sprintf(buf, "%x\n", css->cm_enabled); + ret = sysfs_emit(buf, "%x\n", css->cm_enabled); mutex_unlock(&css->mutex); return ret; } @@ -1028,12 +988,7 @@ static int __init setup_css(int nr) css->pseudo_subchannel->dev.parent = &css->device; css->pseudo_subchannel->dev.release = css_subchannel_release; mutex_init(&css->pseudo_subchannel->reg_mutex); - ret = css_sch_create_locks(css->pseudo_subchannel); - if (ret) { - kfree(css->pseudo_subchannel); - device_unregister(&css->device); - goto out_err; - } + css_sch_create_locks(css->pseudo_subchannel); dev_set_name(&css->pseudo_subchannel->dev, "defunct"); ret = device_register(&css->pseudo_subchannel->dev); @@ -1368,9 +1323,11 @@ static int css_bus_match(struct device *dev, struct device_driver *drv) struct subchannel *sch = to_subchannel(dev); struct css_driver *driver = to_cssdriver(drv); struct css_device_id *id; + int ret; /* When driver_override is set, only bind to the matching driver */ - if (sch->driver_override && strcmp(sch->driver_override, drv->name)) + ret = device_match_driver_override(dev, drv); + if (ret == 0) return 0; for (id = driver->subchannel_type; id->match_flags; id++) { @@ -1427,6 +1384,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env) static struct bus_type css_bus_type = { .name = "css", + .driver_override = true, .match = css_bus_match, .probe = css_probe, .remove = css_remove, diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 3942aa49217696..93307ca75c10b3 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -751,7 +751,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, mutex_init(&cdev->reg_mutex); atomic_set(&priv->onoff, 0); - cdev->ccwlock = sch->lock; + cdev->ccwlock = &sch->lock; cdev->dev.parent = &sch->dev; cdev->dev.release = ccw_device_release; cdev->dev.bus = &ccw_bus_type; @@ -767,9 +767,9 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, goto out_put; } priv->flags.initialized = 1; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); sch_set_cdev(sch, cdev); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return 0; out_put: @@ -854,9 +854,9 @@ static void io_subchannel_register(struct ccw_device *cdev) CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); sch_set_cdev(sch, NULL); - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); mutex_unlock(&cdev->reg_mutex); /* Release initial device reference. */ put_device(&cdev->dev); @@ -907,9 +907,9 @@ static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) atomic_inc(&ccw_device_init_count); /* Start async. device sensing. */ - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); ccw_device_recognition(cdev); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); } static int ccw_device_move_to_sch(struct ccw_device *cdev, @@ -924,12 +924,12 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, return -ENODEV; if (!sch_is_pseudo_sch(old_sch)) { - spin_lock_irq(old_sch->lock); + spin_lock_irq(&old_sch->lock); old_enabled = old_sch->schib.pmcw.ena; rc = 0; if (old_enabled) rc = cio_disable_subchannel(old_sch); - spin_unlock_irq(old_sch->lock); + spin_unlock_irq(&old_sch->lock); if (rc == -EBUSY) { /* Release child reference for new parent. */ put_device(&sch->dev); @@ -947,9 +947,9 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, sch->schib.pmcw.dev, rc); if (old_enabled) { /* Try to re-enable the old subchannel. */ - spin_lock_irq(old_sch->lock); + spin_lock_irq(&old_sch->lock); cio_enable_subchannel(old_sch, (u32)virt_to_phys(old_sch)); - spin_unlock_irq(old_sch->lock); + spin_unlock_irq(&old_sch->lock); } /* Release child reference for new parent. */ put_device(&sch->dev); @@ -957,19 +957,19 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, } /* Clean up old subchannel. */ if (!sch_is_pseudo_sch(old_sch)) { - spin_lock_irq(old_sch->lock); + spin_lock_irq(&old_sch->lock); sch_set_cdev(old_sch, NULL); - spin_unlock_irq(old_sch->lock); + spin_unlock_irq(&old_sch->lock); css_schedule_eval(old_sch->schid); } /* Release child reference for old parent. */ put_device(&old_sch->dev); /* Initialize new subchannel. */ - spin_lock_irq(sch->lock); - cdev->ccwlock = sch->lock; + spin_lock_irq(&sch->lock); + cdev->ccwlock = &sch->lock; if (!sch_is_pseudo_sch(sch)) sch_set_cdev(sch, cdev); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); if (!sch_is_pseudo_sch(sch)) css_update_ssd_info(sch); return 0; @@ -1080,9 +1080,9 @@ static int io_subchannel_probe(struct subchannel *sch) return 0; out_schedule: - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); css_sched_sch_todo(sch, SCH_TODO_UNREG); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return 0; } @@ -1096,10 +1096,10 @@ static void io_subchannel_remove(struct subchannel *sch) goto out_free; ccw_device_unregister(cdev); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); sch_set_cdev(sch, NULL); set_io_private(sch, NULL); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); out_free: dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), io_priv->dma_area, io_priv->dma_area_dma); @@ -1206,7 +1206,7 @@ static void io_subchannel_quiesce(struct subchannel *sch) struct ccw_device *cdev; int ret; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); cdev = sch_get_cdev(sch); if (cio_is_console(sch->schid)) goto out_unlock; @@ -1223,15 +1223,15 @@ static void io_subchannel_quiesce(struct subchannel *sch) ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, HZ/10); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); wait_event(cdev->private->wait_q, cdev->private->state != DEV_STATE_QUIESCE); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); } ret = cio_disable_subchannel(sch); } out_unlock: - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); } static void io_subchannel_shutdown(struct subchannel *sch) @@ -1467,7 +1467,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) enum io_sch_action action; int rc = -EAGAIN; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); if (!device_is_registered(&sch->dev)) goto out_unlock; if (work_pending(&sch->todo_work)) @@ -1521,7 +1521,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) default: break; } - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); /* All other actions require process context. */ if (!process) goto out; @@ -1537,9 +1537,9 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) break; case IO_SCH_UNREG_CDEV: case IO_SCH_UNREG_ATTACH: - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); sch_set_cdev(sch, NULL); - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); /* Unregister ccw device. */ ccw_device_unregister(cdev); break; @@ -1568,9 +1568,9 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) put_device(&cdev->dev); goto out; } - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); ccw_device_trigger_reprobe(cdev); - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); /* Release reference from get_ccwdev_by_dev_id() */ put_device(&cdev->dev); break; @@ -1580,7 +1580,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) return 0; out_unlock: - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); out: return rc; } @@ -1876,9 +1876,9 @@ static void ccw_device_todo(struct work_struct *work) css_schedule_eval(sch->schid); fallthrough; case CDEV_TODO_UNREG: - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); sch_set_cdev(sch, NULL); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); ccw_device_unregister(cdev); break; default: diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 3862961697eb6a..ad90045873e25a 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -698,29 +698,29 @@ int ccw_device_stlck(struct ccw_device *cdev) return -ENOMEM; init_completion(&data.done); data.rc = -EIO; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (rc) goto out_unlock; /* Perform operation. */ cdev->private->state = DEV_STATE_STEAL_LOCK; ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); /* Wait for operation to finish. */ if (wait_for_completion_interruptible(&data.done)) { /* Got a signal. */ - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); ccw_request_cancel(cdev); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); wait_for_completion(&data.done); } rc = data.rc; /* Check results. */ - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); cio_disable_subchannel(sch); cdev->private->state = DEV_STATE_BOXED; out_unlock: - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); kfree(buffer); return rc; diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 826364d2facd85..1caedf931a5f00 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -101,12 +101,12 @@ static void eadm_subchannel_timeout(struct timer_list *t) struct eadm_private *private = from_timer(private, t, timer); struct subchannel *sch = private->sch; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); EADM_LOG(1, "timeout"); EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid)); if (eadm_subchannel_clear(sch)) EADM_LOG(0, "clear failed"); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); } static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires) @@ -163,16 +163,16 @@ static struct subchannel *eadm_get_idle_sch(void) spin_lock_irqsave(&list_lock, flags); list_for_each_entry(private, &eadm_list, head) { sch = private->sch; - spin_lock(sch->lock); + spin_lock(&sch->lock); if (private->state == EADM_IDLE) { private->state = EADM_BUSY; list_move_tail(&private->head, &eadm_list); - spin_unlock(sch->lock); + spin_unlock(&sch->lock); spin_unlock_irqrestore(&list_lock, flags); return sch; } - spin_unlock(sch->lock); + spin_unlock(&sch->lock); } spin_unlock_irqrestore(&list_lock, flags); @@ -190,7 +190,7 @@ int eadm_start_aob(struct aob *aob) if (!sch) return -EBUSY; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); eadm_subchannel_set_timeout(sch, EADM_TIMEOUT); ret = eadm_subchannel_start(sch, aob); if (!ret) @@ -203,7 +203,7 @@ int eadm_start_aob(struct aob *aob) css_sched_sch_todo(sch, SCH_TODO_EVAL); out_unlock: - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return ret; } @@ -221,7 +221,7 @@ static int eadm_subchannel_probe(struct subchannel *sch) INIT_LIST_HEAD(&private->head); timer_setup(&private->timer, eadm_subchannel_timeout, 0); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); set_eadm_private(sch, private); private->state = EADM_IDLE; private->sch = sch; @@ -229,11 +229,11 @@ static int eadm_subchannel_probe(struct subchannel *sch) ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (ret) { set_eadm_private(sch, NULL); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); kfree(private); goto out; } - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); spin_lock_irq(&list_lock); list_add(&private->head, &eadm_list); @@ -248,7 +248,7 @@ static void eadm_quiesce(struct subchannel *sch) DECLARE_COMPLETION_ONSTACK(completion); int ret; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); if (private->state != EADM_BUSY) goto disable; @@ -256,11 +256,11 @@ static void eadm_quiesce(struct subchannel *sch) goto disable; private->completion = &completion; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); wait_for_completion_io(&completion); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); private->completion = NULL; disable: @@ -269,7 +269,7 @@ disable: ret = cio_disable_subchannel(sch); } while (ret == -EBUSY); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); } static void eadm_subchannel_remove(struct subchannel *sch) @@ -282,9 +282,9 @@ static void eadm_subchannel_remove(struct subchannel *sch) eadm_quiesce(sch); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); set_eadm_private(sch, NULL); - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); kfree(private); } @@ -309,7 +309,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) struct eadm_private *private; unsigned long flags; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); if (!device_is_registered(&sch->dev)) goto out_unlock; @@ -325,7 +325,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) private->state = EADM_IDLE; out_unlock: - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return 0; } diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 43601816ea4e4f..a3e25bdd6a76b7 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -65,14 +65,14 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch) * cancel/halt/clear completion. */ private->completion = &completion; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); if (ret == -EBUSY) wait_for_completion_timeout(&completion, 3*HZ); private->completion = NULL; flush_workqueue(vfio_ccw_work_q); - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); ret = cio_disable_subchannel(sch); } while (ret == -EBUSY); @@ -249,7 +249,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) unsigned long flags; int rc = -EAGAIN; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); if (!device_is_registered(&sch->dev)) goto out_unlock; @@ -264,7 +264,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) } out_unlock: - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return rc; } diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index 757b73141246d1..09877b46181d46 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -25,7 +25,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private) unsigned long flags; int ret; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); orb = cp_get_orb(&private->cp, sch); if (!orb) { @@ -72,7 +72,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private) ret = ccode; } out: - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return ret; } @@ -83,7 +83,7 @@ static int fsm_do_halt(struct vfio_ccw_private *private) int ccode; int ret; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); VFIO_CCW_TRACE_EVENT(2, "haltIO"); VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); @@ -111,7 +111,7 @@ static int fsm_do_halt(struct vfio_ccw_private *private) default: ret = ccode; } - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return ret; } @@ -122,7 +122,7 @@ static int fsm_do_clear(struct vfio_ccw_private *private) int ccode; int ret; - spin_lock_irqsave(sch->lock, flags); + spin_lock_irqsave(&sch->lock, flags); VFIO_CCW_TRACE_EVENT(2, "clearIO"); VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); @@ -147,7 +147,7 @@ static int fsm_do_clear(struct vfio_ccw_private *private) default: ret = ccode; } - spin_unlock_irqrestore(sch->lock, flags); + spin_unlock_irqrestore(&sch->lock, flags); return ret; } @@ -376,18 +376,18 @@ static void fsm_open(struct vfio_ccw_private *private, struct subchannel *sch = to_subchannel(private->vdev.dev->parent); int ret; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); sch->isc = VFIO_CCW_ISC; ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); if (ret) goto err_unlock; private->state = VFIO_CCW_STATE_IDLE; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); return; err_unlock: - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); } @@ -397,7 +397,7 @@ static void fsm_close(struct vfio_ccw_private *private, struct subchannel *sch = to_subchannel(private->vdev.dev->parent); int ret; - spin_lock_irq(sch->lock); + spin_lock_irq(&sch->lock); if (!sch->schib.pmcw.ena) goto err_unlock; @@ -409,12 +409,12 @@ static void fsm_close(struct vfio_ccw_private *private, goto err_unlock; private->state = VFIO_CCW_STATE_STANDBY; - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); cp_free(&private->cp); return; err_unlock: - spin_unlock_irq(sch->lock); + spin_unlock_irq(&sch->lock); vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0dd8b9f8d67176..96921a661f64cf 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1421,7 +1421,9 @@ static const struct file_operations sg_fops = { .llseek = no_llseek, }; -static struct class *sg_sysfs_class; +static const struct class sg_sysfs_class = { + .name = "scsi_generic" +}; static int sg_sysfs_valid = 0; @@ -1523,7 +1525,7 @@ sg_add_device(struct device *cl_dev) if (sg_sysfs_valid) { struct device *sg_class_member; - sg_class_member = device_create(sg_sysfs_class, cl_dev->parent, + sg_class_member = device_create(&sg_sysfs_class, cl_dev->parent, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), sdp, "%s", sdp->name); @@ -1613,7 +1615,7 @@ sg_remove_device(struct device *cl_dev) read_unlock_irqrestore(&sdp->sfd_lock, iflags); sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); - device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); + device_destroy(&sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); cdev_del(sdp->cdev); sdp->cdev = NULL; @@ -1621,10 +1623,35 @@ sg_remove_device(struct device *cl_dev) } module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); -module_param_named(def_reserved_size, def_reserved_size, int, - S_IRUGO | S_IWUSR); module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); +static int def_reserved_size_set(const char *val, const struct kernel_param *kp) +{ + int size, ret; + + if (!val) + return -EINVAL; + + ret = kstrtoint(val, 0, &size); + if (ret) + return ret; + + /* limit to 1 MB */ + if (size < 0 || size > 1048576) + return -ERANGE; + + def_reserved_size = size; + return 0; +} + +static const struct kernel_param_ops def_reserved_size_ops = { + .set = def_reserved_size_set, + .get = param_get_int, +}; + +module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, + S_IRUGO | S_IWUSR); + MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); MODULE_LICENSE("GPL"); @@ -1685,21 +1712,19 @@ init_sg(void) SG_MAX_DEVS, "sg"); if (rc) return rc; - sg_sysfs_class = class_create("scsi_generic"); - if ( IS_ERR(sg_sysfs_class) ) { - rc = PTR_ERR(sg_sysfs_class); + rc = class_register(&sg_sysfs_class); + if (rc) goto err_out; - } sg_sysfs_valid = 1; rc = scsi_register_interface(&sg_interface); if (0 == rc) { + register_sg_sysctls(); #ifdef CONFIG_SCSI_PROC_FS sg_proc_init(); #endif /* CONFIG_SCSI_PROC_FS */ return 0; } - class_destroy(sg_sysfs_class); - register_sg_sysctls(); + class_unregister(&sg_sysfs_class); err_out: unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); return rc; @@ -1713,7 +1738,7 @@ exit_sg(void) remove_proc_subtree("scsi/sg", NULL); #endif /* CONFIG_SCSI_PROC_FS */ scsi_unregister_interface(&sg_interface); - class_destroy(sg_sysfs_class); + class_unregister(&sg_sysfs_class); sg_sysfs_valid = 0; unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 07ef3db3d1a144..34f243fd2c589c 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) switch (req_op(rq)) { case REQ_OP_WRITE: - if (!cd->writeable) + if (get_disk_ro(cd->disk)) goto out; SCpnt->cmnd[0] = WRITE_10; cd->cdi.media_written = 1; @@ -670,6 +670,7 @@ static int sr_probe(struct device *dev) error = -ENOMEM; if (get_capabilities(cd)) goto fail_minor; + cdrom_probe_write_features(&cd->cdi); sr_vendor_init(cd); set_capacity(disk, cd->capacity); @@ -888,14 +889,6 @@ static int get_capabilities(struct scsi_cd *cd) /*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ - /* - * if DVD-RAM, MRW-W or CD-RW, we are randomly writable - */ - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != - (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { - cd->writeable = 1; - } - kfree(buffer); return 0; } diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index dc899277b3a441..2d92f9cb6fec7c 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -35,7 +35,6 @@ typedef struct scsi_cd { struct scsi_device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 03d5de759b2567..191da9350ca625 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -359,7 +359,7 @@ static const struct llcc_slice_config sm8550_data[] = { static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { .trp_ecc_error_status0 = 0x20344, .trp_ecc_error_status1 = 0x20348, - .trp_ecc_sb_err_syn0 = 0x2304c, + .trp_ecc_sb_err_syn0 = 0x2034c, .trp_ecc_db_err_syn0 = 0x20370, .trp_ecc_error_cntr_clear = 0x20440, .trp_interrupt_0_status = 0x20480, diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 1511d19643d410..1b7fc1fe671bb8 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -185,30 +185,26 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf, struct ocmem *of_get_ocmem(struct device *dev) { struct platform_device *pdev; - struct device_node *devnode; struct ocmem *ocmem; - devnode = of_parse_phandle(dev->of_node, "sram", 0); + struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node, + "sram", 0); if (!devnode || !devnode->parent) { dev_err(dev, "Cannot look up sram phandle\n"); - of_node_put(devnode); return ERR_PTR(-ENODEV); } pdev = of_find_device_by_node(devnode->parent); - if (!pdev) { - dev_err(dev, "Cannot find device node %s\n", devnode->name); - of_node_put(devnode); - return ERR_PTR(-EPROBE_DEFER); - } - of_node_put(devnode); + if (!pdev) + return dev_err_ptr_probe(dev, -EPROBE_DEFER, + "Cannot find device node %s\n", + devnode->name); ocmem = platform_get_drvdata(pdev); put_device(&pdev->dev); - if (!ocmem) { - dev_err(dev, "Cannot get ocmem\n"); - return ERR_PTR(-ENODEV); - } + if (!ocmem) + return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); + return ocmem; } EXPORT_SYMBOL(of_get_ocmem); @@ -313,7 +309,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) ocmem->dev = dev; ocmem->config = device_get_match_data(dev); - ocmem->core_clk = devm_clk_get(dev, "core"); + ocmem->core_clk = devm_clk_get_optional(dev, "core"); if (IS_ERR(ocmem->core_clk)) return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), "Unable to get core clock\n"); diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 77f0cf126629e4..078561b9314ad7 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -340,7 +340,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, /* Normalize state */ cdev_state = !!state; - if (qmp_cdev->state == state) + if (qmp_cdev->state == cdev_state) return 0; ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index e8cc46874c7297..eace89ed161766 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -1176,6 +1176,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) { struct tegra234_cbb *cbb = dev_get_drvdata(dev); + /* set ERD bit to mask SError and generate interrupt to report error */ + if (cbb->fabric->off_mask_erd) + tegra234_cbb_mask_serror(cbb); + tegra234_cbb_error_enable(&cbb->base); dev_dbg(dev, "%s resumed\n", cbb->fabric->name); diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index e7397fd8e9ad94..50448a4dd0b38e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1864,8 +1864,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (status[i] == SDW_SLAVE_UNATTACHED && slave->status != SDW_SLAVE_UNATTACHED) { - dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", - i, slave->status); + dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", + i, slave->status); sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); /* Ensure driver knows that peripheral unattached */ @@ -1916,8 +1916,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (slave->status == SDW_SLAVE_UNATTACHED) break; - dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", - i, slave->status); + dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", + i, slave->status); sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); break; diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index e69982dbd449bc..fdbd5d477a68ee 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -932,6 +932,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) cdns_read_response(cdns); + /* + * Clear interrupt before signalling the completion to avoid + * a race between this thread and the main thread starting + * another TX. + */ + cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL); + int_status &= ~CDNS_MCP_INT_RX_WL; + if (defer && defer->msg) { cdns_fill_msg_resp(cdns, defer->msg, defer->length, 0); diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 21e357966d2a22..cb2e5413dd32b3 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -606,7 +606,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) void __iomem *base = q->iobase; int err = 0; - init_completion(&q->c); + reinit_completion(&q->c); /* * Always start the sequence at the same index since we update @@ -924,6 +924,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_clk; + init_completion(&q->c); ret = devm_request_irq(dev, ret, fsl_qspi_irq_handler, 0, pdev->name, q); if (ret) { diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index f0a50f40a3ba16..77526f7940688d 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) unsigned long limit = loops_per_jiffy << 1; do { - while (hisi_spi_rx_not_empty(hs)) + unsigned long inner_limit = loops_per_jiffy; + + while (hisi_spi_rx_not_empty(hs) && --inner_limit) { readl(hs->regs + HISI_SPI_DOUT); + cpu_relax(); + } + + if (!inner_limit) { + dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); + break; + } + } while (hisi_spi_busy(hs) && limit--); } diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c index 4433a8a9299f68..22f3b22d77ad84 100644 --- a/drivers/spi/spi-mtk-snfi.c +++ b/drivers/spi/spi-mtk-snfi.c @@ -1307,6 +1307,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { .ecc = true, }; +static void mtk_unregister_ecc_engine(void *data) +{ + struct nand_ecc_engine *eng = data; + + nand_ecc_unregister_on_host_hw_engine(eng); +} + static irqreturn_t mtk_snand_irq(int irq, void *id) { struct mtk_snand *snf = id; @@ -1487,6 +1494,13 @@ static int mtk_snand_probe(struct platform_device *pdev) goto disable_clk; } + ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, + &ms->ecc_eng); + if (ret) { + dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); + goto release_ecc; + } + ctlr->num_chipselect = 1; ctlr->mem_ops = &mtk_snand_mem_ops; ctlr->mem_caps = &mtk_snand_mem_caps; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 9e160cba1ff370..03a11aed055ee5 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -352,7 +352,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); /* When int_cs_inactive comes, spi target abort */ - if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { + if (rs->cs_inactive && + (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { ctlr->target_abort(ctlr); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index cfd17bbb220230..683dce55ef3020 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -312,7 +312,8 @@ static int sifive_spi_probe(struct platform_device *pdev) goto put_host; } - spi->clk = devm_clk_get(&pdev->dev, NULL); + /* Spin up the bus clock before hitting registers */ + spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(spi->clk)) { dev_err(&pdev->dev, "Unable to find bus clock\n"); ret = PTR_ERR(spi->clk); @@ -342,13 +343,6 @@ static int sifive_spi_probe(struct platform_device *pdev) goto put_host; } - /* Spin up the bus clock before hitting registers */ - ret = clk_prepare_enable(spi->clk); - if (ret) { - dev_err(&pdev->dev, "Unable to enable bus clock\n"); - goto put_host; - } - /* probe the number of CS lines */ spi->cs_inactive = sifive_spi_read(spi, SIFIVE_SPI_REG_CSDEF); sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, 0xffffffffU); @@ -357,14 +351,14 @@ static int sifive_spi_probe(struct platform_device *pdev) if (!cs_bits) { dev_err(&pdev->dev, "Could not auto probe CS lines\n"); ret = -EINVAL; - goto disable_clk; + goto put_host; } num_cs = ilog2(cs_bits) + 1; if (num_cs > SIFIVE_SPI_MAX_CS) { dev_err(&pdev->dev, "Invalid number of spi targets\n"); ret = -EINVAL; - goto disable_clk; + goto put_host; } /* Define our host */ @@ -393,22 +387,20 @@ static int sifive_spi_probe(struct platform_device *pdev) dev_name(&pdev->dev), spi); if (ret) { dev_err(&pdev->dev, "Unable to bind to interrupt\n"); - goto disable_clk; + goto put_host; } dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n", irq, host->num_chipselect); - ret = devm_spi_register_controller(&pdev->dev, host); + ret = spi_register_controller(host); if (ret < 0) { dev_err(&pdev->dev, "spi_register_host failed\n"); - goto disable_clk; + goto put_host; } return 0; -disable_clk: - clk_disable_unprepare(spi->clk); put_host: spi_controller_put(host); @@ -420,9 +412,14 @@ static void sifive_spi_remove(struct platform_device *pdev) struct spi_controller *host = platform_get_drvdata(pdev); struct sifive_spi *spi = spi_controller_get_devdata(host); + spi_controller_get(host); + + spi_unregister_controller(host); + /* Disable all the interrupts just in case */ sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0); - clk_disable_unprepare(spi->clk); + + spi_controller_put(host); } static int sifive_spi_suspend(struct device *dev) diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index 7fcff9c539e239..82acb667fd2d77 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -6,7 +6,7 @@ * Patrice Chotard * Lee Jones * - * SPI master mode controller driver, used in STMicroelectronics devices. + * SPI host mode controller driver, used in STMicroelectronics devices. */ #include @@ -115,10 +115,10 @@ static void ssc_read_rx_fifo(struct spi_st *spi_st) spi_st->words_remaining -= count; } -static int spi_st_transfer_one(struct spi_master *master, +static int spi_st_transfer_one(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *t) { - struct spi_st *spi_st = spi_master_get_devdata(master); + struct spi_st *spi_st = spi_controller_get_devdata(host); uint32_t ctl = 0; /* Setup transfer */ @@ -165,7 +165,7 @@ static int spi_st_transfer_one(struct spi_master *master, if (ctl) writel_relaxed(ctl, spi_st->base + SSC_CTL); - spi_finalize_current_transfer(spi->master); + spi_finalize_current_transfer(spi->controller); return t->len; } @@ -174,7 +174,7 @@ static int spi_st_transfer_one(struct spi_master *master, #define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) static int spi_st_setup(struct spi_device *spi) { - struct spi_st *spi_st = spi_master_get_devdata(spi->master); + struct spi_st *spi_st = spi_controller_get_devdata(spi->controller); u32 spi_st_clk, sscbrg, var; u32 hz = spi->max_speed_hz; @@ -274,35 +274,35 @@ static irqreturn_t spi_st_irq(int irq, void *dev_id) static int spi_st_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct spi_master *master; + struct spi_controller *host; struct spi_st *spi_st; int irq, ret = 0; u32 var; - master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); - if (!master) + host = spi_alloc_host(&pdev->dev, sizeof(*spi_st)); + if (!host) return -ENOMEM; - master->dev.of_node = np; - master->mode_bits = MODEBITS; - master->setup = spi_st_setup; - master->transfer_one = spi_st_transfer_one; - master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - master->auto_runtime_pm = true; - master->bus_num = pdev->id; - master->use_gpio_descriptors = true; - spi_st = spi_master_get_devdata(master); + host->dev.of_node = np; + host->mode_bits = MODEBITS; + host->setup = spi_st_setup; + host->transfer_one = spi_st_transfer_one; + host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + host->auto_runtime_pm = true; + host->bus_num = pdev->id; + host->use_gpio_descriptors = true; + spi_st = spi_controller_get_devdata(host); spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); if (IS_ERR(spi_st->clk)) { dev_err(&pdev->dev, "Unable to request clock\n"); ret = PTR_ERR(spi_st->clk); - goto put_master; + goto put_host; } ret = clk_prepare_enable(spi_st->clk); if (ret) - goto put_master; + goto put_host; init_completion(&spi_st->done); @@ -324,7 +324,7 @@ static int spi_st_probe(struct platform_device *pdev) var &= ~SSC_CTL_SR; writel_relaxed(var, spi_st->base + SSC_CTL); - /* Set SSC into slave mode before reconfiguring PIO pins */ + /* Set SSC into target mode before reconfiguring PIO pins */ var = readl_relaxed(spi_st->base + SSC_CTL); var &= ~SSC_CTL_MS; writel_relaxed(var, spi_st->base + SSC_CTL); @@ -347,11 +347,11 @@ static int spi_st_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, host); - ret = devm_spi_register_master(&pdev->dev, master); + ret = spi_register_controller(host); if (ret) { - dev_err(&pdev->dev, "Failed to register master\n"); + dev_err(&pdev->dev, "Failed to register host\n"); goto rpm_disable; } @@ -361,28 +361,34 @@ rpm_disable: pm_runtime_disable(&pdev->dev); clk_disable: clk_disable_unprepare(spi_st->clk); -put_master: - spi_master_put(master); +put_host: + spi_controller_put(host); return ret; } static void spi_st_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct spi_st *spi_st = spi_master_get_devdata(master); + struct spi_controller *host = platform_get_drvdata(pdev); + struct spi_st *spi_st = spi_controller_get_devdata(host); + + spi_controller_get(host); + + spi_unregister_controller(host); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(spi_st->clk); + spi_controller_put(host); + pinctrl_pm_select_sleep_state(&pdev->dev); } #ifdef CONFIG_PM static int spi_st_runtime_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct spi_st *spi_st = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_controller_get_devdata(host); writel_relaxed(0, spi_st->base + SSC_IEN); pinctrl_pm_select_sleep_state(dev); @@ -394,8 +400,8 @@ static int spi_st_runtime_suspend(struct device *dev) static int spi_st_runtime_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct spi_st *spi_st = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_controller_get_devdata(host); int ret; ret = clk_prepare_enable(spi_st->clk); @@ -408,10 +414,10 @@ static int spi_st_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int spi_st_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *host = dev_get_drvdata(dev); int ret; - ret = spi_master_suspend(master); + ret = spi_controller_suspend(host); if (ret) return ret; @@ -420,10 +426,10 @@ static int spi_st_suspend(struct device *dev) static int spi_st_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *host = dev_get_drvdata(dev); int ret; - ret = spi_master_resume(master); + ret = spi_controller_resume(host); if (ret) return ret; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 6a02561cc20ce9..ad091a216b0764 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1136,7 +1136,8 @@ sbc_execute_unmap(struct se_cmd *cmd) goto err; } - if (lba + range > dev->transport->get_blocks(dev) + 1) { + if (lba + range < lba || + lba + range > dev->transport->get_blocks(dev) + 1) { ret = TCM_ADDRESS_OUT_OF_RANGE; goto err; } diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c index 96d99289799a16..a935002c2bdbe7 100644 --- a/drivers/thermal/spear_thermal.c +++ b/drivers/thermal/spear_thermal.c @@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; int ret = 0, val; - if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { + if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); return -EINVAL; } diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 543f35ddf523c4..26953f0daa9fc9 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { */ static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) { - if (num > hvc_iucv_devices) + if (num >= hvc_iucv_devices) return NULL; return hvc_iucv_table[num]; } diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 5ad237d77a9a9f..b26d9a8e4e0558 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -547,7 +547,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, busyloop_timeout = poll_rx ? rvq->busyloop_timeout: tvq->busyloop_timeout; - preempt_disable(); + migrate_disable(); endtime = busy_clock() + busyloop_timeout; while (vhost_can_busy_poll(endtime)) { @@ -564,7 +564,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, cpu_relax(); } - preempt_enable(); + migrate_enable(); if (poll_rx || sock_has_rx_data(sock)) vhost_net_busy_poll_try_queue(net, vq); diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c index eb18c6eb0ff0df..6ce1c3c5f5676c 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -204,6 +204,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); + if (IS_ERR(pdata->gpiod_enable)) + return dev_err_cast_probe(dev, pdata->gpiod_enable, + "failed to get gpio\n"); ret = of_property_count_u32_elems(np, "led-sources"); if (ret < 0) { diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c index ff8e321a22cefc..b2d3f7328ea83c 100644 --- a/drivers/video/fbdev/matrox/g450_pll.c +++ b/drivers/video/fbdev/matrox/g450_pll.c @@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, case M_VIDEO_PLL: { u_int8_t tmp; - unsigned int mnp; + unsigned int mnp __maybe_unused; unsigned long flags; matroxfb_DAC_lock_irqsave(flags); diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c index dcb1b81d35db57..0e81d68378935f 100644 --- a/drivers/video/fbdev/offb.c +++ b/drivers/video/fbdev/offb.c @@ -643,8 +643,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod vid = be32_to_cpup(vidp); did = be32_to_cpup(didp); pdev = pci_get_device(vid, did, NULL); - if (!pdev || pci_enable_device(pdev)) + if (!pdev) return; + + if (pci_enable_device(pdev)) { + pci_dev_put(pdev); + return; + } } #endif /* kludge for valkyrie */ diff --git a/fs/adfs/super.c b/fs/adfs/super.c index e8bfc38239cd59..76e37c6d4cad4a 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, if (adfs_checkdiscrecord(dr)) return -EILSEQ; + if ((dr->nzones | dr->nzones_high << 8) == 0) + return -EILSEQ; + *drp = dr; return 0; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 46df425ab7bae8..7add1a019d8578 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1209,7 +1209,7 @@ out_free_reserve: extent_clear_unlock_delalloc(inode, start, end, NULL, EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | - EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, + EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK); free_async_extent_pages(async_extent); @@ -4623,32 +4623,33 @@ out_up_write: return ret; } -static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) +static int btrfs_rmdir(struct inode *vfs_dir, struct dentry *dentry) { - struct inode *inode = d_inode(dentry); - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + struct btrfs_inode *dir = BTRFS_I(vfs_dir); + struct btrfs_inode *inode = BTRFS_I(d_inode(dentry)); + struct btrfs_fs_info *fs_info = inode->root->fs_info; int ret = 0; struct btrfs_trans_handle *trans; struct fscrypt_name fname; - if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) + if (inode->vfs_inode.i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; - if (btrfs_ino(BTRFS_I(inode)) == BTRFS_FIRST_FREE_OBJECTID) { + if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) { if (unlikely(btrfs_fs_incompat(fs_info, EXTENT_TREE_V2))) { btrfs_err(fs_info, "extent tree v2 doesn't support snapshot deletion yet"); return -EOPNOTSUPP; } - return btrfs_delete_subvolume(BTRFS_I(dir), dentry); + return btrfs_delete_subvolume(dir, dentry); } - ret = fscrypt_setup_filename(dir, &dentry->d_name, 1, &fname); + ret = fscrypt_setup_filename(vfs_dir, &dentry->d_name, 1, &fname); if (ret) return ret; /* This needs to handle no-key deletions later on */ - trans = __unlink_start_trans(BTRFS_I(dir)); + trans = __unlink_start_trans(dir); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_notrans; @@ -4668,23 +4669,24 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) * This is because we can't unlink other roots when replaying the dir * deletes for directory foo. */ - if (BTRFS_I(inode)->last_unlink_trans >= trans->transid) - btrfs_record_snapshot_destroy(trans, BTRFS_I(dir)); + if (inode->last_unlink_trans >= trans->transid) + btrfs_record_snapshot_destroy(trans, dir); - if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { - ret = btrfs_unlink_subvol(trans, BTRFS_I(dir), dentry); + if (unlikely(btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { + ret = btrfs_unlink_subvol(trans, dir, dentry); goto out; } - ret = btrfs_orphan_add(trans, BTRFS_I(inode)); + ret = btrfs_orphan_add(trans, inode); if (ret) goto out; + btrfs_record_unlink_dir(trans, dir, inode, false); + /* now the directory is empty */ - ret = btrfs_unlink_inode(trans, BTRFS_I(dir), BTRFS_I(d_inode(dentry)), - &fname.disk_name); + ret = btrfs_unlink_inode(trans, dir, inode, &fname.disk_name); if (!ret) - btrfs_i_size_write(BTRFS_I(inode), 0); + btrfs_i_size_write(inode, 0); out: btrfs_end_transaction(trans); out_notrans: diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 0a960b6c866e5b..a54649a5e07855 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -262,11 +262,9 @@ static int create_space_info_sub_group(struct btrfs_space_info *parent, u64 flag sub_group->parent = parent; sub_group->subgroup_id = id; - ret = btrfs_sysfs_add_space_info_type(fs_info, sub_group); - if (ret) { - kfree(sub_group); + ret = btrfs_sysfs_add_space_info_type(sub_group); + if (ret) parent->sub_group[index] = NULL; - } return ret; } @@ -291,7 +289,7 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags) goto out_free; } - ret = btrfs_sysfs_add_space_info_type(info, space_info); + ret = btrfs_sysfs_add_space_info_type(space_info); if (ret) return ret; diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 9609579d2289c8..6f01b89add673c 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -1674,13 +1674,12 @@ static const char *alloc_name(struct btrfs_space_info *space_info) * Create a sysfs entry for a space info type at path * /sys/fs/btrfs/UUID/allocation/TYPE */ -int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info) +int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info) { int ret; ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, - fs_info->space_info_kobj, "%s", + space_info->fs_info->space_info_kobj, "%s", alloc_name(space_info)); if (ret) { kobject_put(&space_info->kobj); diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 86c7eef128731e..9a781ba14db04d 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -27,8 +27,7 @@ void __cold btrfs_exit_sysfs(void); int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info); void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info); void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache); -int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info); +int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info); void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info); void btrfs_sysfs_update_devid(struct btrfs_device *device); diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 558f64554b5914..6fd6a652499ec6 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -1279,6 +1279,7 @@ retry: do_sync: spin_unlock(&ci->i_ceph_lock); + ceph_buffer_put(old_blob); do_sync_unlocked: if (lock_snap_rwsem) up_read(&mdsc->snap_rwsem); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index e40229c47fe587..a9097a6c7b5a39 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -907,7 +907,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, return ret; } -EXPORT_SYMBOL_GPL(debugfs_create_str); static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -987,7 +986,7 @@ static const struct file_operations fops_str_wo = { * directory dentry if set. If this parameter is %NULL, then the * file will be created in the root of the debugfs filesystem. * @value: a pointer to the variable that the file should read to and write - * from. + * from. This pointer and the string it points to must not be %NULL. * * This function creates a file in debugfs with the given name that * contains the value of the variable @value. If the @mode variable is so @@ -996,9 +995,13 @@ static const struct file_operations fops_str_wo = { void debugfs_create_str(const char *name, umode_t mode, struct dentry *parent, char **value) { + if (WARN_ON(!value || !*value)) + return; + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, &fops_str_ro, &fops_str_wo); } +EXPORT_SYMBOL_GPL(debugfs_create_str); static ssize_t read_file_blob(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index fb35f78e60bb33..50847fd7e55045 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1824,6 +1824,9 @@ struct f2fs_sb_info { spinlock_t iostat_lat_lock; struct iostat_lat_info *iostat_io_lat; #endif +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lock_class_key cp_global_sem_key; +#endif }; /* Definitions to access f2fs_sb_info */ diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index d5e8f3e40cc93b..92bbdb272a6d93 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -791,7 +791,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, int f2fs_inline_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { - __u64 byteaddr, ilen; + __u64 byteaddr = 0, ilen; __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | FIEMAP_EXTENT_LAST; struct node_info ni; @@ -824,9 +824,14 @@ int f2fs_inline_data_fiemap(struct inode *inode, if (err) goto out; - byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; - byteaddr += (char *)inline_data_addr(inode, ipage) - - (char *)F2FS_INODE(ipage); + if (__is_valid_data_blkaddr(ni.blk_addr)) { + byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; + byteaddr += (char *)inline_data_addr(inode, ipage) - + (char *)F2FS_INODE(ipage); + } else { + f2fs_bug_on(F2FS_I_SB(inode), ni.blk_addr != NEW_ADDR); + flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; + } err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags); trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err); out: diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 7614d93bd67fbd..c018d548e16348 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1694,6 +1694,9 @@ static void f2fs_put_super(struct super_block *sb) kvfree(sbi->write_io[i]); #if IS_ENABLED(CONFIG_UNICODE) utf8_unload(sb->s_encoding); +#endif +#ifdef CONFIG_DEBUG_LOCK_ALLOC + lockdep_unregister_key(&sbi->cp_global_sem_key); #endif kfree(sbi); } @@ -4380,6 +4383,11 @@ try_onemore: init_f2fs_rwsem(&sbi->gc_lock); mutex_init(&sbi->writepages); init_f2fs_rwsem(&sbi->cp_global_sem); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + lockdep_register_key(&sbi->cp_global_sem_key); + lockdep_set_class(&sbi->cp_global_sem.internal_rwsem, + &sbi->cp_global_sem_key); +#endif init_f2fs_rwsem(&sbi->node_write); init_f2fs_rwsem(&sbi->node_change); spin_lock_init(&sbi->stat_lock); @@ -4838,6 +4846,9 @@ free_sb_buf: free_sbi: if (sbi->s_chksum_driver) crypto_free_shash(sbi->s_chksum_driver); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + lockdep_unregister_key(&sbi->cp_global_sem_key); +#endif kfree(sbi); /* give only one another chance */ diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 436bbf23f8e7c6..4cd2d4bde217ad 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -162,50 +162,50 @@ static ssize_t features_show(struct f2fs_attr *a, int len = 0; if (f2fs_sb_has_encrypt(sbi)) - len += scnprintf(buf, PAGE_SIZE - len, "%s", + len += sysfs_emit_at(buf, len, "%s", "encryption"); if (f2fs_sb_has_blkzoned(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "extra_attr"); if (f2fs_sb_has_project_quota(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "projquota"); if (f2fs_sb_has_inode_chksum(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_checksum"); if (f2fs_sb_has_flexible_inline_xattr(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "flexible_inline_xattr"); if (f2fs_sb_has_quota_ino(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "quota_ino"); if (f2fs_sb_has_inode_crtime(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_crtime"); if (f2fs_sb_has_lost_found(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "lost_found"); if (f2fs_sb_has_verity(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "verity"); if (f2fs_sb_has_sb_chksum(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "sb_checksum"); if (f2fs_sb_has_casefold(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "casefold"); if (f2fs_sb_has_readonly(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "readonly"); if (f2fs_sb_has_compression(sbi)) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "compression"); - len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", + len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "pin_file"); - len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + len += sysfs_emit_at(buf, len, "\n"); return len; } @@ -318,21 +318,21 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, if (!strcmp(a->attr.name, "extension_list")) { __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; - int cold_count = le32_to_cpu(sbi->raw_super->extension_count); - int hot_count = sbi->raw_super->hot_ext_count; + int cold_count, hot_count; int len = 0, i; - len += scnprintf(buf + len, PAGE_SIZE - len, - "cold file extension:\n"); + f2fs_down_read(&sbi->sb_lock); + cold_count = le32_to_cpu(sbi->raw_super->extension_count); + hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); for (i = 0; i < cold_count; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", - extlist[i]); + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); - len += scnprintf(buf + len, PAGE_SIZE - len, - "hot file extension:\n"); + len += sysfs_emit_at(buf, len, "hot file extension:\n"); for (i = cold_count; i < cold_count + hot_count; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", - extlist[i]); + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); + f2fs_up_read(&sbi->sb_lock); + return len; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 45040622d316e0..18f75beea0890b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -805,7 +805,7 @@ retry: goto fail_gunlock4; mark_inode_dirty(inode); - d_instantiate(dentry, inode); + d_instantiate_new(dentry, inode); /* After instantiate, errors should result in evict which will destroy * both inode and iopen glocks properly. */ if (file) { @@ -817,7 +817,6 @@ retry: gfs2_glock_dq_uninit(&gh); gfs2_glock_put(io_gl); gfs2_qa_put(dip); - unlock_new_inode(inode); return error; fail_gunlock4: diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 2be5551241b3ad..b8be6c1c942d45 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -478,8 +478,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) { atomic_add(blks, &sdp->sd_log_blks_free); trace_gfs2_log_blocks(sdp, blks); - gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= - sdp->sd_jdesc->jd_blocks); + gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || + atomic_read(&sdp->sd_log_blks_free) <= + sdp->sd_jdesc->jd_blocks); if (atomic_read(&sdp->sd_log_blks_needed)) wake_up(&sdp->sd_log_waitq); } @@ -1024,14 +1025,15 @@ static void trans_drain(struct gfs2_trans *tr) } /** - * gfs2_log_flush - flush incore transaction(s) + * __gfs2_log_flush - flush incore transaction(s) * @sdp: The filesystem * @gl: The glock structure to flush. If NULL, flush the whole incore log * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags * */ -void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) +static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, + u32 flags) { struct gfs2_trans *tr = NULL; unsigned int reserved_blocks = 0, used_blocks = 0; @@ -1039,7 +1041,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) unsigned int first_log_head; unsigned int reserved_revokes = 0; - down_write(&sdp->sd_log_flush_lock); trace_gfs2_log_flush(sdp, 1, flags); repeat: @@ -1151,7 +1152,6 @@ out: gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); gfs2_log_release(sdp, reserved_blocks - used_blocks); } - up_write(&sdp->sd_log_flush_lock); gfs2_trans_free(sdp, tr); if (gfs2_withdrawing(sdp)) gfs2_withdraw(sdp); @@ -1174,6 +1174,13 @@ out_withdraw: goto out_end; } +void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) +{ + down_write(&sdp->sd_log_flush_lock); + __gfs2_log_flush(sdp, gl, flags); + up_write(&sdp->sd_log_flush_lock); +} + /** * gfs2_merge_trans - Merge a new transaction into a cached transaction * @sdp: the filesystem @@ -1315,19 +1322,25 @@ int gfs2_logd(void *data) } if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { + down_write(&sdp->sd_log_flush_lock); gfs2_ail1_empty(sdp, 0); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | - GFS2_LFC_LOGD_JFLUSH_REQD); + __gfs2_log_flush(sdp, NULL, + GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_JFLUSH_REQD); + up_write(&sdp->sd_log_flush_lock); } if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || gfs2_ail_flush_reqd(sdp)) { clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); + down_write(&sdp->sd_log_flush_lock); gfs2_ail1_start(sdp); gfs2_ail1_wait(sdp); gfs2_ail1_empty(sdp, 0); - gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | - GFS2_LFC_LOGD_AIL_FLUSH_REQD); + __gfs2_log_flush(sdp, NULL, + GFS2_LOG_HEAD_FLUSH_NORMAL | + GFS2_LFC_LOGD_AIL_FLUSH_REQD); + up_write(&sdp->sd_log_flush_lock); } t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c index 2ff07ba655a072..781ea403498e36 100644 --- a/fs/netfs/iterator.c +++ b/fs/netfs/iterator.c @@ -22,7 +22,7 @@ * * Extract the page fragments from the given amount of the source iterator and * build up a second iterator that refers to all of those bits. This allows - * the original iterator to disposed of. + * the original iterator to be disposed of. * * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA be * allowed on the pages extracted. @@ -43,7 +43,7 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, unsigned int max_pages; unsigned int npages = 0; unsigned int i; - ssize_t ret; + ssize_t ret = 0; size_t count = orig_len, offset, len; size_t bv_size, pg_size; @@ -67,8 +67,8 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, ret = iov_iter_extract_pages(orig, &pages, count, max_pages - npages, extraction_flags, &offset); - if (ret < 0) { - pr_err("Couldn't get user pages (rc=%zd)\n", ret); + if (unlikely(ret <= 0)) { + ret = ret ?: -EIO; break; } @@ -97,6 +97,13 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, npages += cur_npages; } + if (ret < 0 && (ret == -ENOMEM || npages == 0)) { + for (i = 0; i < npages; i++) + unpin_user_page(bv[i].bv_page); + kvfree(bv); + return ret; + } + iov_iter_bvec(new, orig->data_source, bv, npages, orig_len - count); return npages; } diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index e498aade8c4796..15f66d949adda1 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) sector_t isect, extent_length = 0; struct parallel_io *par = NULL; loff_t offset = header->args.offset; - size_t count = header->args.count; struct page **pages = header->args.pages; int pg_index = header->args.pgbase >> PAGE_SHIFT; unsigned int pg_len; struct blk_plug plug; int i; - dprintk("%s enter, %zu@%lld\n", __func__, count, offset); + dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); /* At this point, header->page_aray is a (sequential) list of nfs_pages. * We want to write each, and if there is an error set pnfs_error @@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) } offset += pg_len; - count -= pg_len; isect += (pg_len >> SECTOR_SHIFT); extent_length -= (pg_len >> SECTOR_SHIFT); } diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 53022bfe0b72d2..1a6868afa9143f 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -751,6 +751,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, int ret, i; for (i = 0; i < nmembs; i++) { + /* + * bd_oblocknr must never be 0 as block 0 + * is never a valid GC target block + */ + if (unlikely(!bdescs[i].bd_oblocknr)) + return -EINVAL; /* XXX: use macro or inline func to check liveness */ ret = nilfs_bmap_lookup_at_level(bmap, bdescs[i].bd_offset, diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c index 6b93c909bdc9e4..894fd44164b48a 100644 --- a/fs/ntfs3/dir.c +++ b/fs/ntfs3/dir.c @@ -425,8 +425,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx) if (!dir_emit_dots(file, ctx)) return 0; - /* Allocate PATH_MAX bytes. */ - name = __getname(); + name = kmalloc(PATH_MAX, GFP_KERNEL); if (!name) return -ENOMEM; @@ -504,7 +503,7 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx) out: - __putname(name); + kfree(name); put_indx_node(node); if (err == 1) { diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index e17d4c1ba06f0a..a38547bd12bb46 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -2666,7 +2666,7 @@ int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len) struct ntfs_inode *ni = sbi->volume.ni; const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */ /* Allocate PATH_MAX bytes. */ - struct cpu_str *uni = __getname(); + struct cpu_str *uni = kmalloc(PATH_MAX, GFP_KERNEL); if (!uni) return -ENOMEM; @@ -2709,6 +2709,6 @@ unlock_out: err = _ni_write_inode(&ni->vfs_inode, 0); out: - __putname(uni); + kfree(uni); return err; } \ No newline at end of file diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index ce381eafd084e4..787e15ba0ca406 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1327,7 +1327,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir, fa |= FILE_ATTRIBUTE_READONLY; /* Allocate PATH_MAX bytes. */ - new_de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); + new_de = kzalloc(PATH_MAX, GFP_KERNEL); if (!new_de) { err = -ENOMEM; goto out1; @@ -1733,7 +1733,7 @@ out3: ntfs_mark_rec_free(sbi, ino, false); out2: - __putname(new_de); + kfree(new_de); kfree(rp); out1: @@ -1756,7 +1756,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) struct NTFS_DE *de; /* Allocate PATH_MAX bytes. */ - de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); + de = kzalloc(PATH_MAX, GFP_KERNEL); if (!de) return -ENOMEM; @@ -1770,7 +1770,7 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de); out: - __putname(de); + kfree(de); return err; } @@ -1793,8 +1793,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry) if (ntfs_is_meta_file(sbi, ni->mi.rno)) return -EINVAL; - /* Allocate PATH_MAX bytes. */ - de = kmem_cache_zalloc(names_cachep, GFP_KERNEL); + de = kzalloc(PATH_MAX, GFP_KERNEL); if (!de) return -ENOMEM; @@ -1830,7 +1829,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry) out: ni_unlock(ni); - __putname(de); + kfree(de); return err; } diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index f5901c23ab9379..1b0c075c148539 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -68,7 +68,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, u32 flags) { struct ntfs_inode *ni = ntfs_i(dir); - struct cpu_str *uni = __getname(); + struct cpu_str *uni = kmalloc(PATH_MAX, GFP_KERNEL); struct inode *inode; int err; @@ -85,7 +85,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, inode = dir_search_u(dir, uni, NULL); ni_unlock(ni); } - __putname(uni); + kfree(uni); } /* @@ -304,8 +304,7 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir, return err; } - /* Allocate PATH_MAX bytes. */ - de = __getname(); + de = kmalloc(PATH_MAX, GFP_KERNEL); if (!de) return -ENOMEM; @@ -350,7 +349,7 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir, ni_unlock(ni); ni_unlock(dir_ni); out: - __putname(de); + kfree(de); return err; } @@ -497,7 +496,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name) /* * Try slow way with current upcase table */ - uni = kmem_cache_alloc(names_cachep, GFP_NOWAIT); + uni = kmalloc(PATH_MAX, GFP_NOWAIT); if (!uni) return -ENOMEM; @@ -519,7 +518,7 @@ static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name) err = 0; out: - kmem_cache_free(names_cachep, uni); + kfree(uni); return err; } @@ -558,7 +557,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1, * Try slow way with current upcase table */ sbi = dentry->d_sb->s_fs_info; - uni1 = __getname(); + uni1 = kmalloc(PATH_MAX, GFP_NOWAIT); if (!uni1) return -ENOMEM; @@ -588,7 +587,7 @@ static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1, ret = !ntfs_cmp_names_cpu(uni1, uni2, sbi->upcase, false) ? 0 : 1; out: - __putname(uni1); + kfree(uni1); return ret; } diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 0b96d0f995c61c..a4cc56df549a69 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1228,8 +1228,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) le32_to_cpu(attr->res.data_size) >> 1, UTF16_LITTLE_ENDIAN, sbi->volume.label, sizeof(sbi->volume.label)); - if (err < 0) + if (err < 0) { sbi->volume.label[0] = 0; + } else if (err >= sizeof(sbi->volume.label)) { + sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; + } else { + sbi->volume.label[err] = 0; + } } else { /* Should we break mounting here? */ //err = -EINVAL; diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 72bceb8cd164b6..a03b4bce5fbfd7 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -551,8 +551,7 @@ struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, int err; void *buf; - /* Allocate PATH_MAX bytes. */ - buf = __getname(); + buf = kmalloc(PATH_MAX, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); @@ -583,7 +582,7 @@ struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, if (!IS_ERR(acl)) set_cached_acl(inode, type, acl); - __putname(buf); + kfree(buf); return acl; } diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 5c04dde99981c7..8e4b575a2bc9fc 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, goto bail; } + if (qr->qr_numregions > O2NM_MAX_REGIONS) { + mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " + "number of heartbeat regions %u\n", + qr->qr_domain, qr->qr_node, qr->qr_numregions); + status = -EINVAL; + goto bail; + } + r = remote; for (i = 0; i < qr->qr_numregions; ++i) { mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); @@ -994,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, for (i = 0; i < localnr; ++i) { foundit = 0; r = remote; - for (j = 0; j <= qr->qr_numregions; ++j) { + for (j = 0; j < qr->qr_numregions; ++j) { if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { foundit = 1; break; diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index b1550ba73f9634..f34f404af2f77b 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c @@ -442,13 +442,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, struct buffer_head *bh = NULL; struct ocfs2_group_desc *bg = NULL; - unsigned int max_bits, num_clusters; + unsigned int max_bits, max_bitmap_bits, num_clusters; unsigned int offset = 0, cluster, chunk; unsigned int chunk_free, last_chunksize = 0; if (!le32_to_cpu(rec->c_free)) goto bail; + max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, + osb->s_feature_incompat); + do { if (!bg) blkno = le64_to_cpu(rec->c_blkno); @@ -480,6 +483,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, continue; max_bits = le16_to_cpu(bg->bg_bits); + + /* + * Non-coherent scans read raw blocks and do not get the + * bg_bits validation from + * ocfs2_read_group_descriptor(). + */ + if (max_bits > max_bitmap_bits) { + mlog(ML_ERROR, + "Group desc #%llu has %u bits, max bitmap bits %u\n", + (unsigned long long)blkno, max_bits, max_bitmap_bits); + max_bits = max_bitmap_bits; + } + offset = 0; for (chunk = 0; chunk < chunks_in_group; chunk++) { diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c index 42c0d314f95e8d..acf2769f4c8c72 100644 --- a/fs/ocfs2/resize.c +++ b/fs/ocfs2/resize.c @@ -500,14 +500,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) goto out_unlock; } - ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); - ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); if (ret) { mlog_errno(ret); goto out_free_group_bh; } + ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); + trace_ocfs2_group_add((unsigned long long)input->group, input->chain, input->clusters, input->frees); @@ -515,7 +515,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) if (IS_ERR(handle)) { mlog_errno(PTR_ERR(handle)); ret = -EINVAL; - goto out_free_group_bh; + goto out_remove_cache; } cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); @@ -569,9 +569,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) out_commit: ocfs2_commit_trans(osb, handle); -out_free_group_bh: +out_remove_cache: if (ret < 0) - ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); + ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); + +out_free_group_bh: brelse(group_bh); out_unlock: diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d0cb529b612a7f..750c1fc70d25a7 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -907,8 +907,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, total_len = prefix_len + name_len + 1; *result += total_len; - /* we are just looking for how big our buffer needs to be */ - if (!size) + /* No buffer means we are only looking for the required size. */ + if (!buffer) return 0; if (*result > size) diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 2f8c1882f45c85..60ef691aeb7020 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -514,6 +514,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh; } + if (sbi->s_sys_blocksize < OMFS_DIR_START) { + printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", + sbi->s_sys_blocksize); + goto out_brelse_bh; + } + if (sbi->s_blocksize < sbi->s_sys_blocksize || sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { printk(KERN_ERR "omfs: block size (%d) is out of range\n", diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 7b6d6378a3b87d..95675d4bab1416 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, else va = ioremap_wc(start, size); + /* We must release the mem region if ioremap fails. */ + if (!va) + release_mem_region(start, size); + /* * Since request_mem_region() and ioremap() are byte-granularity * there is no need handle anything special like we do when the diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 42a7d0a71b22ee..7562ee4ff2929e 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -364,6 +364,31 @@ static inline int dquot_active(struct dquot *dquot) return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); } +static struct dquot *__dqgrab(struct dquot *dquot) +{ + lockdep_assert_held(&dq_list_lock); + if (!atomic_read(&dquot->dq_count)) + remove_free_dquot(dquot); + atomic_inc(&dquot->dq_count); + return dquot; +} + +/* + * Get reference to dquot when we got pointer to it by some other means. The + * dquot has to be active and the caller has to make sure it cannot get + * deactivated under our hands. + */ +struct dquot *dqgrab(struct dquot *dquot) +{ + spin_lock(&dq_list_lock); + WARN_ON_ONCE(!dquot_active(dquot)); + dquot = __dqgrab(dquot); + spin_unlock(&dq_list_lock); + + return dquot; +} +EXPORT_SYMBOL_GPL(dqgrab); + static inline int dquot_dirty(struct dquot *dquot) { return test_bit(DQ_MOD_B, &dquot->dq_flags); @@ -642,15 +667,14 @@ int dquot_scan_active(struct super_block *sb, continue; if (dquot->dq_sb != sb) continue; - /* Now we have active dquot so we can just increase use count */ - atomic_inc(&dquot->dq_count); + __dqgrab(dquot); spin_unlock(&dq_list_lock); dqput(old_dquot); old_dquot = dquot; /* * ->release_dquot() can be racing with us. Our reference - * protects us from new calls to it so just wait for any - * outstanding call and recheck the DQ_ACTIVE_B after that. + * protects us from dquot_release() proceeding so just wait for + * any outstanding call and recheck the DQ_ACTIVE_B after that. */ wait_on_dquot(dquot); if (dquot_active(dquot)) { @@ -718,7 +742,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) /* Now we have active dquot from which someone is * holding reference so we can safely just increase * use count */ - dqgrab(dquot); + __dqgrab(dquot); spin_unlock(&dq_list_lock); err = dquot_write_dquot(dquot); if (err && !ret) @@ -973,9 +997,7 @@ we_slept: spin_unlock(&dq_list_lock); dqstats_inc(DQST_LOOKUPS); } else { - if (!atomic_read(&dquot->dq_count)) - remove_free_dquot(dquot); - atomic_inc(&dquot->dq_count); + __dqgrab(dquot); spin_unlock(&dq_list_lock); dqstats_inc(DQST_CACHE_HITS); dqstats_inc(DQST_LOOKUPS); diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c index 855ac5a62edfaa..8ea532cdc4302b 100644 --- a/fs/smb/client/ioctl.c +++ b/fs/smb/client/ioctl.c @@ -280,7 +280,7 @@ search_end: break; case SMB2_ENCRYPTION_AES256_CCM: case SMB2_ENCRYPTION_AES256_GCM: - out.session_key_length = CIFS_SESS_KEY_SIZE; + out.session_key_length = ses->auth_key.len; out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE; break; default: diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c index 4e7d5c612256d6..576c72691e3748 100644 --- a/fs/smb/client/smb2file.c +++ b/fs/smb/client/smb2file.c @@ -27,10 +27,11 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov) { struct smb2_err_rsp *err = iov->iov_base; struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL); + u8 *end = (u8 *)err + iov->iov_len; u32 len; if (err->ErrorContextCount) { - struct smb2_error_context_rsp *p, *end; + struct smb2_error_context_rsp *p; len = (u32)err->ErrorContextCount * (offsetof(struct smb2_error_context_rsp, ErrorContextData) + @@ -39,25 +40,29 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov) return ERR_PTR(-EINVAL); p = (struct smb2_error_context_rsp *)err->ErrorData; - end = (struct smb2_error_context_rsp *)((u8 *)err + iov->iov_len); - do { + while ((u8 *)p + sizeof(*p) <= end) { if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) { - sym = (struct smb2_symlink_err_rsp *)&p->ErrorContextData; + sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData; break; } cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n", __func__, le32_to_cpu(p->ErrorId)); len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8); - p = (struct smb2_error_context_rsp *)((u8 *)&p->ErrorContextData + len); - } while (p < end); + if (len > end - ((u8 *)p + sizeof(*p))) + return ERR_PTR(-EINVAL); + + p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len); + } } else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) && iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) { sym = (struct smb2_symlink_err_rsp *)err->ErrorData; } - if (!IS_ERR(sym) && (le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG || - le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK)) + if (!IS_ERR(sym) && + ((u8 *)sym + sizeof(*sym) > end || + le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG || + le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK)) sym = ERR_PTR(-EINVAL); return sym; @@ -82,8 +87,10 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec print_len = le16_to_cpu(sym->PrintNameLength); print_offs = le16_to_cpu(sym->PrintNameOffset); - if (iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offs + sub_len || - iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offs + print_len) + if ((char *)sym->PathBuffer + sub_offs + sub_len > + (char *)iov->iov_base + iov->iov_len || + (char *)sym->PathBuffer + print_offs + print_len > + (char *)iov->iov_base + iov->iov_len) return -EINVAL; return smb2_parse_native_symlink(path, diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 076d9e83e1a044..2eb15f3a7fe66c 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -79,7 +79,7 @@ struct smb2_symlink_err_rsp { struct smb2_error_context_rsp { __le32 ErrorDataLength; __le32 ErrorId; - __u8 ErrorContextData; /* ErrorDataLength long array */ + __u8 ErrorContextData[]; } __packed; /* ErrorId values */ diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index daf8ba2cd8a100..63907fb245e9a3 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -334,7 +334,8 @@ out: } static int generate_key(struct cifs_ses *ses, struct kvec label, - struct kvec context, __u8 *key, unsigned int key_size) + struct kvec context, __u8 *key, unsigned int key_size, + unsigned int full_key_size) { unsigned char zero = 0x0; __u8 i[4] = {0, 0, 0, 1}; @@ -355,7 +356,7 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, } rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm, - ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); + ses->auth_key.response, full_key_size); if (rc) { cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); goto smb3signkey_ret; @@ -430,6 +431,7 @@ generate_smb3signingkey(struct cifs_ses *ses, struct TCP_Server_Info *server, const struct derivation_triplet *ptriplet) { + unsigned int full_key_size = SMB2_NTLMV2_SESSKEY_SIZE; int rc; bool is_binding = false; int chan_index = 0; @@ -464,17 +466,31 @@ generate_smb3signingkey(struct cifs_ses *ses, rc = generate_key(ses, ptriplet->signing.label, ptriplet->signing.context, ses->chans[chan_index].signkey, - SMB3_SIGN_KEY_SIZE); + SMB3_SIGN_KEY_SIZE, + SMB2_NTLMV2_SESSKEY_SIZE); if (rc) return rc; } else { rc = generate_key(ses, ptriplet->signing.label, ptriplet->signing.context, ses->smb3signingkey, - SMB3_SIGN_KEY_SIZE); + SMB3_SIGN_KEY_SIZE, + SMB2_NTLMV2_SESSKEY_SIZE); if (rc) return rc; + /* + * Per MS-SMB2 3.2.5.3.1, signing key always uses Session.SessionKey + * (first 16 bytes). Encryption/decryption keys use + * Session.FullSessionKey when dialect is 3.1.1 and cipher is + * AES-256-CCM or AES-256-GCM, otherwise Session.SessionKey. + */ + + if (server->dialect == SMB311_PROT_ID && + (server->cipher_type == SMB2_ENCRYPTION_AES256_CCM || + server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) + full_key_size = ses->auth_key.len; + /* safe to access primary channel, since it will never go away */ spin_lock(&ses->chan_lock); memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey, @@ -484,13 +500,15 @@ generate_smb3signingkey(struct cifs_ses *ses, rc = generate_key(ses, ptriplet->encryption.label, ptriplet->encryption.context, ses->smb3encryptionkey, - SMB3_ENC_DEC_KEY_SIZE); + SMB3_ENC_DEC_KEY_SIZE, + full_key_size); if (rc) return rc; rc = generate_key(ses, ptriplet->decryption.label, ptriplet->decryption.context, ses->smb3decryptionkey, - SMB3_ENC_DEC_KEY_SIZE); + SMB3_ENC_DEC_KEY_SIZE, + full_key_size); if (rc) return rc; } @@ -505,7 +523,7 @@ generate_smb3signingkey(struct cifs_ses *ses, &ses->Suid); cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type); cifs_dbg(VFS, "Session Key %*ph\n", - SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); + (int)ses->auth_key.len, ses->auth_key.response); cifs_dbg(VFS, "Signing Key %*ph\n", SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index 16a57425099dea..825cc03692754a 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -514,6 +514,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, int in_len, char *out_blob, int *out_len) { struct ksmbd_spnego_authen_response *resp; + struct ksmbd_login_response_ext *resp_ext = NULL; struct ksmbd_user *user = NULL; int retval; @@ -542,7 +543,10 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, goto out; } - user = ksmbd_alloc_user(&resp->login_response); + if (resp->login_response.status & KSMBD_USER_FLAG_EXTENSION) + resp_ext = ksmbd_ipc_login_request_ext(resp->login_response.account); + + user = ksmbd_alloc_user(&resp->login_response, resp_ext); if (!user) { ksmbd_debug(AUTH, "login failure\n"); retval = -ENOMEM; @@ -1106,6 +1110,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc; + DECLARE_CRYPTO_WAIT(wait); struct scatterlist *sg; u8 sign[SMB2_SIGNATURE_SIZE] = {}; u8 key[SMB3_ENC_DEC_KEY_SIZE]; @@ -1192,12 +1197,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, aead_request_set_crypt(req, sg, sg, crypt_len, iv); aead_request_set_ad(req, assoc_data_len); - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); - if (enc) - rc = crypto_aead_encrypt(req); - else - rc = crypto_aead_decrypt(req); + rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : + crypto_aead_decrypt(req), &wait); if (rc) goto free_iv; diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index a5209abb004a4a..bbb0be5524dbe0 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -41,6 +41,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) kfree(conn->preauth_info); kfree(conn->mechToken); if (atomic_dec_and_test(&conn->refcnt)) { + /* + * async_ida is embedded in struct ksmbd_conn, so pair + * ida_destroy() with the final kfree() rather than with + * the unconditional field teardown above. This keeps + * the IDA valid for the entire lifetime of the struct, + * even while other refcount holders (oplock / vfs + * durable handles) still reference the connection. + */ + ida_destroy(&conn->async_ida); conn->transport->ops->free_transport(conn->transport); kfree(conn); } diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h index 363501fc308aa3..125ea1b9839efc 100644 --- a/fs/smb/server/ksmbd_netlink.h +++ b/fs/smb/server/ksmbd_netlink.h @@ -51,6 +51,9 @@ * - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response) * This event is to make kerberos authentication to be processed in * userspace. + * + * - KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT(ksmbd_login_request_ext/response_ext) + * This event is to get user account extension info to user IPC daemon. */ #define KSMBD_GENL_NAME "SMBD_GENL" @@ -147,6 +150,16 @@ struct ksmbd_login_response { __u32 reserved[16]; /* Reserved room */ }; +/* + * IPC user login response extension. + */ +struct ksmbd_login_response_ext { + __u32 handle; + __s32 ngroups; /* supplementary group count */ + __s8 reserved[128]; /* Reserved room */ + __s8 ____payload[]; +}; + /* * IPC request to fetch net share config. */ @@ -308,6 +321,9 @@ enum ksmbd_event { KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15, + KSMBD_EVENT_LOGIN_REQUEST_EXT, + KSMBD_EVENT_LOGIN_RESPONSE_EXT, + __KSMBD_EVENT_MAX, KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1 }; @@ -338,6 +354,7 @@ enum KSMBD_TREE_CONN_STATUS { #define KSMBD_USER_FLAG_BAD_USER BIT(3) #define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4) #define KSMBD_USER_FLAG_DELAY_SESSION BIT(5) +#define KSMBD_USER_FLAG_EXTENSION BIT(6) /* * Share config flags. diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c index 279d00feff2168..e9b3a8e049668f 100644 --- a/fs/smb/server/mgmt/user_config.c +++ b/fs/smb/server/mgmt/user_config.c @@ -12,6 +12,7 @@ struct ksmbd_user *ksmbd_login_user(const char *account) { struct ksmbd_login_response *resp; + struct ksmbd_login_response_ext *resp_ext = NULL; struct ksmbd_user *user = NULL; resp = ksmbd_ipc_login_request(account); @@ -21,15 +22,19 @@ struct ksmbd_user *ksmbd_login_user(const char *account) if (!(resp->status & KSMBD_USER_FLAG_OK)) goto out; - user = ksmbd_alloc_user(resp); + if (resp->status & KSMBD_USER_FLAG_EXTENSION) + resp_ext = ksmbd_ipc_login_request_ext(account); + + user = ksmbd_alloc_user(resp, resp_ext); out: kvfree(resp); return user; } -struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) +struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, + struct ksmbd_login_response_ext *resp_ext) { - struct ksmbd_user *user = NULL; + struct ksmbd_user *user; user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL); if (!user) @@ -44,18 +49,36 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) if (user->passkey) memcpy(user->passkey, resp->hash, resp->hash_sz); - if (!user->name || !user->passkey) { - kfree(user->name); - kfree(user->passkey); - kfree(user); - user = NULL; + user->ngroups = 0; + user->sgid = NULL; + + if (!user->name || !user->passkey) + goto err_free; + + if (resp_ext) { + user->sgid = kmemdup(resp_ext->____payload, + resp_ext->ngroups * sizeof(gid_t), + GFP_KERNEL); + if (!user->sgid) + goto err_free; + + user->ngroups = resp_ext->ngroups; + ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups); } + return user; + +err_free: + kfree(user->name); + kfree(user->passkey); + kfree(user); + return NULL; } void ksmbd_free_user(struct ksmbd_user *user) { ksmbd_ipc_logout_request(user->name, user->flags); + kfree(user->sgid); kfree(user->name); kfree(user->passkey); kfree(user); diff --git a/fs/smb/server/mgmt/user_config.h b/fs/smb/server/mgmt/user_config.h index e068a19fd90493..8c227b8d495431 100644 --- a/fs/smb/server/mgmt/user_config.h +++ b/fs/smb/server/mgmt/user_config.h @@ -18,6 +18,8 @@ struct ksmbd_user { size_t passkey_sz; char *passkey; + int ngroups; + gid_t *sgid; }; static inline bool user_guest(struct ksmbd_user *user) @@ -60,7 +62,8 @@ static inline unsigned int user_gid(struct ksmbd_user *user) } struct ksmbd_user *ksmbd_login_user(const char *account); -struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp); +struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, + struct ksmbd_login_response_ext *resp_ext); void ksmbd_free_user(struct ksmbd_user *user); int ksmbd_anonymous_user(struct ksmbd_user *user); bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2); diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index e344475a41bd16..6c7fbd589087e1 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -168,6 +168,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) free_channel_list(sess); kfree(sess->Preauth_HashValue); ksmbd_release_id(&session_ida, sess->id); + ida_destroy(&sess->tree_conn_ida); kfree(sess); } @@ -322,8 +323,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, struct ksmbd_session *sess; sess = ksmbd_session_lookup(conn, id); - if (!sess && conn->binding) + if (!sess && conn->binding) { sess = ksmbd_session_lookup_slowpath(id); + if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { + ksmbd_user_session_put(sess); + sess = NULL; + } + } if (sess && sess->state != SMB2_SESSION_VALID) { ksmbd_user_session_put(sess); sess = NULL; @@ -438,6 +444,8 @@ static struct ksmbd_session *__session_create(int protocol) if (!sess) return NULL; + ida_init(&sess->tree_conn_ida); + if (ksmbd_init_file_table(&sess->file_table)) goto error; @@ -456,8 +464,6 @@ static struct ksmbd_session *__session_create(int protocol) if (ret) goto error; - ida_init(&sess->tree_conn_ida); - down_write(&sessions_table_lock); hash_add(sessions_table, &sess->hlist, sess->id); up_write(&sessions_table_lock); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 6c41a67be725d7..d68fe617369e04 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2827,6 +2827,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, dh_info->reconnected = true; goto out; } + ksmbd_put_durable_fd(dh_info->fp); + dh_info->fp = NULL; } if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c index 2839c704110cd1..c64d1fc34d6bf3 100644 --- a/fs/smb/server/smb_common.c +++ b/fs/smb/server/smb_common.c @@ -740,13 +740,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, struct ksmbd_share_config *share) { struct ksmbd_session *sess = work->sess; + struct ksmbd_user *user = sess->user; struct cred *cred; struct group_info *gi; unsigned int uid; unsigned int gid; + int i; - uid = user_uid(sess->user); - gid = user_gid(sess->user); + uid = user_uid(user); + gid = user_gid(user); if (share->force_uid != KSMBD_SHARE_INVALID_UID) uid = share->force_uid; if (share->force_gid != KSMBD_SHARE_INVALID_GID) @@ -759,11 +761,18 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, cred->fsuid = make_kuid(&init_user_ns, uid); cred->fsgid = make_kgid(&init_user_ns, gid); - gi = groups_alloc(0); + gi = groups_alloc(user->ngroups); if (!gi) { abort_creds(cred); return -ENOMEM; } + + for (i = 0; i < user->ngroups; i++) + gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]); + + if (user->ngroups) + groups_sort(gi); + set_groups(cred, gi); put_group_info(gi); diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index 0a3a26e63ebc04..ff59217b4bea8b 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -1025,7 +1025,26 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, ace->flags = flags; ace->access_req = access_req; smb_copy_sid(&ace->sid, sid); - ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4)); + ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + + (ace->sid.num_subauth * 4)); +} + +static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size, + u16 *ace_cnt, const struct smb_sid *sid, + u8 type, u8 flags, __le32 access_req) +{ + int ace_size; + + smb_set_ace(*ace, sid, type, flags, access_req); + ace_size = le16_to_cpu((*ace)->size); + /* pdacl->size is __le16 and includes struct smb_acl. */ + if (check_add_overflow(*nt_size, ace_size, nt_size) || + *nt_size > U16_MAX - (int)sizeof(struct smb_acl)) + return -EINVAL; + + (*ace_cnt)++; + *ace = (struct smb_ace *)((char *)*ace + ace_size); + return 0; } int smb_inherit_dacl(struct ksmbd_conn *conn, @@ -1090,6 +1109,12 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, if (pace_size > aces_size) break; + if (parent_aces->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || + pace_size < offsetof(struct smb_ace, sid) + + CIFS_SID_BASE_SIZE + + sizeof(__le32) * parent_aces->sid.num_subauth) + break; + aces_size -= pace_size; flags = parent_aces->flags; @@ -1119,22 +1144,24 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, } if (is_dir && creator && flags & CONTAINER_INHERIT_ACE) { - smb_set_ace(aces, psid, parent_aces->type, inherited_flags, - parent_aces->access_req); - nt_size += le16_to_cpu(aces->size); - ace_cnt++; - aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); + rc = smb_append_inherited_ace(&aces, &nt_size, &ace_cnt, + psid, parent_aces->type, + inherited_flags, + parent_aces->access_req); + if (rc) + goto free_aces_base; flags |= INHERIT_ONLY_ACE; psid = creator; } else if (is_dir && !(parent_aces->flags & NO_PROPAGATE_INHERIT_ACE)) { psid = &parent_aces->sid; } - smb_set_ace(aces, psid, parent_aces->type, flags | inherited_flags, - parent_aces->access_req); - nt_size += le16_to_cpu(aces->size); - aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); - ace_cnt++; + rc = smb_append_inherited_ace(&aces, &nt_size, &ace_cnt, psid, + parent_aces->type, + flags | inherited_flags, + parent_aces->access_req); + if (rc) + goto free_aces_base; pass: parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); } @@ -1144,7 +1171,7 @@ pass: struct smb_acl *pdacl; struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL; int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; - int pntsd_alloc_size; + size_t pntsd_alloc_size; if (parent_pntsd->osidoffset) { powner_sid = (struct smb_sid *)((char *)parent_pntsd + @@ -1157,8 +1184,19 @@ pass: pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4); } - pntsd_alloc_size = sizeof(struct smb_ntsd) + powner_sid_size + - pgroup_sid_size + sizeof(struct smb_acl) + nt_size; + if (check_add_overflow(sizeof(struct smb_ntsd), + (size_t)powner_sid_size, + &pntsd_alloc_size) || + check_add_overflow(pntsd_alloc_size, + (size_t)pgroup_sid_size, + &pntsd_alloc_size) || + check_add_overflow(pntsd_alloc_size, sizeof(struct smb_acl), + &pntsd_alloc_size) || + check_add_overflow(pntsd_alloc_size, (size_t)nt_size, + &pntsd_alloc_size)) { + rc = -EINVAL; + goto free_aces_base; + } pntsd = kzalloc(pntsd_alloc_size, GFP_KERNEL); if (!pntsd) { diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index 53bfcf57f167a1..554a6c92a1ccb4 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "vfs_cache.h" #include "transport_ipc.h" @@ -120,6 +121,12 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = { }, [KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = { }, + [KSMBD_EVENT_LOGIN_REQUEST_EXT] = { + .len = sizeof(struct ksmbd_login_request), + }, + [KSMBD_EVENT_LOGIN_RESPONSE_EXT] = { + .len = sizeof(struct ksmbd_login_response_ext), + }, }; static struct genl_ops ksmbd_genl_ops[] = { @@ -187,6 +194,14 @@ static struct genl_ops ksmbd_genl_ops[] = { .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE, .doit = handle_generic_event, }, + { + .cmd = KSMBD_EVENT_LOGIN_REQUEST_EXT, + .doit = handle_unsupported_event, + }, + { + .cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT, + .doit = handle_generic_event, + }, }; static struct genl_family ksmbd_genl_family = { @@ -198,7 +213,7 @@ static struct genl_family ksmbd_genl_family = { .module = THIS_MODULE, .ops = ksmbd_genl_ops, .n_ops = ARRAY_SIZE(ksmbd_genl_ops), - .resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1, + .resv_start_op = KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1, }; static void ksmbd_nl_init_fixup(void) @@ -478,26 +493,54 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) { unsigned int msg_sz = entry->msg_sz; - if (entry->type == KSMBD_EVENT_RPC_REQUEST) { + switch (entry->type) { + case KSMBD_EVENT_RPC_REQUEST: + { struct ksmbd_rpc_command *resp = entry->response; - msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; - } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) { + if (check_add_overflow(sizeof(struct ksmbd_rpc_command), + resp->payload_sz, &msg_sz)) + return -EINVAL; + break; + } + case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: + { struct ksmbd_spnego_authen_response *resp = entry->response; msg_sz = sizeof(struct ksmbd_spnego_authen_response) + resp->session_key_len + resp->spnego_blob_len; - } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) { + break; + } + case KSMBD_EVENT_SHARE_CONFIG_REQUEST: + { struct ksmbd_share_config_response *resp = entry->response; if (resp->payload_sz) { if (resp->payload_sz < resp->veto_list_sz) return -EINVAL; - msg_sz = sizeof(struct ksmbd_share_config_response) + - resp->payload_sz; + if (check_add_overflow(sizeof(struct ksmbd_share_config_response), + resp->payload_sz, &msg_sz)) + return -EINVAL; + } + break; + } + case KSMBD_EVENT_LOGIN_REQUEST_EXT: + { + struct ksmbd_login_response_ext *resp = entry->response; + + if (resp->ngroups) { + if (resp->ngroups < 0 || + resp->ngroups > NGROUPS_MAX) { + pr_err("ngroups(%d) from login response exceeds max groups(%d)\n", + resp->ngroups, NGROUPS_MAX); + return -EINVAL; + } + msg_sz = sizeof(struct ksmbd_login_response_ext) + + resp->ngroups * sizeof(gid_t); } } + } return entry->msg_sz != msg_sz ? -EINVAL : 0; } @@ -582,6 +625,29 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) return resp; } +struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account) +{ + struct ksmbd_ipc_msg *msg; + struct ksmbd_login_request *req; + struct ksmbd_login_response_ext *resp; + + if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) + return NULL; + + msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request)); + if (!msg) + return NULL; + + msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT; + req = (struct ksmbd_login_request *)msg->payload; + req->handle = ksmbd_acquire_id(&ipc_ida); + strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); + resp = ipc_msg_send_request(msg, req->handle); + ipc_msg_handle_free(req->handle); + ipc_msg_free(msg); + return resp; +} + struct ksmbd_spnego_authen_response * ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) { diff --git a/fs/smb/server/transport_ipc.h b/fs/smb/server/transport_ipc.h index 5e5b90a0c1879c..d9b6737f8cd03d 100644 --- a/fs/smb/server/transport_ipc.h +++ b/fs/smb/server/transport_ipc.h @@ -12,6 +12,8 @@ struct ksmbd_login_response * ksmbd_ipc_login_request(const char *account); +struct ksmbd_login_response_ext * +ksmbd_ipc_login_request_ext(const char *account); struct ksmbd_session; struct ksmbd_share_config; diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 3528ec33919d52..10ceade590529b 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1407,8 +1407,8 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, /* build rdma_rw_ctx for each descriptor */ desc_buf = buf; for (i = 0; i < desc_num; i++) { - msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + - sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); + msg = kzalloc(struct_size(msg, sg_list, SG_CHUNK_SIZE), + GFP_KERNEL); if (!msg) { ret = -ENOMEM; goto out; diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index f98315e91e99b4..36257e1092d6ea 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -802,7 +802,7 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode mutex_lock(&eventfs_mutex); if (!parent->is_freed) - list_add_tail(&ei->list, &parent->children); + list_add_tail_rcu(&ei->list, &parent->children); mutex_unlock(&eventfs_mutex); /* Was the parent freed? */ diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h index b9b51617a335d2..0705103060748c 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h +++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h @@ -6,6 +6,7 @@ #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H +/* Clocks */ #define DISP_CC_PLL0 0 #define DISP_CC_PLL0_OUT_EVEN 1 #define DISP_CC_MDSS_AHB_CLK 2 @@ -40,7 +41,11 @@ #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 #define DISP_CC_XO_CLK 32 -/* DISP_CC GDSCR */ +/* Resets */ +#define DISP_CC_MDSS_CORE_BCR 0 +#define DISP_CC_MDSS_RSCC_BCR 1 + +/* GDSCs */ #define MDSS_GDSC 0 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h index 2569f874fe13c6..be97a0ca2ade49 100644 --- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h +++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h @@ -308,5 +308,10 @@ #define USB30_MP_GDSC 8 #define USB30_PRIM_GDSC 9 #define USB30_SEC_GDSC 10 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 +#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 +#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 +#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 +#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 #endif diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index fdfb61ccf55aef..b4f2b237444138 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -109,6 +109,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, unsigned int clearing); +extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); extern void unregister_cdrom(struct cdrom_device_info *cdi); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 624d4a38c358a0..72070333026b90 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -98,7 +98,6 @@ enum cpuhp_state { CPUHP_IOMMU_IOVA_DEAD, CPUHP_LUSTRE_CFS_DEAD, CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, - CPUHP_PADATA_DEAD, CPUHP_AP_DTPM_CPU_DEAD, CPUHP_RANDOM_PREPARE, CPUHP_WORKQUEUE_PREP, diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h index ae80a303c216be..ca32b5bb28eb57 100644 --- a/include/linux/dev_printk.h +++ b/include/linux/dev_printk.h @@ -277,4 +277,12 @@ do { \ __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ +#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) + +/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ +#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ + ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) + #endif /* _DEVICE_PRINTK_H_ */ diff --git a/include/linux/dmi.h b/include/linux/dmi.h index 927f8a8b7a1ddd..2eedf44e680126 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -60,6 +60,7 @@ enum dmi_entry_type { DMI_ENTRY_OOB_REMOTE_ACCESS, DMI_ENTRY_BIS_ENTRY, DMI_ENTRY_SYSTEM_BOOT, + DMI_ENTRY_64_MEM_ERROR, DMI_ENTRY_MGMT_DEV, DMI_ENTRY_MGMT_DEV_COMPONENT, DMI_ENTRY_MGMT_DEV_THRES, @@ -69,6 +70,10 @@ enum dmi_entry_type { DMI_ENTRY_ADDITIONAL, DMI_ENTRY_ONBOARD_DEV_EXT, DMI_ENTRY_MGMT_CONTROLLER_HOST, + DMI_ENTRY_TPM_DEVICE, + DMI_ENTRY_PROCESSOR_ADDITIONAL, + DMI_ENTRY_FIRMWARE_INVENTORY, + DMI_ENTRY_STRING_PROPERTY, DMI_ENTRY_INACTIVE = 126, DMI_ENTRY_END_OF_TABLE = 127, }; diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 061e19c94a6bc6..f73ca4d62683b5 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -392,14 +392,9 @@ extern char *parse_args(const char *name, const char *doing, void *arg)); /* Called by module remove. */ -#ifdef CONFIG_SYSFS -extern void destroy_params(const struct kernel_param *params, unsigned num); -#else -static inline void destroy_params(const struct kernel_param *params, - unsigned num) -{ -} -#endif /* !CONFIG_SYSFS */ +#ifdef CONFIG_MODULES +void module_destroy_params(const struct kernel_param *params, unsigned int num); +#endif /* All the helper functions */ /* The macros to do compile-time type checking stolen from Jakub diff --git a/include/linux/padata.h b/include/linux/padata.h index 6f07e12a438196..72f5899cc7a950 100644 --- a/include/linux/padata.h +++ b/include/linux/padata.h @@ -147,23 +147,23 @@ struct padata_mt_job { /** * struct padata_instance - The overall control structure. * - * @cpu_online_node: Linkage for CPU online callback. - * @cpu_dead_node: Linkage for CPU offline callback. + * @cpuhp_node: Linkage for CPU hotplug callbacks. * @parallel_wq: The workqueue used for parallel work. * @serial_wq: The workqueue used for serial work. * @pslist: List of padata_shell objects attached to this instance. * @cpumask: User supplied cpumasks for parallel and serial works. + * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. * @kobj: padata instance kernel object. * @lock: padata instance lock. * @flags: padata flags. */ struct padata_instance { - struct hlist_node cpu_online_node; - struct hlist_node cpu_dead_node; + struct hlist_node cpuhp_node; struct workqueue_struct *parallel_wq; struct workqueue_struct *serial_wq; struct list_head pslist; struct padata_cpumask cpumask; + cpumask_var_t validate_cpumask; struct kobject kobj; struct mutex lock; u8 flags; diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h index b7e57fdbd4139a..b1d1f46d7d3be5 100644 --- a/include/linux/ppp_defs.h +++ b/include/linux/ppp_defs.h @@ -8,6 +8,7 @@ #define _PPP_DEFS_H_ #include +#include #include #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) @@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) return !!((proto & 0x0101) == 0x0001); } +/** + * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed + * @skb: skb to check + * + * Check if the PPP protocol field is compressed (the least significant + * bit of the most significant octet is 1). skb->data must point to the PPP + * protocol header. + * + * Return: Whether the PPP protocol field is compressed. + */ +static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) +{ + return unlikely(skb->data[0] & 0x01); +} + #endif /* _PPP_DEFS_H_ */ diff --git a/include/linux/printk.h b/include/linux/printk.h index 478203bb2369c0..794476418ccef4 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -759,7 +759,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, #endif /** - * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params + * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default + * params * @prefix_str: string to prefix each line with; * caller supplies trailing spaces for alignment if desired * @prefix_type: controls whether prefix of an offset, address, or none @@ -767,7 +768,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, * @buf: data blob to dump * @len: number of bytes in the @buf * - * Calls print_hex_dump(), with log level of KERN_DEBUG, + * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, * rowsize of 16, groupsize of 1, and ASCII output included. */ #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 4fa4ef0a173a36..a9be09f96b10e1 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); bool dquot_initialize_needed(struct inode *inode); void dquot_drop(struct inode *inode); struct dquot *dqget(struct super_block *sb, struct kqid qid); -static inline struct dquot *dqgrab(struct dquot *dquot) -{ - /* Make sure someone else has active reference to dquot */ - WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); - WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); - atomic_inc(&dquot->dq_count); - return dquot; -} +struct dquot *dqgrab(struct dquot *dquot); static inline bool dquot_is_busy(struct dquot *dquot) { diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h index c87204247592fd..a132fc562297a4 100644 --- a/include/linux/spinlock_up.h +++ b/include/linux/spinlock_up.h @@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) lock->slock = 1; } -/* - * Read-write spinlocks. No debug version. - */ -#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) -#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) -#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) - #else /* DEBUG_SPINLOCK */ #define arch_spin_is_locked(lock) ((void)(lock), 0) /* for sched/core.c and kernel_lock.c: */ @@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) #define arch_spin_is_contended(lock) (((void)(lock), 0)) +/* + * Read-write spinlocks. No debug version. + */ +#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) + #endif /* __LINUX_SPINLOCK_UP_H */ diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h index 078e16d2512a55..728aec9bda4a4d 100644 --- a/include/net/bond_3ad.h +++ b/include/net/bond_3ad.h @@ -239,7 +239,7 @@ typedef struct port { churn_state_t sm_churn_actor_state; churn_state_t sm_churn_partner_state; struct slave *slave; /* pointer to the bond slave that this port belongs to */ - struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ + struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ u32 transaction_id; /* continuous number for identification of Marker PDU's; */ struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ @@ -271,6 +271,7 @@ struct ad_slave_info { struct port port; /* 802.3ad port structure */ struct bond_3ad_stats stats; u16 id; + u16 port_priority; }; static inline const char *bond_3ad_churn_desc(churn_state_t state) diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 18687ccf063830..e6eedf23aea1a3 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -77,6 +77,8 @@ enum { BOND_OPT_NS_TARGETS, BOND_OPT_PRIO, BOND_OPT_COUPLED_CONTROL, + BOND_OPT_BROADCAST_NEIGH, + BOND_OPT_ACTOR_PORT_PRIO, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index 66940d41d48540..0d9c1eb40d12b6 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -115,6 +115,8 @@ static inline int is_netpoll_tx_blocked(struct net_device *dev) #define is_netpoll_tx_blocked(dev) (0) #endif +DECLARE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); + struct bond_params { int mode; int xmit_policy; @@ -149,6 +151,7 @@ struct bond_params { struct in6_addr ns_targets[BOND_MAX_NS_TARGETS]; #endif int coupled_control; + int broadcast_neighbor; /* 2 bytes of padding : see ether_addr_equal_64bits() */ u8 ad_actor_system[ETH_ALEN + 2]; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index d98f5390ffad38..3645776d71c9c7 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -1133,12 +1133,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, st struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst, bool connected); -struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, - struct net_device *dev, - struct net *net, struct socket *sock, - struct in6_addr *saddr, - const struct ip_tunnel_info *info, - u8 protocol, bool use_cache); struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *orig_dst); diff --git a/include/net/pie.h b/include/net/pie.h index 01cbc66825a40b..1f3db0c355149b 100644 --- a/include/net/pie.h +++ b/include/net/pie.h @@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) vars->dq_tstamp = DTIME_INVALID; vars->accu_prob = 0; vars->dq_count = DQCOUNT_INVALID; - vars->avg_dq_rate = 0; + WRITE_ONCE(vars->avg_dq_rate, 0); } static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) diff --git a/include/net/route.h b/include/net/route.h index 27c17aff0bbe14..22d8095a3a81e9 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -136,12 +136,6 @@ static inline struct rtable *__ip_route_output_key(struct net *net, struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, const struct sock *sk); -struct rtable *ip_route_output_tunnel(struct sk_buff *skb, - struct net_device *dev, - struct net *net, __be32 *saddr, - const struct ip_tunnel_info *info, - u8 protocol, bool use_cache); - struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig); diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 0e6eb40cd7778f..6818a59a1ebcb3 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -161,6 +161,21 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, void udp_tunnel_sock_release(struct socket *sock); +struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, int oif, + __be32 *saddr, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache); +struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, + struct socket *sock, + struct in6_addr *saddr, + const struct ip_tunnel_info *info, + u8 protocol, bool use_cache); + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, __be16 flags, __be64 tunnel_id, int md_size); diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h index b4bc2828fa09f0..ec8d0de1ad2256 100644 --- a/include/trace/events/timer.h +++ b/include/trace/events/timer.h @@ -198,12 +198,13 @@ TRACE_EVENT(hrtimer_init, * hrtimer_start - called when the hrtimer is started * @hrtimer: pointer to struct hrtimer * @mode: the hrtimers mode + * @was_armed: Was armed when hrtimer_start*() was invoked */ TRACE_EVENT(hrtimer_start, - TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), + TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), - TP_ARGS(hrtimer, mode), + TP_ARGS(hrtimer, mode, was_armed), TP_STRUCT__entry( __field( void *, hrtimer ) @@ -211,6 +212,7 @@ TRACE_EVENT(hrtimer_start, __field( s64, expires ) __field( s64, softexpires ) __field( enum hrtimer_mode, mode ) + __field( bool, was_armed ) ), TP_fast_assign( @@ -219,13 +221,14 @@ TRACE_EVENT(hrtimer_start, __entry->expires = hrtimer_get_expires(hrtimer); __entry->softexpires = hrtimer_get_softexpires(hrtimer); __entry->mode = mode; + __entry->was_armed = was_armed; ), TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " - "mode=%s", __entry->hrtimer, __entry->function, + "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, (unsigned long long) __entry->expires, (unsigned long long) __entry->softexpires, - decode_hrtimer_mode(__entry->mode)) + decode_hrtimer_mode(__entry->mode), __entry->was_armed) ); /** diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 08a0494736e6e3..6950169329ef1e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1344,6 +1344,8 @@ enum { #define BPF_F_TEST_RUN_ON_CPU (1U << 0) /* If set, XDP frames will be transmitted after processing */ #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) +/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ +#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) /* type for BPF_ENABLE_STATS */ enum bpf_stats_type { diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6750911da4f066..7c1fb141970246 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -979,6 +979,9 @@ enum { IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, IFLA_BOND_SLAVE_PRIO, + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, __IFLA_BOND_SLAVE_MAX, }; diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h index 39f7c44baf5350..61d6edad4b94af 100644 --- a/include/uapi/linux/mii.h +++ b/include/uapi/linux/mii.h @@ -82,7 +82,8 @@ #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ +#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c index c848a5018d1263..d8123dc5d742c0 100644 --- a/io_uring/io-wq.c +++ b/io_uring/io-wq.c @@ -1046,7 +1046,8 @@ static inline void io_wq_remove_pending(struct io_wq *wq, if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) { if (prev) prev_work = container_of(prev, struct io_wq_work, list); - if (prev_work && io_get_work_hash(prev_work) == hash) + if (prev_work && io_wq_is_hashed(prev_work) && + io_get_work_hash(prev_work) == hash) wq->hash_tail[hash] = prev_work; else wq->hash_tail[hash] = NULL; diff --git a/kernel/audit.c b/kernel/audit.c index 9c8e5f732c4c79..433672f81e30dd 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1427,6 +1427,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh, err = audit_list_rules_send(skb, seq); break; case AUDIT_TRIM: + if (audit_enabled == AUDIT_LOCKED) + return -EPERM; audit_trim_trees(); audit_log_common_recv_msg(audit_context(), &ab, AUDIT_CONFIG_CHANGE); @@ -1439,6 +1441,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh, size_t msglen = data_len; char *old, *new; + if (audit_enabled == AUDIT_LOCKED) + return -EPERM; err = -EINVAL; if (msglen < 2 * sizeof(u32)) break; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index d48830c7e4beb7..bb3cea8c71488f 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2845,7 +2845,7 @@ void __audit_log_capset(const struct cred *new, const struct cred *old) context->capset.pid = task_tgid_nr(current); context->capset.cap.effective = new->cap_effective; - context->capset.cap.inheritable = new->cap_effective; + context->capset.cap.inheritable = new->cap_inheritable; context->capset.cap.permitted = new->cap_permitted; context->capset.cap.ambient = new->cap_ambient; context->type = AUDIT_CAPSET; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 1811efcfbd6e3b..ec5c489ed31311 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -938,8 +938,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer) struct bpf_array *array = container_of(map, struct bpf_array, map); int i; - for (i = 0; i < array->map.max_entries; i++) + for (i = 0; i < array->map.max_entries; i++) { __fd_array_map_delete_elem(map, &i, need_defer); + cond_resched(); + } } static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c index e14c822f8911c9..92486a7b916e38 100644 --- a/kernel/bpf/bpf_lsm.c +++ b/kernel/bpf/bpf_lsm.c @@ -340,7 +340,6 @@ BTF_ID(func, bpf_lsm_current_getsecid_subj) BTF_ID(func, bpf_lsm_task_getsecid_obj) BTF_ID(func, bpf_lsm_task_prctl) BTF_ID(func, bpf_lsm_task_setscheduler) -BTF_ID(func, bpf_lsm_task_to_inode) BTF_ID(func, bpf_lsm_userns_create) BTF_SET_END(sleepable_lsm_hooks) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 3011add7c4a882..d708cf3e6207f9 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1422,6 +1422,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) * know whether fp here is the clone or the original. */ fp->aux->prog = fp; + if (fp->aux->offload) + fp->aux->offload->prog = fp; bpf_prog_clone_free(fp_other); } diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index 3bdec239be6108..c169f0624e1009 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c @@ -642,7 +642,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, for (i = 0; i < dtab->n_buckets; i++) { head = dev_map_index_hash(dtab, i); hlist_for_each_entry_rcu(dst, head, index_hlist, - lockdep_is_held(&dtab->index_lock)) { + rcu_read_lock_bh_held()) { if (!is_valid_dst(dst, xdpf)) continue; @@ -724,7 +724,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, struct bpf_dtab_netdev *dst, *last_dst = NULL; int excluded_devices[1+MAX_NEST_DEV]; struct hlist_head *head; - struct hlist_node *next; int num_excluded = 0; unsigned int i; int err; @@ -764,10 +763,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ for (i = 0; i < dtab->n_buckets; i++) { head = dev_map_index_hash(dtab, i); - hlist_for_each_entry_safe(dst, next, head, index_hlist) { - if (!dst) - continue; - + hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { if (is_ifindex_excluded(excluded_devices, num_excluded, dst->dev->ifindex)) continue; diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 8bac6ae1204dcb..934fdc688d7c14 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -991,7 +991,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, for_each_possible_cpu(cpu) { if (cpu == current_cpu) - copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value); + copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value); else /* Since elem is preallocated, we cannot touch special fields */ zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu)); } diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 2cfbc48b824259..885ff0710a8b98 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -849,7 +849,13 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, data->buf = buffers->buf; for (i = 0; i < fmt_size; i++) { - if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { + unsigned char c = fmt[i]; + + /* + * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass + * through unchanged, while still rejecting ASCII control bytes. + */ + if (isascii(c) && !isprint(c) && !isspace(c)) { err = -EINVAL; goto out; } @@ -871,6 +877,15 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, * always access fmt[i + 1], in the worst case it will be a 0 */ i++; + c = fmt[i]; + /* + * The format parser below only understands ASCII conversion + * specifiers and modifiers, so reject non-ASCII after '%'. + */ + if (!isascii(c)) { + err = -EINVAL; + goto out; + } /* skip optional "[0 +-][num]" width formatting field */ while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index a04f505aefe9b6..c8b8dcc37ed4a7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b7fd3995538bf6..0d90236d0ad94f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5336,6 +5336,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, int perm_flags; const char *reg_name = ""; + if (base_type(reg->type) != PTR_TO_BTF_ID) + goto bad_type; + if (btf_is_kernel(reg->btf)) { perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; @@ -5346,7 +5349,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, perm_flags = PTR_MAYBE_NULL | MEM_ALLOC; } - if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) + if (type_flag(reg->type) & ~perm_flags) goto bad_type; /* We need to verify reg->type and reg->btf, before accessing reg->btf */ diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c index ef5878fb200571..d544a747f3954d 100644 --- a/kernel/cgroup/rdma.c +++ b/kernel/cgroup/rdma.c @@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, ret = PTR_ERR(rpool); goto err; } else { - new = rpool->resources[index].usage + 1; + new = (s64)rpool->resources[index].usage + 1; if (new > rpool->resources[index].max) { ret = -EAGAIN; goto err; diff --git a/kernel/fork.c b/kernel/fork.c index c65a70581af736..e280f02b6446ab 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -3443,11 +3443,10 @@ int ksys_unshare(unsigned long unshare_flags) new_cred, new_fs); if (err) goto bad_unshare_cleanup_cred; - if (new_cred) { err = set_cred_ucounts(new_cred); if (err) - goto bad_unshare_cleanup_cred; + goto bad_unshare_cleanup_nsproxy; } if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { @@ -3463,8 +3462,10 @@ int ksys_unshare(unsigned long unshare_flags) shm_init_task(current); } - if (new_nsproxy) + if (new_nsproxy) { switch_task_namespaces(current, new_nsproxy); + new_nsproxy = NULL; + } task_lock(current); @@ -3493,13 +3494,15 @@ int ksys_unshare(unsigned long unshare_flags) perf_event_namespaces(current); +bad_unshare_cleanup_nsproxy: + if (new_nsproxy) + put_nsproxy(new_nsproxy); bad_unshare_cleanup_cred: if (new_cred) put_cred(new_cred); bad_unshare_cleanup_fd: if (new_fd) put_files_struct(new_fd); - bad_unshare_cleanup_fs: if (new_fs) free_fs_struct(new_fs); diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c index 7e43839ca7b05c..60b08247b07dd5 100644 --- a/kernel/futex/requeue.c +++ b/kernel/futex/requeue.c @@ -307,8 +307,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, return -EINVAL; /* Ensure that this does not race against an early wakeup */ - if (!futex_requeue_pi_prepare(top_waiter, NULL)) + if (!futex_requeue_pi_prepare(top_waiter, NULL)) { + plist_del(&top_waiter->list, &hb1->chain); + futex_hb_waiters_dec(hb1); return -EAGAIN; + } /* * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit @@ -707,10 +710,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, /* * We were woken prior to requeue by a timeout or a signal. - * Unqueue the futex_q and determine which it was. + * Conditionally unqueue the futex_q and determine which it was. */ - plist_del(&q->list, &hb->chain); - futex_hb_waiters_dec(hb); + if (!plist_node_empty(&q->list)) { + plist_del(&q->list, &hb->chain); + futex_hb_waiters_dec(hb); + } /* Handle spurious wakeups gracefully */ ret = -EWOULDBLOCK; diff --git a/kernel/module/main.c b/kernel/module/main.c index 76d90c20de6743..ac528fbb628245 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1261,7 +1261,7 @@ static void free_module(struct module *mod) module_unload_free(mod); /* Free any allocated parameters. */ - destroy_params(mod->kp, mod->num_kp); + module_destroy_params(mod->kp, mod->num_kp); if (is_livepatch_module(mod)) free_module_elf(mod); @@ -2998,7 +2998,7 @@ static int load_module(struct load_info *info, const char __user *uargs, mod_sysfs_teardown(mod); coming_cleanup: mod->state = MODULE_STATE_GOING; - destroy_params(mod->kp, mod->num_kp); + module_destroy_params(mod->kp, mod->num_kp); blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); klp_module_going(mod); diff --git a/kernel/padata.c b/kernel/padata.c index 44ea75bfd86810..9e4037a0fd334f 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -548,7 +548,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) } /* Allocate and initialize the internal cpumask dependend resources. */ -static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) +static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, + int offlining_cpu) { struct padata_instance *pinst = ps->pinst; struct parallel_data *pd; @@ -574,6 +575,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); + if (offlining_cpu >= 0) { + __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); + __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); + } padata_init_reorder_list(pd); padata_init_squeues(pd); @@ -620,11 +625,11 @@ static void __padata_stop(struct padata_instance *pinst) } /* Replace the internal control structure with a new one. */ -static int padata_replace_one(struct padata_shell *ps) +static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) { struct parallel_data *pd_new; - pd_new = padata_alloc_pd(ps); + pd_new = padata_alloc_pd(ps, offlining_cpu); if (!pd_new) return -ENOMEM; @@ -634,7 +639,7 @@ static int padata_replace_one(struct padata_shell *ps) return 0; } -static int padata_replace(struct padata_instance *pinst) +static int padata_replace(struct padata_instance *pinst, int offlining_cpu) { struct padata_shell *ps; int err = 0; @@ -642,7 +647,7 @@ static int padata_replace(struct padata_instance *pinst) pinst->flags |= PADATA_RESET; list_for_each_entry(ps, &pinst->pslist, list) { - err = padata_replace_one(ps); + err = padata_replace_one(ps, offlining_cpu); if (err) break; } @@ -659,9 +664,21 @@ static int padata_replace(struct padata_instance *pinst) /* If cpumask contains no active cpu, we mark the instance as invalid. */ static bool padata_validate_cpumask(struct padata_instance *pinst, - const struct cpumask *cpumask) + const struct cpumask *cpumask, + int offlining_cpu) { - if (!cpumask_intersects(cpumask, cpu_online_mask)) { + cpumask_copy(pinst->validate_cpumask, cpu_online_mask); + + /* + * @offlining_cpu is still in cpu_online_mask, so remove it here for + * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where + * @offlining_cpu wouldn't be in the online mask doesn't work because + * padata_cpu_offline() can fail but such a state doesn't allow failure. + */ + if (offlining_cpu >= 0) + __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); + + if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { pinst->flags |= PADATA_INVALID; return false; } @@ -677,13 +694,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, int valid; int err; - valid = padata_validate_cpumask(pinst, pcpumask); + valid = padata_validate_cpumask(pinst, pcpumask, -1); if (!valid) { __padata_stop(pinst); goto out_replace; } - valid = padata_validate_cpumask(pinst, cbcpumask); + valid = padata_validate_cpumask(pinst, cbcpumask, -1); if (!valid) __padata_stop(pinst); @@ -691,7 +708,7 @@ out_replace: cpumask_copy(pinst->cpumask.pcpu, pcpumask); cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); - err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); + err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); if (valid) __padata_start(pinst); @@ -743,36 +760,6 @@ EXPORT_SYMBOL(padata_set_cpumask); #ifdef CONFIG_HOTPLUG_CPU -static int __padata_add_cpu(struct padata_instance *pinst, int cpu) -{ - int err = 0; - - if (cpumask_test_cpu(cpu, cpu_online_mask)) { - err = padata_replace(pinst); - - if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && - padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) - __padata_start(pinst); - } - - return err; -} - -static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) -{ - int err = 0; - - if (!cpumask_test_cpu(cpu, cpu_online_mask)) { - if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || - !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) - __padata_stop(pinst); - - err = padata_replace(pinst); - } - - return err; -} - static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) { return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || @@ -784,27 +771,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) struct padata_instance *pinst; int ret; - pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); + pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); if (!pinst_has_cpu(pinst, cpu)) return 0; mutex_lock(&pinst->lock); - ret = __padata_add_cpu(pinst, cpu); + + ret = padata_replace(pinst, -1); + + if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && + padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) + __padata_start(pinst); + mutex_unlock(&pinst->lock); return ret; } -static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) +static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) { struct padata_instance *pinst; int ret; - pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); + pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); if (!pinst_has_cpu(pinst, cpu)) return 0; mutex_lock(&pinst->lock); - ret = __padata_remove_cpu(pinst, cpu); + + if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || + !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) + __padata_stop(pinst); + + ret = padata_replace(pinst, cpu); + mutex_unlock(&pinst->lock); return ret; } @@ -815,15 +814,14 @@ static enum cpuhp_state hp_online; static void __padata_free(struct padata_instance *pinst) { #ifdef CONFIG_HOTPLUG_CPU - cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, - &pinst->cpu_dead_node); - cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); + cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); #endif WARN_ON(!list_empty(&pinst->pslist)); free_cpumask_var(pinst->cpumask.pcpu); free_cpumask_var(pinst->cpumask.cbcpu); + free_cpumask_var(pinst->validate_cpumask); destroy_workqueue(pinst->serial_wq); destroy_workqueue(pinst->parallel_wq); kfree(pinst); @@ -983,10 +981,10 @@ struct padata_instance *padata_alloc(const char *name) if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) goto err_free_serial_wq; - if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { - free_cpumask_var(pinst->cpumask.pcpu); - goto err_free_serial_wq; - } + if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) + goto err_free_p_mask; + if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) + goto err_free_cb_mask; INIT_LIST_HEAD(&pinst->pslist); @@ -994,7 +992,7 @@ struct padata_instance *padata_alloc(const char *name) cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); if (padata_setup_cpumasks(pinst)) - goto err_free_masks; + goto err_free_v_mask; __padata_start(pinst); @@ -1003,18 +1001,19 @@ struct padata_instance *padata_alloc(const char *name) #ifdef CONFIG_HOTPLUG_CPU cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, - &pinst->cpu_online_node); - cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, - &pinst->cpu_dead_node); + &pinst->cpuhp_node); #endif cpus_read_unlock(); return pinst; -err_free_masks: - free_cpumask_var(pinst->cpumask.pcpu); +err_free_v_mask: + free_cpumask_var(pinst->validate_cpumask); +err_free_cb_mask: free_cpumask_var(pinst->cpumask.cbcpu); +err_free_p_mask: + free_cpumask_var(pinst->cpumask.pcpu); err_free_serial_wq: destroy_workqueue(pinst->serial_wq); err_put_cpus: @@ -1057,7 +1056,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) ps->pinst = pinst; cpus_read_lock(); - pd = padata_alloc_pd(ps); + pd = padata_alloc_pd(ps, -1); cpus_read_unlock(); if (!pd) @@ -1106,32 +1105,25 @@ void __init padata_init(void) int ret; ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", - padata_cpu_online, NULL); + padata_cpu_online, padata_cpu_offline); if (ret < 0) goto err; hp_online = ret; - - ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", - NULL, padata_cpu_dead); - if (ret < 0) - goto remove_online_state; #endif possible_cpus = num_possible_cpus(); padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work), GFP_KERNEL); if (!padata_works) - goto remove_dead_state; + goto remove_online_state; for (i = 0; i < possible_cpus; ++i) list_add(&padata_works[i].pw_list, &padata_free_works); return; -remove_dead_state: -#ifdef CONFIG_HOTPLUG_CPU - cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); remove_online_state: +#ifdef CONFIG_HOTPLUG_CPU cpuhp_remove_multi_state(hp_online); err: #endif diff --git a/kernel/params.c b/kernel/params.c index e39ac5420cd6dc..9d09ea99363fcc 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -593,12 +593,6 @@ static ssize_t param_attr_store(struct module_attribute *mattr, } #endif -#ifdef CONFIG_MODULES -#define __modinit -#else -#define __modinit __init -#endif - #ifdef CONFIG_SYSFS void kernel_param_lock(struct module *mod) { @@ -623,9 +617,9 @@ EXPORT_SYMBOL(kernel_param_unlock); * create file in sysfs. Returns an error on out of memory. Always cleans up * if there's an error. */ -static __modinit int add_sysfs_param(struct module_kobject *mk, - const struct kernel_param *kp, - const char *name) +static __init_or_module int add_sysfs_param(struct module_kobject *mk, + const struct kernel_param *kp, + const char *name) { struct module_param_attrs *new_mp; struct attribute **new_attrs; @@ -750,16 +744,8 @@ void module_param_sysfs_remove(struct module *mod) } #endif -void destroy_params(const struct kernel_param *params, unsigned num) -{ - unsigned int i; - - for (i = 0; i < num; i++) - if (params[i].ops->free) - params[i].ops->free(params[i].arg); -} - -struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) +struct module_kobject * __init_or_module +lookup_or_create_module_kobject(const char *name) { struct module_kobject *mk; struct kobject *kobj; @@ -992,3 +978,21 @@ static int __init param_sysfs_builtin_init(void) late_initcall(param_sysfs_builtin_init); #endif /* CONFIG_SYSFS */ + +#ifdef CONFIG_MODULES + +/* + * module_destroy_params - free all parameters for one module + * @params: module parameters (array) + * @num: number of module parameters + */ +void module_destroy_params(const struct kernel_param *params, unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) + if (params[i].ops->free) + params[i].ops->free(params[i].arg); +} + +#endif /* CONFIG_MODULES */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 03f488f93cddf6..d3071b81c06404 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -499,17 +499,10 @@ debug_init(struct hrtimer *timer, clockid_t clockid, trace_hrtimer_init(timer, clockid, mode); } -static inline void debug_activate(struct hrtimer *timer, - enum hrtimer_mode mode) +static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) { debug_hrtimer_activate(timer, mode); - trace_hrtimer_start(timer, mode); -} - -static inline void debug_deactivate(struct hrtimer *timer) -{ - debug_hrtimer_deactivate(timer); - trace_hrtimer_cancel(timer); + trace_hrtimer_start(timer, mode, was_armed); } static struct hrtimer_clock_base * @@ -1099,13 +1092,12 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); * The timer is inserted in expiry order. Insertion into the * red black tree is O(log(n)). Must hold the base lock. * - * Returns 1 when the new timer is the leftmost timer in the tree. + * Returns true when the new timer is the leftmost timer in the tree. */ -static int enqueue_hrtimer(struct hrtimer *timer, - struct hrtimer_clock_base *base, - enum hrtimer_mode mode) +static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + enum hrtimer_mode mode, bool was_armed) { - debug_activate(timer, mode); + debug_activate(timer, mode, was_armed); WARN_ON_ONCE(!base->cpu_base->online); base->cpu_base->active_bases |= 1 << base->index; @@ -1165,6 +1157,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, if (state & HRTIMER_STATE_ENQUEUED) { bool reprogram; + debug_hrtimer_deactivate(timer); + /* * Remove the timer and force reprogramming when high * resolution mode is active and the timer is on the current @@ -1173,7 +1167,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, * reprogramming happens in the interrupt handler. This is a * rare case and less expensive than a smp call. */ - debug_deactivate(timer); reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); /* @@ -1240,15 +1233,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, { struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_clock_base *new_base; - bool force_local, first; + bool force_local, first, was_armed; /* * If the timer is on the local cpu base and is the first expiring * timer then this might end up reprogramming the hardware twice - * (on removal and on enqueue). To avoid that by prevent the - * reprogram on removal, keep the timer local to the current CPU - * and enforce reprogramming after it is queued no matter whether - * it is the new first expiring timer again or not. + * (on removal and on enqueue). To avoid that prevent the reprogram + * on removal, keep the timer local to the current CPU and enforce + * reprogramming after it is queued no matter whether it is the new + * first expiring timer again or not. */ force_local = base->cpu_base == this_cpu_base; force_local &= base->cpu_base->next_timer == timer; @@ -1270,7 +1263,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, * avoids programming the underlying clock event twice (once at * removal and once after enqueue). */ - remove_hrtimer(timer, base, true, force_local); + was_armed = remove_hrtimer(timer, base, true, force_local); if (mode & HRTIMER_MODE_REL) tim = ktime_add_safe(tim, base->get_time()); @@ -1287,7 +1280,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, new_base = base; } - first = enqueue_hrtimer(timer, new_base, mode); + first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the + * clock bases and reprogram the clock event device. + */ + if (new_base->cpu_base->in_hrtirq) + return false; + if (!force_local) { /* * If the current CPU base is online, then the timer is @@ -1383,8 +1384,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) base = lock_hrtimer_base(timer, &flags); - if (!hrtimer_callback_running(timer)) + if (!hrtimer_callback_running(timer)) { ret = remove_hrtimer(timer, base, false, false); + if (ret) + trace_hrtimer_cancel(timer); + } unlock_hrtimer_base(timer, &flags); @@ -1764,7 +1768,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, */ if (restart != HRTIMER_NORESTART && !(timer->state & HRTIMER_STATE_ENQUEUED)) - enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); + enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); /* * Separate the ->running assignment from the ->state assignment. @@ -2246,7 +2250,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, while ((node = timerqueue_getnext(&old_base->active))) { timer = container_of(node, struct hrtimer, node); BUG_ON(hrtimer_callback_running(timer)); - debug_deactivate(timer); + debug_hrtimer_deactivate(timer); /* * Mark it as ENQUEUED not INACTIVE otherwise the @@ -2263,7 +2267,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, * sort out already expired timers and reprogram the * event device. */ - enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); + enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); } } diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c index e47fdb4c92fbcb..30f72e0ecb5d4a 100644 --- a/kernel/trace/trace_branch.c +++ b/kernel/trace/trace_branch.c @@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) int ret; ret = register_stat_tracer(&annotated_branch_stats); - if (!ret) { + if (ret) { printk(KERN_WARNING "Warning: could not register " "annotated branches stats\n"); - return 1; + return ret; } return 0; } @@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) int ret; ret = register_stat_tracer(&all_branch_stats); - if (!ret) { + if (ret) { printk(KERN_WARNING "Warning: could not register " "all branches stats\n"); - return 1; + return ret; } return 0; } diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 19b3d388fbc69e..597f47397c7260 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -1349,12 +1349,14 @@ static const char *hist_field_name(struct hist_field *field, field->flags & HIST_FIELD_FL_VAR_REF) { if (field->system) { static char full_name[MAX_FILTER_STR_VAL]; + int len; + + len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", + field->system, field->event_name, + field->name); + if (len >= sizeof(full_name)) + return NULL; - strcat(full_name, field->system); - strcat(full_name, "."); - strcat(full_name, field->event_name); - strcat(full_name, "."); - strcat(full_name, field->name); field_name = full_name; } else field_name = field->name; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 641914d86154d7..8692e75aa6d808 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4683,7 +4683,9 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) if (ret) kthread_flush_worker(pwq_release_worker); - return ret; + if (ret) + goto enomem; + return 0; enomem: if (wq->cpu_pwq) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f6285c4325d634..4607db3037bd91 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3282,8 +3282,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, memcpy(conn->dev_class, ev->dev_class, 3); - hci_dev_unlock(hdev); - if (ev->link_type == ACL_LINK || (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { struct hci_cp_accept_conn_req cp; @@ -3317,7 +3315,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, hci_connect_cfm(conn, 0); } - return; unlock: hci_dev_unlock(hdev); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3da3e9fddd0498..bbaf0070ca6176 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5400,7 +5400,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, if (chan->ident != cmd->ident) continue; + l2cap_chan_hold(chan); + l2cap_chan_lock(chan); + l2cap_chan_del(chan, ECONNRESET); + + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } return 0; @@ -6658,7 +6664,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) if (sdu_len > chan->imtu) { BT_ERR("Too big LE L2CAP SDU length: len %u > %u", - skb->len, sdu_len); + sdu_len, chan->imtu); l2cap_send_disconn_req(chan, ECONNRESET); err = -EMSGSIZE; goto failed; diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 3a1c82b797a30d..8e665cee22503b 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -966,7 +966,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, void *data; int ret; - if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) + if ((kattr->test.flags & ~BPF_F_TEST_SKB_CHECKSUM_COMPLETE) || + kattr->test.cpu || kattr->test.batch_size) return -EINVAL; if (size < ETH_HLEN) @@ -1017,6 +1018,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); __skb_put(skb, size); + if (ctx && ctx->ifindex > 1) { dev = dev_get_by_index(net, ctx->ifindex); if (!dev) { @@ -1029,19 +1031,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, switch (skb->protocol) { case htons(ETH_P_IP): - sk->sk_family = AF_INET; - if (sizeof(struct iphdr) <= skb_headlen(skb)) { - sk->sk_rcv_saddr = ip_hdr(skb)->saddr; - sk->sk_daddr = ip_hdr(skb)->daddr; + if (skb_headlen(skb) < sizeof(struct iphdr)) { + ret = -EINVAL; + goto out; } + sk->sk_family = AF_INET; + sk->sk_rcv_saddr = ip_hdr(skb)->saddr; + sk->sk_daddr = ip_hdr(skb)->daddr; break; #if IS_ENABLED(CONFIG_IPV6) case htons(ETH_P_IPV6): - sk->sk_family = AF_INET6; - if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { - sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; - sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { + ret = -EINVAL; + goto out; } + sk->sk_family = AF_INET6; + sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; + sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; break; #endif default: @@ -1052,9 +1058,34 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, __skb_push(skb, hh_len); if (is_direct_pkt_access) bpf_compute_data_pointers(skb); + ret = convert___skb_to_skb(skb, ctx); if (ret) goto out; + + if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { + const int off = skb_network_offset(skb); + int len = skb->len - off; + + skb->csum = skb_checksum(skb, off, len, 0); + skb->ip_summed = CHECKSUM_COMPLETE; + } + + if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { + if (!ipv6_bpf_stub) { + pr_warn_once("Please test this program with the IPv6 module loaded\n"); + ret = -EOPNOTSUPP; + goto out; + } +#if IS_ENABLED(CONFIG_IPV6) + /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is + * handled by the above if statement. + */ + dst_hold(&net->ipv6.ip6_null_entry->dst); + skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); +#endif + } + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); if (ret) goto out; @@ -1069,6 +1100,20 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, } memset(__skb_push(skb, hh_len), 0, hh_len); } + + if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { + const int off = skb_network_offset(skb); + int len = skb->len - off; + __wsum csum; + + csum = skb_checksum(skb, off, len, 0); + + if (csum_fold(skb->csum) != csum_fold(csum)) { + ret = -EBADMSG; + goto out; + } + } + convert_skb_to___skb(skb, ctx); size = skb->len; diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 254ded0b05f6a1..521aec1d5fc060 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -47,7 +47,6 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b) { kfree(b->h.items); - kfree(b); } void crush_destroy_bucket_list(struct crush_bucket_list *b) @@ -55,14 +54,12 @@ void crush_destroy_bucket_list(struct crush_bucket_list *b) kfree(b->item_weights); kfree(b->sum_weights); kfree(b->h.items); - kfree(b); } void crush_destroy_bucket_tree(struct crush_bucket_tree *b) { kfree(b->h.items); kfree(b->node_weights); - kfree(b); } void crush_destroy_bucket_straw(struct crush_bucket_straw *b) @@ -70,14 +67,12 @@ void crush_destroy_bucket_straw(struct crush_bucket_straw *b) kfree(b->straws); kfree(b->item_weights); kfree(b->h.items); - kfree(b); } void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b) { kfree(b->item_weights); kfree(b->h.items); - kfree(b); } void crush_destroy_bucket(struct crush_bucket *b) @@ -99,6 +94,7 @@ void crush_destroy_bucket(struct crush_bucket *b) crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b); break; } + kfree(b); } /** diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 7c76eb9d6ceec5..c34a5bf86831b3 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -390,11 +390,15 @@ static int decode_choose_args(void **p, void *end, struct crush_map *c) goto fail; if (arg->ids_size && - arg->ids_size != c->buckets[bucket_index]->size) + (!c->buckets[bucket_index] || + arg->ids_size != c->buckets[bucket_index]->size)) goto e_inval; } - insert_choose_arg_map(&c->choose_args, arg_map); + if (!__insert_choose_arg_map(&c->choose_args, arg_map)) { + ret = -EEXIST; + goto fail; + } } return 0; @@ -517,6 +521,10 @@ static struct crush_map *crush_decode(void *pbyval, void *end) b->id = ceph_decode_32(p); b->type = ceph_decode_16(p); b->alg = ceph_decode_8(p); + if (b->alg != alg) { + b->alg = 0; + goto bad; + } b->hash = ceph_decode_8(p); b->weight = ceph_decode_32(p); b->size = ceph_decode_32(p); @@ -1703,7 +1711,7 @@ static int osdmap_decode(void **p, void *end, bool msgr2, ceph_decode_need(p, end, 3*sizeof(u32) + map->max_osd*(struct_v >= 5 ? sizeof(u32) : sizeof(u8)) + - sizeof(*map->osd_weight), e_inval); + map->max_osd*sizeof(*map->osd_weight), e_inval); if (ceph_decode_32(p) != map->max_osd) goto e_inval; diff --git a/net/core/filter.c b/net/core/filter.c index 2cd58d1d4a7aa7..371f4e789998d5 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -492,7 +492,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) ((unaligned_ok && offset >= 0) || (!unaligned_ok && offset >= 0 && offset + ip_align >= 0 && - offset + ip_align % size == 0))) { + (offset + ip_align) % size == 0))) { bool ldx_off_ok = offset <= S16_MAX; *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); @@ -4354,6 +4354,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); + if (unlikely(!(master->flags & IFF_UP))) + return XDP_ABORTED; slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); if (slave && slave != xdp->rxq->dev) { /* The target device is different from the receiving device, so diff --git a/net/core/gro.c b/net/core/gro.c index 92cb86d4ce50ac..0a9d4a3bb104d0 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -216,10 +216,12 @@ done: p->data_len += len; p->truesize += delta_truesize; p->len += len; + skb_shinfo(p)->flags |= skbinfo->flags & SKBFL_SHARED_FRAG; if (lp != p) { lp->data_len += len; lp->truesize += delta_truesize; lp->len += len; + skb_shinfo(lp)->flags |= skbinfo->flags & SKBFL_SHARED_FRAG; } NAPI_GRO_CB(skb)->same_flow = 1; return 0; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e6b36df482bc7f..bc9690a3d60e98 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1774,7 +1774,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms) static struct lock_class_key neigh_table_proxy_queue_class; -static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly; +static struct neigh_table __rcu *neigh_tables[NEIGH_NR_TABLES] __read_mostly; void neigh_table_init(int index, struct neigh_table *tbl) { @@ -1831,13 +1831,19 @@ void neigh_table_init(int index, struct neigh_table *tbl) tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time * 20; - neigh_tables[index] = tbl; + rcu_assign_pointer(neigh_tables[index], tbl); } EXPORT_SYMBOL(neigh_table_init); +/* + * Only called from ndisc_cleanup(), which means this is dead code + * because we no longer can unload IPv6 module. + */ int neigh_table_clear(int index, struct neigh_table *tbl) { - neigh_tables[index] = NULL; + RCU_INIT_POINTER(neigh_tables[index], NULL); + synchronize_rcu(); + /* It is not clean... Fix it to unload IPv6 module safely */ cancel_delayed_work_sync(&tbl->managed_work); cancel_delayed_work_sync(&tbl->gc_work); @@ -1869,10 +1875,10 @@ static struct neigh_table *neigh_find_table(int family) switch (family) { case AF_INET: - tbl = neigh_tables[NEIGH_ARP_TABLE]; + tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]); break; case AF_INET6: - tbl = neigh_tables[NEIGH_ND_TABLE]; + tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]); break; } @@ -2338,7 +2344,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, ndtmsg = nlmsg_data(nlh); for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { - tbl = neigh_tables[tidx]; + tbl = rcu_dereference_rtnl(neigh_tables[tidx]); if (!tbl) continue; if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) @@ -2526,7 +2532,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { struct neigh_parms *p; - tbl = neigh_tables[tidx]; + tbl = rcu_dereference_rtnl(neigh_tables[tidx]); if (!tbl) continue; @@ -2887,7 +2893,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0]; for (t = 0; t < NEIGH_NR_TABLES; t++) { - tbl = neigh_tables[t]; + tbl = rcu_dereference_rtnl(neigh_tables[t]); if (!tbl) continue; @@ -3151,14 +3157,17 @@ int neigh_xmit(int index, struct net_device *dev, const void *addr, struct sk_buff *skb) { int err = -EAFNOSUPPORT; + if (likely(index < NEIGH_NR_TABLES)) { struct neigh_table *tbl; struct neighbour *neigh; - tbl = neigh_tables[index]; - if (!tbl) - goto out; rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); + if (!tbl) { + rcu_read_unlock(); + goto out_kfree_skb; + } if (index == NEIGH_ARP_TABLE) { u32 key = *((u32 *)addr); @@ -3183,11 +3192,10 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; err = dev_queue_xmit(skb); } -out: return err; out_kfree_skb: kfree_skb(skb); - goto out; + return err; } EXPORT_SYMBOL(neigh_xmit); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c81ef99d39b047..8b05866e93b195 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2050,6 +2050,7 @@ struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom, skb_frag_ref(skb, i); } skb_shinfo(n)->nr_frags = i; + skb_shinfo(n)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; } if (skb_has_frag_list(skb)) { @@ -4086,6 +4087,8 @@ onlymerged: tgt->ip_summed = CHECKSUM_PARTIAL; skb->ip_summed = CHECKSUM_PARTIAL; + skb_shinfo(tgt)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + skb_len_add(skb, -shiftlen); skb_len_add(tgt, shiftlen); @@ -4658,7 +4661,8 @@ normal: skb_copy_from_linear_data_offset(head_skb, offset, skb_put(nskb, hsize), hsize); - skb_shinfo(nskb)->flags |= skb_shinfo(head_skb)->flags & + skb_shinfo(nskb)->flags |= (skb_shinfo(head_skb)->flags | + skb_shinfo(frag_skb)->flags) & SKBFL_SHARED_FRAG; if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) @@ -4675,6 +4679,9 @@ normal: nfrags = skb_shinfo(list_skb)->nr_frags; frag = skb_shinfo(list_skb)->frags; frag_skb = list_skb; + + skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & SKBFL_SHARED_FRAG; + if (!skb_headlen(list_skb)) { BUG_ON(!nfrags); } else { @@ -5824,6 +5831,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, from_shinfo->frags, from_shinfo->nr_frags * sizeof(skb_frag_t)); to_shinfo->nr_frags += from_shinfo->nr_frags; + if (from_shinfo->nr_frags) + to_shinfo->flags |= from_shinfo->flags & SKBFL_SHARED_FRAG; if (!skb_cloned(from)) from_shinfo->nr_frags = 0; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 14365b20f1c5c0..564054123772a1 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, arpptr += dev->addr_len; memcpy(&src_ipaddr, arpptr, sizeof(u32)); arpptr += sizeof(u32); - tgt_devaddr = arpptr; - arpptr += dev->addr_len; + + if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { + if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, + sizeof(arpinfo->tgt_devaddr.mask)))) + return 0; + + tgt_devaddr = NULL; + } else { + tgt_devaddr = arpptr; + arpptr += dev->addr_len; + } memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, - dev->addr_len)) || + dev->addr_len))) + return 0; + + if (tgt_devaddr && NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len))) diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index a4e07e5e9c118d..f65dd339208e8a 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += pln; if (mangle->flags & ARPT_MANGLE_TDEV) { + if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && + skb->dev->type == ARPHRD_IEEE1394)) + return NF_DROP; + if (ARPT_DEV_ADDR_LEN_MAX < hln || (arpptr + hln > skb_tail_pointer(skb))) return NF_DROP; @@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += hln; if (mangle->flags & ARPT_MANGLE_TIP) { + if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && + skb->dev->type == ARPHRD_IEEE1394)) + return NF_DROP; + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || (arpptr + pln > skb_tail_pointer(skb))) return NF_DROP; diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 99385fe34a1e57..4f30ddd2016b68 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -2183,10 +2183,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, goto err_notify; } - /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially + /* When replacing a nexthop with one of a different family, potentially * update IPv4 indication in all the groups using the nexthop. */ - if (oldi->family == AF_INET && newi->family == AF_INET6) { + if (oldi->family != newi->family) { list_for_each_entry(nhge, &old->grp_list, nh_list) { struct nexthop *nhp = nhge->nh_parent; struct nh_group *nhg; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 55ea367f95b3bd..f134c59f839e24 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2918,54 +2918,6 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, } EXPORT_SYMBOL_GPL(ip_route_output_flow); -struct rtable *ip_route_output_tunnel(struct sk_buff *skb, - struct net_device *dev, - struct net *net, __be32 *saddr, - const struct ip_tunnel_info *info, - u8 protocol, bool use_cache) -{ -#ifdef CONFIG_DST_CACHE - struct dst_cache *dst_cache; -#endif - struct rtable *rt = NULL; - struct flowi4 fl4; - __u8 tos; - -#ifdef CONFIG_DST_CACHE - dst_cache = (struct dst_cache *)&info->dst_cache; - if (use_cache) { - rt = dst_cache_get_ip4(dst_cache, saddr); - if (rt) - return rt; - } -#endif - memset(&fl4, 0, sizeof(fl4)); - fl4.flowi4_mark = skb->mark; - fl4.flowi4_proto = protocol; - fl4.daddr = info->key.u.ipv4.dst; - fl4.saddr = info->key.u.ipv4.src; - tos = info->key.tos; - fl4.flowi4_tos = RT_TOS(tos); - - rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) { - netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); - return ERR_PTR(-ENETUNREACH); - } - if (rt->dst.dev == dev) { /* is this necessary? */ - netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); - ip_rt_put(rt); - return ERR_PTR(-ELOOP); - } -#ifdef CONFIG_DST_CACHE - if (use_cache) - dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); -#endif - *saddr = fl4.saddr; - return rt; -} -EXPORT_SYMBOL_GPL(ip_route_output_tunnel); - /* called with rcu_read_lock held */ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, struct rtable *rt, u32 table_id, dscp_t dscp, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 33b724dcde6ed3..5b1fbb0ca2ff6e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3962,9 +3962,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, info.tcpi_sndbuf_limited, TCP_NLA_PAD); nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, - tp->data_segs_out, TCP_NLA_PAD); + READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, - tp->total_retrans, TCP_NLA_PAD); + READ_ONCE(tp->total_retrans), TCP_NLA_PAD); rate = READ_ONCE(sk->sk_pacing_rate); rate64 = (rate != ~0UL) ? rate : ~0ULL; @@ -3986,23 +3986,25 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); - nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), TCP_NLA_PAD); - nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, - TCP_NLA_PAD); - nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, - max_t(int, 0, tp->write_seq - tp->snd_nxt)); + max_t(int, 0, + READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, TCP_NLA_PAD); if (ack_skb) nla_put_u8(stats, TCP_NLA_TTL, tcp_skb_ttl_or_hop_limit(ack_skb)); - nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_REHASH, + READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash)); return stats; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 359d36be048294..eb1bf586347413 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1041,7 +1041,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) state->flag |= FLAG_DSACK_TLP; - tp->dsack_dups += dup_segs; + WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); /* Skip the DSACK if dup segs weren't retransmitted by sender */ if (tp->dsack_dups > tp->total_retrans) return 0; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index db8f2830c67bf2..429b94a86b5bbd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1400,8 +1400,10 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, if (skb->len != tcp_header_size) { tcp_event_data_sent(tp, sk); - tp->data_segs_out += tcp_skb_pcount(skb); - tp->bytes_sent += skb->len - tcp_header_size; + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); + WRITE_ONCE(tp->bytes_sent, + tp->bytes_sent + skb->len - tcp_header_size); } if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) @@ -2364,6 +2366,7 @@ static int tcp_clone_payload(struct sock *sk, struct sk_buff *to, todo = min_t(int, skb_frag_size(fragfrom), probe_size - len); len += todo; + skb_shinfo(to)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; if (lastfrag && skb_frag_page(fragfrom) == skb_frag_page(lastfrag) && skb_frag_off(fragfrom) == skb_frag_off(lastfrag) + @@ -3347,8 +3350,8 @@ start: TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); - tp->total_retrans += segs; - tp->bytes_retrans += skb->len; + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); /* make sure skb->data is aligned on arches that require it * and check if ack-trimming & collapsing extended the headroom @@ -4285,7 +4288,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) * However in this case, we are dealing with a passive fastopen * socket thus we can change total_retrans value. */ - tcp_sk_rw(sk)->total_retrans++; + WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, + tcp_sk_rw(sk)->total_retrans + 1); } trace_tcp_retransmit_synack(sk, req); } diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c index 4bcf7eff95e390..b7f9b60d8991f2 100644 --- a/net/ipv4/tcp_plb.c +++ b/net/ipv4/tcp_plb.c @@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb) sk_rethink_txhash(sk); plb->consec_cong_rounds = 0; - tcp_sk(sk)->plb_rehash++; + WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH); } EXPORT_SYMBOL_GPL(tcp_plb_check_rehash); diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index cd860d8d497b4f..84ae2759ff1956 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -547,6 +547,8 @@ static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) p->truesize += skb->truesize; p->len += skb->len; + skb_shinfo(p)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + NAPI_GRO_CB(skb)->same_flow = 1; return 0; diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index 1e7e4aecdc48a2..494685e828563d 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -204,4 +204,52 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, } EXPORT_SYMBOL_GPL(udp_tun_rx_dst); +struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, int oif, + __be32 *saddr, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache) +{ + struct rtable *rt = NULL; + struct flowi4 fl4; + +#ifdef CONFIG_DST_CACHE + if (dst_cache) { + rt = dst_cache_get_ip4(dst_cache, saddr); + if (rt) + return rt; + } +#endif + + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; + fl4.flowi4_oif = oif; + fl4.daddr = key->u.ipv4.dst; + fl4.saddr = key->u.ipv4.src; + fl4.fl4_dport = dport; + fl4.fl4_sport = sport; + fl4.flowi4_tos = RT_TOS(tos); + + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) { + netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); + return ERR_PTR(-ENETUNREACH); + } + if (rt->dst.dev == dev) { /* is this necessary? */ + netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); + ip_rt_put(rt); + return ERR_PTR(-ELOOP); + } +#ifdef CONFIG_DST_CACHE + if (dst_cache) + dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); +#endif + *saddr = fl4.saddr; + return rt; +} +EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); + MODULE_LICENSE("GPL"); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 0002fe04e04097..9c56612c66211c 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -907,7 +907,6 @@ static int icmpv6_rcv(struct sk_buff *skb) struct net *net = dev_net_rcu(skb->dev); struct net_device *dev = icmp6_dev(skb); struct inet6_dev *idev = __in6_dev_get(dev); - const struct in6_addr *saddr, *daddr; struct icmp6hdr *hdr; u8 type; @@ -938,12 +937,10 @@ static int icmpv6_rcv(struct sk_buff *skb) __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", - saddr, daddr); + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr); goto csum_error; } @@ -1026,7 +1023,8 @@ static int icmpv6_rcv(struct sk_buff *skb) break; net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", - saddr, daddr); + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr); /* * error of unknown type. diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a824c707dffff4..710aadbb2e2673 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1307,74 +1307,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, } EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); -/** - * ip6_dst_lookup_tunnel - perform route lookup on tunnel - * @skb: Packet for which lookup is done - * @dev: Tunnel device - * @net: Network namespace of tunnel device - * @sock: Socket which provides route info - * @saddr: Memory to store the src ip address - * @info: Tunnel information - * @protocol: IP protocol - * @use_cache: Flag to enable cache usage - * This function performs a route lookup on a tunnel - * - * It returns a valid dst pointer and stores src address to be used in - * tunnel in param saddr on success, else a pointer encoded error code. - */ - -struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, - struct net_device *dev, - struct net *net, - struct socket *sock, - struct in6_addr *saddr, - const struct ip_tunnel_info *info, - u8 protocol, - bool use_cache) -{ - struct dst_entry *dst = NULL; -#ifdef CONFIG_DST_CACHE - struct dst_cache *dst_cache; -#endif - struct flowi6 fl6; - __u8 prio; - -#ifdef CONFIG_DST_CACHE - dst_cache = (struct dst_cache *)&info->dst_cache; - if (use_cache) { - dst = dst_cache_get_ip6(dst_cache, saddr); - if (dst) - return dst; - } -#endif - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_mark = skb->mark; - fl6.flowi6_proto = protocol; - fl6.daddr = info->key.u.ipv6.dst; - fl6.saddr = info->key.u.ipv6.src; - prio = info->key.tos; - fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); - - dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, - NULL); - if (IS_ERR(dst)) { - netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); - return ERR_PTR(-ENETUNREACH); - } - if (dst->dev == dev) { /* is this necessary? */ - netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); - dst_release(dst); - return ERR_PTR(-ELOOP); - } -#ifdef CONFIG_DST_CACHE - if (use_cache) - dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); -#endif - *saddr = fl6.saddr; - return dst; -} -EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); - static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, gfp_t gfp) { diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index cdc4d4ee242066..7aef559e60ec53 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -1,3 +1,4 @@ + // SPDX-License-Identifier: GPL-2.0-only #include #include @@ -111,4 +112,72 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, } EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); +/** + * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel + * @skb: Packet for which lookup is done + * @dev: Tunnel device + * @net: Network namespace of tunnel device + * @sock: Socket which provides route info + * @saddr: Memory to store the src ip address + * @info: Tunnel information + * @protocol: IP protocol + * @use_cache: Flag to enable cache usage + * This function performs a route lookup on a UDP tunnel + * + * It returns a valid dst pointer and stores src address to be used in + * tunnel in param saddr on success, else a pointer encoded error code. + */ + +struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, + struct socket *sock, + struct in6_addr *saddr, + const struct ip_tunnel_info *info, + u8 protocol, + bool use_cache) +{ + struct dst_entry *dst = NULL; +#ifdef CONFIG_DST_CACHE + struct dst_cache *dst_cache; +#endif + struct flowi6 fl6; + __u8 prio; + +#ifdef CONFIG_DST_CACHE + dst_cache = (struct dst_cache *)&info->dst_cache; + if (use_cache) { + dst = dst_cache_get_ip6(dst_cache, saddr); + if (dst) + return dst; + } +#endif + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_mark = skb->mark; + fl6.flowi6_proto = protocol; + fl6.daddr = info->key.u.ipv6.dst; + fl6.saddr = info->key.u.ipv6.src; + prio = info->key.tos; + fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); + + dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, + NULL); + if (IS_ERR(dst)) { + netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); + return ERR_PTR(-ENETUNREACH); + } + if (dst->dev == dev) { /* is this necessary? */ + netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); + dst_release(dst); + return ERR_PTR(-ELOOP); + } +#ifdef CONFIG_DST_CACHE + if (use_cache) + dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +#endif + *saddr = fl6.saddr; + return dst; +} +EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); + MODULE_LICENSE("GPL"); diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c index a29ff901df7588..d4dbdd3d5679de 100644 --- a/net/mptcp/fastopen.c +++ b/net/mptcp/fastopen.c @@ -12,6 +12,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf struct sock *sk, *ssk; struct sk_buff *skb; struct tcp_sock *tp; + bool has_rxtstamp; /* on early fallback the subflow context is deleted by * subflow_syn_recv_sock() @@ -39,14 +40,14 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf */ tp->copied_seq += skb->len; subflow->ssn_offset += skb->len; + has_rxtstamp = TCP_SKB_CB(skb)->has_rxtstamp; - /* initialize a dummy sequence number, we will update it at MPC - * completion, if needed - */ + /* Only the sequence delta is relevant */ MPTCP_SKB_CB(skb)->map_seq = -skb->len; MPTCP_SKB_CB(skb)->end_seq = 0; MPTCP_SKB_CB(skb)->offset = 0; - MPTCP_SKB_CB(skb)->has_rxtstamp = TCP_SKB_CB(skb)->has_rxtstamp; + MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; + MPTCP_SKB_CB(skb)->cant_coalesce = 1; mptcp_data_lock(sk); @@ -58,22 +59,3 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf mptcp_data_unlock(sk); } - -void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt) -{ - struct sock *sk = (struct sock *)msk; - struct sk_buff *skb; - - skb = skb_peek_tail(&sk->sk_receive_queue); - if (skb) { - WARN_ON_ONCE(MPTCP_SKB_CB(skb)->end_seq); - pr_debug("msk %p moving seq %llx -> %llx end_seq %llx -> %llx\n", sk, - MPTCP_SKB_CB(skb)->map_seq, MPTCP_SKB_CB(skb)->map_seq + msk->ack_seq, - MPTCP_SKB_CB(skb)->end_seq, MPTCP_SKB_CB(skb)->end_seq + msk->ack_seq); - MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq; - MPTCP_SKB_CB(skb)->end_seq += msk->ack_seq; - } - - pr_debug("msk=%p ack_seq=%llx\n", msk, msk->ack_seq); -} diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 28f8d7fb7bdf39..4a5802126c8e4b 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -308,8 +308,15 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (!entry->addr.id) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { - sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); + sk_reset_timer(sk, timer, jiffies + HZ); goto out; } @@ -336,6 +343,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } @@ -591,6 +599,8 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) /* check first for announce */ if (msk->pm.add_addr_signaled < add_addr_signal_max) { + u8 endp_id; + /* due to racing events on both ends we can reach here while * previous add address is still running: if we invoke now * mptcp_pm_announce_addr(), that will fail and the @@ -604,19 +614,20 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) if (!select_signal_address(pernet, msk, &local)) goto subflow; + /* Special case for ID0: set the correct ID */ + endp_id = local.addr.id; + if (endp_id == msk->mpc_endpoint_id) + local.addr.id = 0; + /* If the alloc fails, we are on memory pressure, not worth * continuing, and trying to create subflows. */ if (!mptcp_pm_alloc_anno_list(msk, &local.addr)) return; - __clear_bit(local.addr.id, msk->pm.id_avail_bitmap); + __clear_bit(endp_id, msk->pm.id_avail_bitmap); msk->pm.add_addr_signaled++; - /* Special case for ID0: set the correct ID */ - if (local.addr.id == msk->mpc_endpoint_id) - local.addr.id = 0; - mptcp_pm_announce_addr(msk, &local.addr, false); mptcp_pm_nl_addr_send_ack(msk); @@ -923,6 +934,9 @@ int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk, struct sock *ssk = mptcp_subflow_tcp_sock(subflow); struct mptcp_addr_info local, remote; + if (!__mptcp_subflow_active(subflow)) + continue; + mptcp_local_address((struct sock_common *)ssk, &local); if (!mptcp_addresses_equal(&local, addr, addr->port)) continue; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 71995d00696eab..aed6c04c7de67c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -139,7 +139,8 @@ static bool mptcp_try_coalesce(struct sock *sk, struct sk_buff *to, bool fragstolen; int delta; - if (MPTCP_SKB_CB(from)->offset || + if (unlikely(MPTCP_SKB_CB(to)->cant_coalesce) || + MPTCP_SKB_CB(from)->offset || ((to->len + from->len) > (sk->sk_rcvbuf >> 3)) || !skb_try_coalesce(to, from, &fragstolen, &delta)) return false; @@ -370,6 +371,7 @@ static bool __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk, MPTCP_SKB_CB(skb)->end_seq = MPTCP_SKB_CB(skb)->map_seq + copy_len; MPTCP_SKB_CB(skb)->offset = offset; MPTCP_SKB_CB(skb)->has_rxtstamp = has_rxtstamp; + MPTCP_SKB_CB(skb)->cant_coalesce = 0; if (MPTCP_SKB_CB(skb)->map_seq == msk->ack_seq) { /* in sequence */ diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index fbb3897c9c2c2b..2a33452715597a 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -129,7 +129,8 @@ struct mptcp_skb_cb { u64 map_seq; u64 end_seq; u32 offset; - u8 has_rxtstamp:1; + u8 has_rxtstamp; + u8 cant_coalesce; }; #define MPTCP_SKB_CB(__skb) ((struct mptcp_skb_cb *)&((__skb)->cb[0])) @@ -988,8 +989,6 @@ void mptcp_event_pm_listener(const struct sock *ssk, enum mptcp_event_type event); bool mptcp_userspace_pm_active(const struct mptcp_sock *msk); -void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, - const struct mptcp_options_received *mp_opt); void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow, struct request_sock *req); diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 49be98ffd1de7a..f2fc735d8b6183 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -778,9 +778,6 @@ void __mptcp_subflow_fully_established(struct mptcp_sock *msk, subflow_set_remote_key(msk, subflow, mp_opt); subflow->fully_established = 1; WRITE_ONCE(msk->fully_established, true); - - if (subflow->is_mptfo) - __mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt); } static struct sock *subflow_syn_recv_sock(const struct sock *sk, diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 2877706f0162fa..819538d2e46003 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) return dest_dst; } +/* Based on ip_exceeds_mtu(). */ +static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) +{ + if (skb->len <= mtu) + return false; + + if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) + return false; + + return true; +} + static inline bool __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) { @@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) */ if (IP6CB(skb)->frag_max_size > mtu) return true; /* largest fragment violate MTU */ - } - else if (skb->len > mtu && !skb_is_gso(skb)) { + } else if (ip_vs_exceeds_mtu(skb, mtu)) return true; /* Packet size violate MTU size */ - } + return false; } @@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, return true; if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && - skb->len > mtu && !skb_is_gso(skb) && + ip_vs_exceeds_mtu(skb, mtu) && !ip_vs_iph_icmp(ipvsh))) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index fabb2c1ca00ab5..0dd55d3fba38da 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -471,9 +471,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, if (!ih) goto out_unlock; - if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) - ct->proto.sctp.init[!dir] = 0; - ct->proto.sctp.init[dir] = 1; + /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ + if (old_state == SCTP_CONNTRACK_NONE || + ct->proto.sctp.vtag[!dir] != ih->init_tag) { + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) + ct->proto.sctp.init[!dir] = 0; + ct->proto.sctp.init[dir] = 1; + } pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index fda6fc1fc4c583..ec31611b7a290b 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, return 1; } +/* Parse optional port number after IP address. + * Returns false on malformed input, true otherwise. + * If port is non-NULL, stores parsed port in network byte order. + * If no port is present, sets *port to default SIP port. + */ +static bool sip_parse_port(const char *dptr, const char **endp, + const char *limit, __be16 *port) +{ + unsigned int p = 0; + int len = 0; + + if (dptr >= limit) + return false; + + if (*dptr != ':') { + if (port) + *port = htons(SIP_PORT); + if (endp) + *endp = dptr; + return true; + } + + dptr++; /* skip ':' */ + + while (dptr < limit && isdigit(*dptr)) { + p = p * 10 + (*dptr - '0'); + dptr++; + len++; + if (len > 5) /* max "65535" */ + return false; + } + + if (len == 0) + return false; + + /* reached limit while parsing port */ + if (dptr >= limit) + return false; + + if (p < 1024 || p > 65535) + return false; + + if (port) + *port = htons(p); + + if (endp) + *endp = dptr; + + return true; +} + /* skip ip address. returns its length. */ static int epaddr_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) @@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, return 0; } - /* Port number */ - if (*dptr == ':') { - dptr++; - dptr += digits_len(ct, dptr, limit, shift); - } + if (!sip_parse_port(dptr, &dptr, limit, NULL)) + return 0; return dptr - aux; } @@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, return epaddr_len(ct, dptr, limit, shift); } +/* simple_strtoul stops after first non-number character. + * But as we're not dealing with c-strings, we can't rely on + * hitting \r,\n,\0 etc. before moving past end of buffer. + * + * This is a variant of simple_strtoul, but doesn't require + * a c-string. + * + * If value exceeds UINT_MAX, 0 is returned. + */ +static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) +{ + const unsigned int max = sizeof("4294967295"); + unsigned int olen = len; + const char *s = cp; + u64 result = 0; + + if (len > max) + len = max; + + while (olen > 0 && isdigit(*s)) { + unsigned int value; + + if (len == 0) + goto err; + + value = *s - '0'; + result = result * 10 + value; + + if (result > UINT_MAX) + goto err; + s++; + len--; + olen--; + } + + if (endp) + *endp = (char *)s; + + return result; +err: + if (endp) + *endp = (char *)cp; + return 0; +} + /* Parse a SIP request line of the form: * * Request-Line = Method SP Request-URI SP SIP-Version CRLF @@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, { const char *start = dptr, *limit = dptr + datalen, *end; unsigned int mlen; - unsigned int p; int shift = 0; /* Skip method and following whitespace */ @@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) return -1; - if (end < limit && *end == ':') { - end++; - p = simple_strtoul(end, (char **)&end, 10); - if (p < 1024 || p > 65535) - return -1; - *port = htons(p); - } else - *port = htons(SIP_PORT); + if (!sip_parse_port(end, &end, limit, port)) + return -1; if (end == dptr) return 0; @@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, union nf_inet_addr *addr, __be16 *port) { const char *c, *limit = dptr + datalen; - unsigned int p; int ret; ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, @@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) return -1; - if (*c == ':') { - c++; - p = simple_strtoul(c, (char **)&c, 10); - if (p < 1024 || p > 65535) - return -1; - *port = htons(p); - } else - *port = htons(SIP_PORT); + if (!sip_parse_port(c, &c, limit, port)) + return -1; if (dataoff) *dataoff = c - dptr; @@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, return 0; start += strlen(name); - *val = simple_strtoul(start, &end, 0); + *val = sip_strtouint(start, limit - start, (char **)&end); if (start == end) return -1; if (matchoff && matchlen) { @@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff = sdpoff; for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { + char *end; + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, SDP_HDR_MEDIA, SDP_HDR_UNSPEC, &mediaoff, &medialen) <= 0) @@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff += t->len; medialen -= t->len; - port = simple_strtoul(*dptr + mediaoff, NULL, 10); - if (port == 0) + port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); + if (port == 0 || *dptr + mediaoff == end) continue; if (port < 1024 || port > 65535) { nf_ct_helper_log(skb, ct, "wrong port %u", port); @@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, */ if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, &matchoff, &matchlen) > 0) - expires = simple_strtoul(*dptr + matchoff, NULL, 10); + expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, SIP_HDR_CONTACT, NULL, @@ -1286,6 +1367,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, goto store_cseq; } + helper = rcu_dereference(nfct_help(ct)->helper); + if (!helper) + return NF_DROP; + exp = nf_ct_expect_alloc(ct); if (!exp) { nf_ct_helper_log(skb, ct, "cannot alloc expectation"); @@ -1296,10 +1381,6 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, if (sip_direct_signalling) saddr = &ct->tuplehash[!dir].tuple.src.u3; - helper = rcu_dereference(nfct_help(ct)->helper); - if (!helper) - return NF_DROP; - nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), saddr, &daddr, proto, NULL, &port); exp->timeout.expires = sip_timeout * HZ; @@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, &matchoff, &matchlen) > 0) - expires = simple_strtoul(*dptr + matchoff, NULL, 10); + expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); while (1) { unsigned int c_expires = expires; @@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchoff, matchlen, matchend; unsigned int code, cseq, i; + char *end; if (*datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; - code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); + code = sip_strtouint(*dptr + strlen("SIP/2.0 "), + *datalen - strlen("SIP/2.0 "), NULL); if (!code) { nf_ct_helper_log(skb, ct, "cannot get code"); return NF_DROP; @@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, nf_ct_helper_log(skb, ct, "cannot parse cseq"); return NF_DROP; } - cseq = simple_strtoul(*dptr + matchoff, NULL, 10); - if (!cseq && *(*dptr + matchoff) != '0') { + cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); + if (*dptr + matchoff == end) { nf_ct_helper_log(skb, ct, "cannot get cseq"); return NF_DROP; } @@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { const struct sip_handler *handler; + char *end; handler = &sip_handlers[i]; if (handler->request == NULL) @@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, nf_ct_helper_log(skb, ct, "cannot parse cseq"); return NF_DROP; } - cseq = simple_strtoul(*dptr + matchoff, NULL, 10); - if (!cseq && *(*dptr + matchoff) != '0') { + cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); + if (*dptr + matchoff == end) { nf_ct_helper_log(skb, ct, "cannot get cseq"); return NF_DROP; } @@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0) break; - clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); + clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); if (dptr + matchoff == end) break; diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c index 98deef6cde6943..8f1054920a8571 100644 --- a/net/netfilter/nf_nat_amanda.c +++ b/net/netfilter/nf_nat_amanda.c @@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, return NF_DROP; } - sprintf(buffer, "%u", port); + snprintf(buffer, sizeof(buffer), "%u", port); if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, protoff, matchoff, matchlen, buffer, strlen(buffer))) { diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index cf4aeb299bdef2..9fbfc6bff0c221 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c @@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, } static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, + size_t size, const union nf_inet_addr *addr, bool delim) { if (nf_ct_l3num(ct) == NFPROTO_IPV4) - return sprintf(buffer, "%pI4", &addr->ip); + return scnprintf(buffer, size, "%pI4", &addr->ip); else { if (delim) - return sprintf(buffer, "[%pI6c]", &addr->ip6); + return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); else - return sprintf(buffer, "%pI6c", &addr->ip6); + return scnprintf(buffer, size, "%pI6c", &addr->ip6); } } static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, + size_t size, const union nf_inet_addr *addr, u16 port) { if (nf_ct_l3num(ct) == NFPROTO_IPV4) - return sprintf(buffer, "%pI4:%u", &addr->ip, port); + return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); else - return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); + return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); } static int map_addr(struct sk_buff *skb, unsigned int protoff, @@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) return 1; - buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); + buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); return mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); } @@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, true) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.dst.u3, true); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, @@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, false) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.src.u3, false); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, @@ -244,10 +246,11 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, "rport=", &poff, &plen, &n) > 0 && + n >= 1024 && n <= 65535 && htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; - buflen = sprintf(buffer, "%u", ntohs(p)); + buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, poff, plen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle rport"); @@ -418,7 +421,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { - buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); + buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), + &newaddr, port); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle packet"); @@ -438,8 +442,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + char buffer[sizeof("4294967295")]; unsigned int matchoff, matchlen; - char buffer[sizeof("65536")]; int buflen, c_len; /* Get actual SDP length */ @@ -454,7 +458,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0) return 0; - buflen = sprintf(buffer, "%u", c_len); + buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); return mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); } @@ -491,7 +495,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, char buffer[INET6_ADDRSTRLEN]; unsigned int buflen; - buflen = sip_sprintf_addr(ct, buffer, addr, false); + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, type, term, buffer, buflen)) return 0; @@ -509,7 +513,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, char buffer[sizeof("nnnnn")]; unsigned int buflen; - buflen = sprintf(buffer, "%u", port); + buflen = scnprintf(buffer, sizeof(buffer), "%u", port); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) return 0; @@ -529,7 +533,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff unsigned int buflen; /* Mangle session description owner and contact addresses */ - buflen = sip_sprintf_addr(ct, buffer, addr, false); + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) return 0; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index a0914a92e07dd0..6fc88bf5110927 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6803,6 +6803,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, struct nft_data_desc desc; enum nft_registers dreg; struct nft_trans *trans; + bool set_full = false; u64 timeout; u64 expiration; int err, i; @@ -7095,10 +7096,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, if (err < 0) goto err_elem_free; + if (!(flags & NFT_SET_ELEM_CATCHALL)) { + unsigned int max = nft_set_maxsize(set), nelems; + + nelems = atomic_inc_return(&set->nelems); + if (nelems > max) + set_full = true; + } + trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); if (trans == NULL) { err = -ENOMEM; - goto err_elem_free; + goto err_set_size; } ext->genmask = nft_genmask_cur(ctx->net); @@ -7130,23 +7139,16 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, goto err_element_clash; } - if (!(flags & NFT_SET_ELEM_CATCHALL)) { - unsigned int max = nft_set_maxsize(set); - - if (!atomic_add_unless(&set->nelems, 1, max)) { - err = -ENFILE; - goto err_set_full; - } - } - nft_trans_elem(trans) = elem; nft_trans_commit_list_add_tail(ctx->net, trans); - return 0; -err_set_full: - nft_setelem_remove(ctx->net, set, &elem); + return set_full ? -ENFILE : 0; + err_element_clash: kfree(trans); +err_set_size: + if (!(flags & NFT_SET_ELEM_CATCHALL)) + atomic_dec(&set->nelems); err_elem_free: nf_tables_set_elem_destroy(ctx, set, elem.priv); err_parse_data: diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c index da9d5d6de98f4d..6d3dfbeb398cb4 100644 --- a/net/netfilter/nfnetlink_osf.c +++ b/net/netfilter/nfnetlink_osf.c @@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); static inline int nf_osf_ttl(const struct sk_buff *skb, int ttl_check, unsigned char f_ttl) { - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); const struct iphdr *ip = ip_hdr(skb); - const struct in_ifaddr *ifa; - int ret = 0; - if (ttl_check == NF_OSF_TTL_TRUE) + switch (ttl_check) { + case NF_OSF_TTL_TRUE: return ip->ttl == f_ttl; - if (ttl_check == NF_OSF_TTL_NOCHECK) - return 1; - else if (ip->ttl <= f_ttl) + break; + case NF_OSF_TTL_NOCHECK: return 1; - - in_dev_for_each_ifa_rcu(ifa, in_dev) { - if (inet_ifa_match(ip->saddr, ifa)) { - ret = (ip->ttl == f_ttl); - break; - } + case NF_OSF_TTL_LESS: + default: + return ip->ttl <= f_ttl; } - - return ret; } struct nf_osf_hdr_ctx { @@ -64,9 +56,9 @@ struct nf_osf_hdr_ctx { static bool nf_osf_match_one(const struct sk_buff *skb, const struct nf_osf_user_finger *f, int ttl_check, - struct nf_osf_hdr_ctx *ctx) + const struct nf_osf_hdr_ctx *ctx) { - const __u8 *optpinit = ctx->optp; + const __u8 *optp = ctx->optp; unsigned int check_WSS = 0; int fmatch = FMATCH_WRONG; int foptsize, optnum; @@ -95,17 +87,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, check_WSS = f->wss.wc; for (optnum = 0; optnum < f->opt_num; ++optnum) { - if (f->opt[optnum].kind == *ctx->optp) { + if (f->opt[optnum].kind == *optp) { __u32 len = f->opt[optnum].length; - const __u8 *optend = ctx->optp + len; + const __u8 *optend = optp + len; fmatch = FMATCH_OK; - switch (*ctx->optp) { + switch (*optp) { case OSFOPT_MSS: - mss = ctx->optp[3]; + mss = optp[3]; mss <<= 8; - mss |= ctx->optp[2]; + mss |= optp[2]; mss = ntohs((__force __be16)mss); break; @@ -113,7 +105,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, break; } - ctx->optp = optend; + optp = optend; } else fmatch = FMATCH_OPT_WRONG; @@ -156,9 +148,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, } } - if (fmatch != FMATCH_OK) - ctx->optp = optpinit; - return fmatch == FMATCH_OK; } @@ -320,6 +309,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, if (f->opt_num > ARRAY_SIZE(f->opt)) return -EINVAL; + if (f->wss.wc >= OSF_WSS_MAX || + (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) + return -EINVAL; + for (i = 0; i < f->opt_num; i++) { if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) return -EINVAL; diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 7ed103de9b76fd..83c963e668ffe0 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -1363,6 +1363,8 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj, if (nf_ct_expect_related(exp, 0) != 0) regs->verdict.code = NF_DROP; + + nf_ct_expect_put(exp); } static const struct nla_policy nft_ct_expect_policy[NFTA_CT_EXPECT_MAX + 1] = { diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c index 42ba31dfc03593..1223bdea1f00d4 100644 --- a/net/netfilter/nft_fwd_netdev.c +++ b/net/netfilter/nft_fwd_netdev.c @@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, goto out; } iph = ip_hdr(skb); + if (iph->ttl <= 1) { + verdict = NF_DROP; + goto out; + } + ip_decrease_ttl(iph); neigh_table = NEIGH_ARP_TABLE; break; @@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, goto out; } ip6h = ipv6_hdr(skb); + if (ip6h->hop_limit <= 1) { + verdict = NF_DROP; + goto out; + } + ip6h->hop_limit--; neigh_table = NEIGH_ND_TABLE; break; diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c index 123b4f47ccef4c..23ec9b397f1ebc 100644 --- a/net/netfilter/nft_osf.c +++ b/net/netfilter/nft_osf.c @@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, struct nf_osf_data data; struct tcphdr _tcph; + if (nft_pf(pkt) != NFPROTO_IPV4) { + regs->verdict.code = NFT_BREAK; + return; + } + if (pkt->tprot != IPPROTO_TCP) { regs->verdict.code = NFT_BREAK; return; @@ -119,7 +124,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, switch (ctx->family) { case NFPROTO_IPV4: - case NFPROTO_IPV6: case NFPROTO_INET: hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_PRE_ROUTING) | diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c index 81649da57ba5d3..bd2354760895d2 100644 --- a/net/netfilter/xt_mac.c +++ b/net/netfilter/xt_mac.c @@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) return ret; } -static struct xt_match mac_mt_reg __read_mostly = { - .name = "mac", - .revision = 0, - .family = NFPROTO_UNSPEC, - .match = mac_mt, - .matchsize = sizeof(struct xt_mac_info), - .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | - (1 << NF_INET_FORWARD), - .me = THIS_MODULE, +static struct xt_match mac_mt_reg[] __read_mostly = { + { + .name = "mac", + .family = NFPROTO_IPV4, + .match = mac_mt, + .matchsize = sizeof(struct xt_mac_info), + .hooks = (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_FORWARD), + .me = THIS_MODULE, + }, + { + .name = "mac", + .family = NFPROTO_IPV6, + .match = mac_mt, + .matchsize = sizeof(struct xt_mac_info), + .hooks = (1 << NF_INET_PRE_ROUTING) | + (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_FORWARD), + .me = THIS_MODULE, + }, }; static int __init mac_mt_init(void) { - return xt_register_match(&mac_mt_reg); + return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); } static void __exit mac_mt_exit(void) { - xt_unregister_match(&mac_mt_reg); + xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); } module_init(mac_mt_init); diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c index 50332888c8d233..7be2fe22b067e8 100644 --- a/net/netfilter/xt_owner.c +++ b/net/netfilter/xt_owner.c @@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) return true; } -static struct xt_match owner_mt_reg __read_mostly = { - .name = "owner", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = owner_check, - .match = owner_mt, - .matchsize = sizeof(struct xt_owner_match_info), - .hooks = (1 << NF_INET_LOCAL_OUT) | - (1 << NF_INET_POST_ROUTING), - .me = THIS_MODULE, +static struct xt_match owner_mt_reg[] __read_mostly = { + { + .name = "owner", + .revision = 1, + .family = NFPROTO_IPV4, + .checkentry = owner_check, + .match = owner_mt, + .matchsize = sizeof(struct xt_owner_match_info), + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING), + .me = THIS_MODULE, + }, + { + .name = "owner", + .revision = 1, + .family = NFPROTO_IPV6, + .checkentry = owner_check, + .match = owner_mt, + .matchsize = sizeof(struct xt_owner_match_info), + .hooks = (1 << NF_INET_LOCAL_OUT) | + (1 << NF_INET_POST_ROUTING), + .me = THIS_MODULE, + } }; static int __init owner_mt_init(void) { - return xt_register_match(&owner_mt_reg); + return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); } static void __exit owner_mt_exit(void) { - xt_unregister_match(&owner_mt_reg); + xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); } module_init(owner_mt_init); diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 343e65f377d442..130842c35c6fa8 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c @@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) return 0; } -static struct xt_match physdev_mt_reg __read_mostly = { - .name = "physdev", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = physdev_mt_check, - .match = physdev_mt, - .matchsize = sizeof(struct xt_physdev_info), - .me = THIS_MODULE, +static struct xt_match physdev_mt_reg[] __read_mostly = { + { + .name = "physdev", + .family = NFPROTO_IPV4, + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize = sizeof(struct xt_physdev_info), + .me = THIS_MODULE, + }, + { + .name = "physdev", + .family = NFPROTO_IPV6, + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize = sizeof(struct xt_physdev_info), + .me = THIS_MODULE, + }, }; static int __init physdev_mt_init(void) { - return xt_register_match(&physdev_mt_reg); + return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); } static void __exit physdev_mt_exit(void) { - xt_unregister_match(&physdev_mt_reg); + xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); } module_init(physdev_mt_init); diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index cb6e8279010a4b..b5fa65558318f5 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c @@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, return 0; for (i = sp->len - 1; i >= 0; i--) { - pos = strict ? i - sp->len + 1 : 0; + pos = strict ? sp->len - i - 1 : 0; if (pos >= info->len) return 0; e = &info->pol[pos]; diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c index 6df485f4403d02..61b2f1e58d1505 100644 --- a/net/netfilter/xt_realm.c +++ b/net/netfilter/xt_realm.c @@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { .matchsize = sizeof(struct xt_realm_info), .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), - .family = NFPROTO_UNSPEC, + .family = NFPROTO_IPV4, .me = THIS_MODULE }; diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 76e01f292aaff6..811e53bee4085b 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) static int socket_mt_v1_check(const struct xt_mtchk_param *par) { const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; - int err; - - err = socket_mt_enable_defrag(par->net, par->family); - if (err) - return err; if (info->flags & ~XT_SOCKET_FLAGS_V1) { pr_info_ratelimited("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1); return -EINVAL; } - return 0; + + return socket_mt_enable_defrag(par->net, par->family); } static int socket_mt_v2_check(const struct xt_mtchk_param *par) { const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; - int err; - - err = socket_mt_enable_defrag(par->net, par->family); - if (err) - return err; if (info->flags & ~XT_SOCKET_FLAGS_V2) { pr_info_ratelimited("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2); return -EINVAL; } - return 0; + + return socket_mt_enable_defrag(par->net, par->family); } static int socket_mt_v3_check(const struct xt_mtchk_param *par) { const struct xt_socket_mtinfo3 *info = (struct xt_socket_mtinfo3 *)par->matchinfo; - int err; - err = socket_mt_enable_defrag(par->net, par->family); - if (err) - return err; if (info->flags & ~XT_SOCKET_FLAGS_V3) { pr_info_ratelimited("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V3); return -EINVAL; } - return 0; + + return socket_mt_enable_defrag(par->net, par->family); } static void socket_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index cb52fac7caa3cd..7803e7548d9203 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -2158,9 +2158,40 @@ error: return err; } +static size_t ovs_vport_cmd_msg_size(void) +{ + size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); + + msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ + msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ + msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ + msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ + msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ + + /* OVS_VPORT_ATTR_STATS */ + msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); + + /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + + * OVS_VPORT_UPCALL_ATTR_FAIL) + */ + msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + + nla_total_size_64bit(sizeof(u64))); + + /* OVS_VPORT_ATTR_UPCALL_PID */ + msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); + + /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + + * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) + */ + msgsize += nla_total_size(nla_total_size(sizeof(u16)) + + nla_total_size(nla_total_size(0))); + + return msgsize; +} + static struct sk_buff *ovs_vport_cmd_alloc_info(void) { - return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); } /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ @@ -2170,7 +2201,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, struct sk_buff *skb; int retval; - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + skb = ovs_vport_cmd_alloc_info(); if (!skb) return ERR_PTR(-ENOMEM); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 0faa6e097829c5..a0a8854e9f19e8 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -407,6 +407,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) return -EINVAL; + if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) + return -EINVAL; + old = ovsl_dereference(vport->upcall_portids); vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 8435a20968ef51..f0840169d5e31f 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) return ret; } -static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) +static int rds_set_transport(struct net *net, struct rds_sock *rs, + sockptr_t optval, int optlen) { int t_type; @@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) if (t_type < 0 || t_type >= RDS_TRANS_COUNT) return -EINVAL; + /* RDS/IB is restricted to the initial network namespace */ + if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) + return -EPROTOTYPE; + rs->rs_transport = rds_trans_get(t_type); return rs->rs_transport ? 0 : -ENOPROTOOPT; @@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen) { struct rds_sock *rs = rds_sk_to_rs(sock->sk); + struct net *net = sock_net(sock->sk); int ret; if (level != SOL_RDS) { @@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, break; case SO_RDS_TRANSPORT: lock_sock(sock->sk); - ret = rds_set_transport(rs, optval, optlen); + ret = rds_set_transport(net, rs, optval, optlen); release_sock(sock->sk); break; case SO_TIMESTAMP_OLD: diff --git a/net/rds/connection.c b/net/rds/connection.c index 98c0d5ff9de9c6..cd41f83863c893 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, i++, head++) { hlist_for_each_entry_rcu(conn, head, c_hash_node) { + /* Zero the per-item buffer before handing it to the + * visitor so any field the visitor does not write - + * including implicit alignment padding - cannot leak + * stack contents to user space via rds_info_copy(). + */ + memset(buffer, 0, item_len); + /* XXX no c_lock usage.. */ if (!visitor(conn, buffer)) continue; @@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, */ cp = conn->c_path; + /* Zero the per-item buffer for the same reason as + * rds_for_each_conn_info(): any byte the visitor + * does not write (including alignment padding) must + * not leak stack contents via rds_info_copy(). + */ + memset(buffer, 0, item_len); + /* XXX no cp_lock usage.. */ if (!visitor(cp, buffer)) continue; diff --git a/net/rds/ib.c b/net/rds/ib.c index 9826fe7f9d0086..ce5be43c5fbac3 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, * allowed to influence which paths have priority. We could call userspace * asserting this policy "routing". */ -static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, - __u32 scope_id) +static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, + __u32 scope_id) { int ret; struct rdma_cm_id *cm_id; @@ -489,6 +489,26 @@ out: return ret; } +static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + __u32 scope_id) +{ + struct rds_ib_device *rds_ibdev = NULL; + + /* RDS/IB is restricted to the initial network namespace */ + if (!net_eq(net, &init_net)) + return -EPROTOTYPE; + + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { + rds_ib_dev_put(rds_ibdev); + return 0; + } + } + + return rds_ib_laddr_check_cm(net, addr, scope_id); +} + static void rds_ib_unregister_client(void) { ib_unregister_client(&rds_ib_client); diff --git a/net/rds/ib.h b/net/rds/ib.h index 2ba71102b1f1f2..d6c1197731c1c2 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -384,6 +384,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) /* ib_rdma.c */ +struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, struct in6_addr *ipaddr); void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 30fca2169aa7ab..468fd60d818ff3 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { static void rds_ib_odp_mr_worker(struct work_struct *work); -static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) +struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) { struct rds_ib_device *rds_ibdev; struct rds_ib_ipaddr *i_ipaddr; diff --git a/net/rds/message.c b/net/rds/message.c index 921d89973b935b..9824e79e057f4f 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -408,6 +408,7 @@ static int rds_message_zcopy_from_user(struct rds_message *rm, struct iov_iter * for (i = 0; i < rm->data.op_nents; i++) put_page(sg_page(&rm->data.op_sg[i])); + rm->data.op_nents = 0; mmp = &rm->data.op_mmp_znotifier->z_mmp; mm_unaccount_pinned_pages(mmp); ret = -EFAULT; diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index a5f4a27c8dd31f..7810c9d64ff3ae 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -328,9 +328,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) int err = -ENOMEM; mutex_lock(&zones_mutex); - ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); - if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) + rcu_read_lock(); + ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { + rcu_read_unlock(); goto out_unlock; + } + rcu_read_unlock(); ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); if (!ct_ft) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 14e06f474b6caf..0b85971165d2a3 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -620,7 +620,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, } port = rev ? tuple.src.u.all : tuple.dst.u.all; if (port != keys->ports.dst) { - port = keys->ports.dst; + keys->ports.dst = port; upd = true; } } @@ -2314,10 +2314,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, byte_target_ns = (byte_target * rate_ns) >> rate_shft; - b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); - b->cparams.interval = max(rtt_est_ns + - b->cparams.target - target_ns, - b->cparams.target * 2); + WRITE_ONCE(b->cparams.target, + max((byte_target_ns * 3) / 2, target_ns)); + WRITE_ONCE(b->cparams.interval, + max(rtt_est_ns + b->cparams.target - target_ns, + b->cparams.target * 2)); b->cparams.mtu_time = byte_target_ns; b->cparams.p_inc = 1 << 24; /* 1/256 */ b->cparams.p_dec = 1 << 20; /* 1/4096 */ @@ -2931,9 +2932,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); PUT_TSTAT_U32(TARGET_US, - ktime_to_us(ns_to_ktime(b->cparams.target))); + ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); PUT_TSTAT_U32(INTERVAL_US, - ktime_to_us(ns_to_ktime(b->cparams.interval))); + ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); PUT_TSTAT_U32(SENT_PACKETS, b->packets); PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index a9195914220850..b27da148ca7442 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* Draw a packet at random from queue and compare flow */ if (choke_match_random(q, skb, &idx)) { - q->stats.matched++; + WRITE_ONCE(q->stats.matched, q->stats.matched + 1); choke_drop_by_idx(sch, idx, to_free); goto congestion_drop; } @@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, qdisc_qstats_overlimit(sch); if (use_harddrop(q) || !use_ecn(q) || !INET_ECN_set_ce(skb)) { - q->stats.forced_drop++; + WRITE_ONCE(q->stats.forced_drop, + q->stats.forced_drop + 1); goto congestion_drop; } - q->stats.forced_mark++; + WRITE_ONCE(q->stats.forced_mark, + q->stats.forced_mark + 1); } else if (++q->vars.qcount) { if (red_mark_probability(p, &q->vars, q->vars.qavg)) { q->vars.qcount = 0; @@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, qdisc_qstats_overlimit(sch); if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { - q->stats.prob_drop++; + WRITE_ONCE(q->stats.prob_drop, + q->stats.prob_drop + 1); goto congestion_drop; } - q->stats.prob_mark++; + WRITE_ONCE(q->stats.prob_mark, + q->stats.prob_mark + 1); } } else q->vars.qR = red_random(p); @@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, return NET_XMIT_SUCCESS; } - q->stats.pdrop++; + WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); return qdisc_drop(skb, sch, to_free); congestion_drop: @@ -460,10 +464,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct choke_sched_data *q = qdisc_priv(sch); struct tc_choke_xstats st = { - .early = q->stats.prob_drop + q->stats.forced_drop, - .marked = q->stats.prob_mark + q->stats.forced_mark, - .pdrop = q->stats.pdrop, - .matched = q->stats.matched, + .early = READ_ONCE(q->stats.prob_drop) + + READ_ONCE(q->stats.forced_drop), + .marked = READ_ONCE(q->stats.prob_mark) + + READ_ONCE(q->stats.forced_mark), + .pdrop = READ_ONCE(q->stats.pdrop), + .matched = READ_ONCE(q->stats.matched), }; return gnet_stats_copy_app(d, &st, sizeof(st)); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 47b5a056165cb0..056895df178541 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -568,6 +568,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) }; struct list_head *pos; + sch_tree_lock(sch); + st.qdisc_stats.maxpacket = q->cstats.maxpacket; st.qdisc_stats.drop_overlimit = q->drop_overlimit; st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; @@ -576,7 +578,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.qdisc_stats.memory_usage = q->memory_usage; st.qdisc_stats.drop_overmemory = q->drop_overmemory; - sch_tree_lock(sch); list_for_each(pos, &q->new_flows) st.qdisc_stats.new_flows_len++; diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c index 607c580d75e4b6..4bd5ca9acc53f7 100644 --- a/net/sched/sch_fq_pie.c +++ b/net/sched/sch_fq_pie.c @@ -498,18 +498,19 @@ nla_put_failure: static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct fq_pie_sched_data *q = qdisc_priv(sch); - struct tc_fq_pie_xstats st = { - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .overmemory = q->overmemory, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, - .new_flow_count = q->new_flow_count, - .memory_usage = q->memory_usage, - }; + struct tc_fq_pie_xstats st = { 0 }; struct list_head *pos; sch_tree_lock(sch); + + st.packets_in = q->stats.packets_in; + st.overlimit = q->stats.overlimit; + st.overmemory = q->overmemory; + st.dropped = q->stats.dropped; + st.ecn_mark = q->stats.ecn_mark; + st.new_flow_count = q->new_flow_count; + st.memory_usage = q->memory_usage; + list_for_each(pos, &q->new_flows) st.new_flows_len++; diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 83fc44f20e31cb..67b555c02f2c01 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, return NULL; list_del(&flow->flowchain); kfree(flow); - q->hh_flows_current_cnt--; + WRITE_ONCE(q->hh_flows_current_cnt, + q->hh_flows_current_cnt - 1); } else if (flow->hash_id == hash) { return flow; } @@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, } if (q->hh_flows_current_cnt >= q->hh_flows_limit) { - q->hh_flows_overlimit++; + WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); return NULL; } /* Create new entry. */ @@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, if (!flow) return NULL; - q->hh_flows_current_cnt++; + WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); INIT_LIST_HEAD(&flow->flowchain); list_add_tail(&flow->flowchain, head); @@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) return WDRR_BUCKET_FOR_NON_HH; flow->hash_id = hash; flow->hit_timestamp = now; - q->hh_flows_total_cnt++; + WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); /* By returning without updating counters in q->hhf_arrays, * we implicitly implement "shielding" (see Optimization O1). @@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, return NET_XMIT_SUCCESS; prev_backlog = sch->qstats.backlog; - q->drop_overlimit++; + WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); /* Return Congestion Notification only if we dropped a packet from this * bucket. */ @@ -678,10 +679,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct hhf_sched_data *q = qdisc_priv(sch); struct tc_hhf_xstats st = { - .drop_overlimit = q->drop_overlimit, - .hh_overlimit = q->hh_flows_overlimit, - .hh_tot_count = q->hh_flows_total_cnt, - .hh_cur_count = q->hh_flows_current_cnt, + .drop_overlimit = READ_ONCE(q->drop_overlimit), + .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), + .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), + .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), }; return gnet_stats_copy_app(d, &st, sizeof(st)); diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 7361f90c8c1a11..f8c5c506180858 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -226,10 +226,10 @@ static bool loss_4state(struct netem_sched_data *q) if (rnd < clg->a4) { clg->state = LOST_IN_GAP_PERIOD; return true; - } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { + } else if (rnd < clg->a1 + clg->a4) { clg->state = LOST_IN_BURST_PERIOD; return true; - } else if (clg->a1 + clg->a4 < rnd) { + } else { clg->state = TX_IN_GAP_PERIOD; } @@ -246,9 +246,9 @@ static bool loss_4state(struct netem_sched_data *q) case LOST_IN_BURST_PERIOD: if (rnd < clg->a3) clg->state = TX_IN_BURST_PERIOD; - else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { + else if (rnd < clg->a2 + clg->a3) { clg->state = TX_IN_GAP_PERIOD; - } else if (clg->a2 + clg->a3 < rnd) { + } else { clg->state = LOST_IN_BURST_PERIOD; return true; } @@ -522,7 +522,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, 1 << get_random_u32_below(8); } - if (unlikely(q->t_len >= sch->limit)) { + if (unlikely(sch->q.qlen >= sch->limit)) { /* re-link segs, so that qdisc_drop_all() frees them all */ skb->next = segs; qdisc_drop_all(skb, sch, to_free); @@ -657,9 +657,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) if (!q->slot_dist) next_delay = q->slot_config.min_delay + - (get_random_u32() * - (q->slot_config.max_delay - - q->slot_config.min_delay) >> 32); + mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, + get_random_u32(), 32); else next_delay = tabledist(q->slot_config.dist_delay, (s32)(q->slot_config.dist_jitter), @@ -825,6 +824,39 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) return 0; } +static int validate_time(const struct nlattr *attr, const char *name, + struct netlink_ext_ack *extack) +{ + if (nla_get_s64(attr) < 0) { + NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); + return -EINVAL; + } + return 0; +} + +static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) +{ + const struct tc_netem_slot *c = nla_data(attr); + + if (c->min_delay < 0 || c->max_delay < 0) { + NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); + return -EINVAL; + } + if (c->min_delay > c->max_delay) { + NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); + return -EINVAL; + } + if (c->dist_delay < 0 || c->dist_jitter < 0) { + NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); + return -EINVAL; + } + if (c->max_packets < 0 || c->max_bytes < 0) { + NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); + return -EINVAL; + } + return 0; +} + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) { const struct tc_netem_slot *c = nla_data(attr); @@ -1038,6 +1070,24 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } + if (tb[TCA_NETEM_SLOT]) { + ret = validate_slot(tb[TCA_NETEM_SLOT], extack); + if (ret) + goto table_free; + } + + if (tb[TCA_NETEM_LATENCY64]) { + ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); + if (ret) + goto table_free; + } + + if (tb[TCA_NETEM_JITTER64]) { + ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); + if (ret) + goto table_free; + } + sch_tree_lock(sch); /* backup q->clg and q->loss_model */ old_clg = q->clg; @@ -1110,11 +1160,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, /* capping jitter to the range acceptable by tabledist() */ q->jitter = min_t(s64, abs(q->jitter), INT_MAX); - if (tb[TCA_NETEM_PRNG_SEED]) + if (tb[TCA_NETEM_PRNG_SEED]) { q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); - else - q->prng.seed = get_random_u64(); - prandom_seed_state(&q->prng.prng_state, q->prng.seed); + prandom_seed_state(&q->prng.prng_state, q->prng.seed); + } unlock: sch_tree_unlock(sch); @@ -1137,6 +1186,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, return -EINVAL; q->loss_model = CLG_RANDOM; + q->prng.seed = get_random_u64(); + prandom_seed_state(&q->prng.prng_state, q->prng.seed); + ret = netem_change(sch, opt, extack); if (ret) pr_info("netem: change failed\n"); diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index 48c5ab8ec143c1..6ca4dd77a29c75 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, bool enqueue = false; if (unlikely(qdisc_qlen(sch) >= sch->limit)) { - q->stats.overlimit++; + WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); goto out; } @@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* If packet is ecn capable, mark it if drop probability * is lower than 10%, else drop it. */ - q->stats.ecn_mark++; + WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); enqueue = true; } @@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (!q->params.dq_rate_estimator) pie_set_enqueue_time(skb); - q->stats.packets_in++; + WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); if (qdisc_qlen(sch) > q->stats.maxq) - q->stats.maxq = qdisc_qlen(sch); + WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); return qdisc_enqueue_tail(skb, sch); } out: - q->stats.dropped++; + WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); q->vars.accu_prob = 0; return qdisc_drop(skb, sch, to_free); } @@ -212,16 +212,14 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, * packet timestamp. */ if (!params->dq_rate_estimator) { - vars->qdelay = now - pie_get_enqueue_time(skb); + WRITE_ONCE(vars->qdelay, + backlog ? now - pie_get_enqueue_time(skb) : 0); if (vars->dq_tstamp != DTIME_INVALID) dtime = now - vars->dq_tstamp; vars->dq_tstamp = now; - if (backlog == 0) - vars->qdelay = 0; - if (dtime == 0) return; @@ -260,11 +258,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, count = count / dtime; if (vars->avg_dq_rate == 0) - vars->avg_dq_rate = count; + WRITE_ONCE(vars->avg_dq_rate, count); else - vars->avg_dq_rate = + WRITE_ONCE(vars->avg_dq_rate, (vars->avg_dq_rate - - (vars->avg_dq_rate >> 3)) + (count >> 3); + (vars->avg_dq_rate >> 3)) + (count >> 3)); /* If the queue has receded below the threshold, we hold * on to the last drain rate calculated, else we reset @@ -369,12 +367,12 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, if (qdelay > (PSCHED_NS2TICKS(250 * NSEC_PER_MSEC))) delta += MAX_PROB / (100 / 2); - vars->prob += delta; + WRITE_ONCE(vars->prob, vars->prob + delta); if (delta > 0) { /* prevent overflow */ if (vars->prob < oldprob) { - vars->prob = MAX_PROB; + WRITE_ONCE(vars->prob, MAX_PROB); /* Prevent normalization error. If probability is at * maximum value already, we normalize it here, and * skip the check to do a non-linear drop in the next @@ -385,7 +383,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, } else { /* prevent underflow */ if (vars->prob > oldprob) - vars->prob = 0; + WRITE_ONCE(vars->prob, 0); } /* Non-linear drop in probability: Reduce drop probability quickly if @@ -394,9 +392,9 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, if (qdelay == 0 && qdelay_old == 0 && update_prob) /* Reduce drop probability to 98.4% */ - vars->prob -= vars->prob / 64; + WRITE_ONCE(vars->prob, vars->prob - vars->prob / 64); - vars->qdelay = qdelay; + WRITE_ONCE(vars->qdelay, qdelay); vars->backlog_old = backlog; /* We restart the measurement cycle if the following conditions are met @@ -493,22 +491,22 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct pie_sched_data *q = qdisc_priv(sch); struct tc_pie_xstats st = { - .prob = q->vars.prob << BITS_PER_BYTE, - .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / + .prob = READ_ONCE(q->vars.prob) << BITS_PER_BYTE, + .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / NSEC_PER_USEC, - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .maxq = q->stats.maxq, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, + .packets_in = READ_ONCE(q->stats.packets_in), + .overlimit = READ_ONCE(q->stats.overlimit), + .maxq = READ_ONCE(q->stats.maxq), + .dropped = READ_ONCE(q->stats.dropped), + .ecn_mark = READ_ONCE(q->stats.ecn_mark), }; /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ - st.dq_rate_estimating = q->params.dq_rate_estimator; + st.dq_rate_estimating = READ_ONCE(q->params.dq_rate_estimator); /* unscale and return dq_rate in bytes per sec */ - if (q->params.dq_rate_estimator) - st.avg_dq_rate = q->vars.avg_dq_rate * + if (st.dq_rate_estimating) + st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; return gnet_stats_copy_app(d, &st, sizeof(st)); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index ea3580d1d19e8f..5348b610530686 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, case RED_PROB_MARK: qdisc_qstats_overlimit(sch); if (!red_use_ecn(q)) { - q->stats.prob_drop++; + WRITE_ONCE(q->stats.prob_drop, + q->stats.prob_drop + 1); goto congestion_drop; } if (INET_ECN_set_ce(skb)) { - q->stats.prob_mark++; + WRITE_ONCE(q->stats.prob_mark, + q->stats.prob_mark + 1); skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); if (!skb) return NET_XMIT_CN | ret; } else if (!red_use_nodrop(q)) { - q->stats.prob_drop++; + WRITE_ONCE(q->stats.prob_drop, + q->stats.prob_drop + 1); goto congestion_drop; } @@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, case RED_HARD_MARK: qdisc_qstats_overlimit(sch); if (red_use_harddrop(q) || !red_use_ecn(q)) { - q->stats.forced_drop++; + WRITE_ONCE(q->stats.forced_drop, + q->stats.forced_drop + 1); goto congestion_drop; } if (INET_ECN_set_ce(skb)) { - q->stats.forced_mark++; + WRITE_ONCE(q->stats.forced_mark, + q->stats.forced_mark + 1); skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); if (!skb) return NET_XMIT_CN | ret; } else if (!red_use_nodrop(q)) { - q->stats.forced_drop++; + WRITE_ONCE(q->stats.forced_drop, + q->stats.forced_drop + 1); goto congestion_drop; } @@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->qstats.backlog += len; sch->q.qlen++; } else if (net_xmit_drop_count(ret)) { - q->stats.pdrop++; + WRITE_ONCE(q->stats.pdrop, + q->stats.pdrop + 1); qdisc_qstats_drop(sch); } return ret; @@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, &hw_stats_request); } - st.early = q->stats.prob_drop + q->stats.forced_drop; - st.pdrop = q->stats.pdrop; - st.marked = q->stats.prob_mark + q->stats.forced_mark; + st.early = READ_ONCE(q->stats.prob_drop) + + READ_ONCE(q->stats.forced_drop); + + st.pdrop = READ_ONCE(q->stats.pdrop); + + st.marked = READ_ONCE(q->stats.prob_mark) + + READ_ONCE(q->stats.forced_mark); return gnet_stats_copy_app(d, &st, sizeof(st)); } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 1871a1c0224d46..ce67826fdf9b6d 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) sfbhash >>= SFB_BUCKET_SHIFT; if (b[hash].qlen < 0xFFFF) - b[hash].qlen++; + WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); b += SFB_NUMBUCKETS; /* next level */ } } @@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, sfbhash >>= SFB_BUCKET_SHIFT; if (b[hash].qlen > 0) - b[hash].qlen--; + WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); b += SFB_NUMBUCKETS; /* next level */ } } @@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) { - b->p_mark = prob_minus(b->p_mark, q->decrement); + WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); } static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) { - b->p_mark = prob_plus(b->p_mark, q->increment); + WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); } static void sfb_zero_all_buckets(struct sfb_sched_data *q) @@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { - if (qlen < b->qlen) - qlen = b->qlen; - totalpm += b->p_mark; - if (prob < b->p_mark) - prob = b->p_mark; + u32 b_qlen = READ_ONCE(b->qlen); + u32 b_mark = READ_ONCE(b->p_mark); + + if (qlen < b_qlen) + qlen = b_qlen; + totalpm += b_mark; + if (prob < b_mark) + prob = b_mark; b++; } *prob_r = prob; @@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (unlikely(sch->q.qlen >= q->limit)) { qdisc_qstats_overlimit(sch); - q->stats.queuedrop++; + WRITE_ONCE(q->stats.queuedrop, + q->stats.queuedrop + 1); goto drop; } @@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (unlikely(minqlen >= q->max)) { qdisc_qstats_overlimit(sch); - q->stats.bucketdrop++; + WRITE_ONCE(q->stats.bucketdrop, + q->stats.bucketdrop + 1); goto drop; } @@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, } if (sfb_rate_limit(skb, q)) { qdisc_qstats_overlimit(sch); - q->stats.penaltydrop++; + WRITE_ONCE(q->stats.penaltydrop, + q->stats.penaltydrop + 1); goto drop; } goto enqueue; @@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, * In either case, we want to start dropping packets. */ if (r < (p_min - SFB_MAX_PROB / 2) * 2) { - q->stats.earlydrop++; + WRITE_ONCE(q->stats.earlydrop, + q->stats.earlydrop + 1); goto drop; } } if (INET_ECN_set_ce(skb)) { - q->stats.marked++; + WRITE_ONCE(q->stats.marked, + q->stats.marked + 1); } else { - q->stats.earlydrop++; + WRITE_ONCE(q->stats.earlydrop, + q->stats.earlydrop + 1); goto drop; } } @@ -408,7 +417,8 @@ enqueue: sch->q.qlen++; increment_qlen(&cb, q); } else if (net_xmit_drop_count(ret)) { - q->stats.childdrop++; + WRITE_ONCE(q->stats.childdrop, + q->stats.childdrop + 1); qdisc_qstats_drop(sch); } return ret; @@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct sfb_sched_data *q = qdisc_priv(sch); struct tc_sfb_xstats st = { - .earlydrop = q->stats.earlydrop, - .penaltydrop = q->stats.penaltydrop, - .bucketdrop = q->stats.bucketdrop, - .queuedrop = q->stats.queuedrop, - .childdrop = q->stats.childdrop, - .marked = q->stats.marked, + .earlydrop = READ_ONCE(q->stats.earlydrop), + .penaltydrop = READ_ONCE(q->stats.penaltydrop), + .bucketdrop = READ_ONCE(q->stats.bucketdrop), + .queuedrop = READ_ONCE(q->stats.queuedrop), + .childdrop = READ_ONCE(q->stats.childdrop), + .marked = READ_ONCE(q->stats.marked), }; st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index a01d17d03bf571..c14f9e2d8dc51a 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -644,7 +644,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, queue = skb_get_queue_mapping(skb); child = q->qdiscs[queue]; - if (unlikely(!child)) + if (unlikely(child == &noop_qdisc)) return qdisc_drop(skb, sch, to_free); if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { @@ -727,7 +727,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, int len; u8 tc; - if (unlikely(!child)) + if (unlikely(child == &noop_qdisc)) return NULL; if (TXTIME_ASSIST_IS_ENABLED(q->flags)) @@ -982,11 +982,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) } if (should_change_schedules(admin, oper, end_time)) { - /* Set things so the next time this runs, the new - * schedule runs. - */ - end_time = sched_base_time(admin); switch_schedules(q, &admin, &oper); + /* After changing schedules, the next entry is the first one + * in the new schedule, with a pre-calculated end_time. + */ + next = list_first_entry(&oper->entries, struct sched_entry, list); + end_time = next->end_time; } next->end_time = end_time; @@ -2213,6 +2214,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, if (!dev_queue) return -EINVAL; + if (!new) + new = &noop_qdisc; + if (dev->flags & IFF_UP) dev_deactivate(dev); @@ -2226,14 +2230,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, *old = q->qdiscs[cl - 1]; if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); - if (new) + if (new != &noop_qdisc) qdisc_refcount_inc(new); - if (*old) + if (*old && *old != &noop_qdisc) qdisc_put(*old); } q->qdiscs[cl - 1] = new; - if (new) + if (new != &noop_qdisc) new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; if (dev->flags & IFF_UP) diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index f5a7d5a3875555..a024c08432471d 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -201,6 +201,7 @@ new_skb: cb->chunk = head_cb->chunk; cb->af = head_cb->af; + cb->encap_port = head_cb->encap_port; } } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e0e626dc79535b..5e9449b0c7907e 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1555,6 +1555,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( /* Tag the variable length parameters. */ chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + if (asoc->state >= SCTP_STATE_ESTABLISHED) { + /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ + if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + } + /* Verify the INIT chunk before processing it. */ err_chunk = NULL; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b3c19210667fbb..98586bcf83cebe 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6997,7 +6997,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, /* See if the user provided enough room for all the data */ num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); - if (len < num_chunks) + if (len < sizeof(struct sctp_authchunks) + num_chunks) return -EINVAL; if (copy_to_user(to, ch->chunks, num_chunks)) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 76284fc538ebdd..b0bba0feef5644 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) if (fragid == LAST_FRAGMENT) { TIPC_SKB_CB(head)->validated = 0; - if (unlikely(!tipc_msg_validate(&head))) + + /* If the reassembled skb has been freed in + * tipc_msg_validate() because of an invalid truesize, + * then head will point to a newly allocated reassembled + * skb, while *headbuf points to freed reassembled skb. + * In such cases, correct *headbuf for freeing the newly + * allocated reassembled skb later. + */ + if (unlikely(!tipc_msg_validate(&head))) { + if (head != *headbuf) + *headbuf = head; goto err; + } + *buf = head; TIPC_SKB_CB(head)->tail = NULL; *headbuf = NULL; diff --git a/net/tls/tls.h b/net/tls/tls.h index a3c5c5a59fda69..718508e923eecf 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -183,6 +183,7 @@ int tls_strp_dev_init(void); void tls_strp_dev_exit(void); void tls_strp_done(struct tls_strparser *strp); +void __tls_strp_done(struct tls_strparser *strp); void tls_strp_stop(struct tls_strparser *strp); int tls_strp_init(struct tls_strparser *strp, struct sock *sk); void tls_strp_data_ready(struct tls_strparser *strp); diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c index ae723cd6af3975..7d85feebdfd931 100644 --- a/net/tls/tls_strp.c +++ b/net/tls/tls_strp.c @@ -623,6 +623,12 @@ void tls_strp_done(struct tls_strparser *strp) WARN_ON(!strp->stopped); cancel_work_sync(&strp->work); + __tls_strp_done(strp); +} + +/* For setup error paths where the strparser was initialized but never armed. */ +void __tls_strp_done(struct tls_strparser *strp) +{ tls_strp_anchor_free(strp); } diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index d86a487065e925..937aa78eed0e40 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -2595,8 +2595,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) void tls_sw_free_resources_rx(struct sock *sk) { struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_rx *ctx; + + ctx = tls_sw_ctx_rx(tls_ctx); tls_sw_release_resources_rx(sk); + __tls_strp_done(&ctx->strp); tls_sw_free_ctx_rx(tls_ctx); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 651c7debe799da..87908ae74efb32 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -3561,15 +3561,15 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) struct bpf_prog *prog; struct sock *sk = v; uid_t uid; - bool slow; int ret; if (v == SEQ_START_TOKEN) return 0; - slow = lock_sock_fast(sk); + lock_sock(sk); + unix_state_lock(sk); - if (unlikely(sk_unhashed(sk))) { + if (unlikely(sock_flag(sk, SOCK_DEAD))) { ret = SEQ_SKIP; goto unlock; } @@ -3579,7 +3579,8 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) prog = bpf_iter_get_info(&meta, false); ret = unix_prog_seq_show(prog, &meta, v, uid); unlock: - unlock_sock_fast(sk, slow); + unix_state_unlock(sk); + release_sock(sk); return ret; } diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c index bca2d86ba97d8d..976e035053e5a7 100644 --- a/net/unix/unix_bpf.c +++ b/net/unix/unix_bpf.c @@ -184,6 +184,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r */ if (!psock->sk_pair) { sk_pair = unix_peer(sk); + if (unlikely(!sk_pair)) + return -EINVAL; + sock_hold(sk_pair); psock->sk_pair = sk_pair; } diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h index 301f5207f0238d..08f5e9334c9e83 100644 --- a/rust/uapi/uapi_helper.h +++ b/rust/uapi/uapi_helper.h @@ -7,3 +7,5 @@ */ #include +#include +#include diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 51ad29940f05ca..2b611bf169dd98 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -837,7 +837,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, } } if (!rc) - crypto_shash_final(shash, digest); + rc = crypto_shash_final(shash, digest); return rc; } diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 619371aa9964dc..8545c7bbc58e3f 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -40,13 +40,6 @@ #define COMPR_CODEC_CAPS_OVERFLOW #endif -/* TODO: - * - add substream support for multiple devices in case of - * SND_DYNAMIC_MINORS is not used - * - Multiple node representation - * driver should be able to register multiple nodes - */ - struct snd_compr_file { unsigned long caps; struct snd_compr_stream stream; diff --git a/sound/core/sound.c b/sound/core/sound.c index df5571d9862955..f3bb0adf37ccec 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -219,9 +219,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) case SNDRV_DEVICE_TYPE_RAWMIDI: case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: case SNDRV_DEVICE_TYPE_PCM_CAPTURE: + if (snd_BUG_ON(!card)) + return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; case SNDRV_DEVICE_TYPE_COMPRESS: if (snd_BUG_ON(!card)) return -EINVAL; + if (dev < 0 || + dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) + return -EINVAL; minor = SNDRV_MINOR(card->number, type + dev); break; default: diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 60398fced046b0..4066b68a102e21 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); #define PFX "sc6000: " #define DRV_NAME "SC-6000" +struct snd_sc6000 { + char __iomem *vport; + char __iomem *vmss_port; + u8 mss_config; + u8 config; + u8 hw_cfg[2]; + bool old_dsp; +}; + /* hardware dependent functions */ /* @@ -204,7 +213,7 @@ static int sc6000_read(char __iomem *vport) } -static int sc6000_write(char __iomem *vport, int cmd) +static int sc6000_write(struct device *devptr, char __iomem *vport, int cmd) { unsigned char val; int loop = 500000; @@ -221,18 +230,19 @@ static int sc6000_write(char __iomem *vport, int cmd) cpu_relax(); } while (loop--); - snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); + dev_err(devptr, "DSP Command (0x%x) timeout.\n", cmd); return -EIO; } -static int sc6000_dsp_get_answer(char __iomem *vport, int command, +static int sc6000_dsp_get_answer(struct device *devptr, + char __iomem *vport, int command, char *data, int data_len) { int len = 0; - if (sc6000_write(vport, command)) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); + if (sc6000_write(devptr, vport, command)) { + dev_err(devptr, "CMD 0x%x: failed!\n", command); return -EIO; } @@ -265,82 +275,86 @@ static int sc6000_dsp_reset(char __iomem *vport) } /* detection and initialization */ -static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) +static int sc6000_hw_cfg_write(struct device *devptr, + char __iomem *vport, const u8 *cfg) { - if (sc6000_write(vport, COMMAND_6C) < 0) { - snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); return -EIO; } - if (sc6000_write(vport, COMMAND_5C) < 0) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); + if (sc6000_write(devptr, vport, COMMAND_5C) < 0) { + dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_5C); return -EIO; } - if (sc6000_write(vport, cfg[0]) < 0) { - snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); + if (sc6000_write(devptr, vport, cfg[0]) < 0) { + dev_err(devptr, "DATA 0x%x: failed!\n", cfg[0]); return -EIO; } - if (sc6000_write(vport, cfg[1]) < 0) { - snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); + if (sc6000_write(devptr, vport, cfg[1]) < 0) { + dev_err(devptr, "DATA 0x%x: failed!\n", cfg[1]); return -EIO; } - if (sc6000_write(vport, COMMAND_C5) < 0) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); + if (sc6000_write(devptr, vport, COMMAND_C5) < 0) { + dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_C5); return -EIO; } return 0; } -static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) +static int sc6000_cfg_write(struct device *devptr, + char __iomem *vport, unsigned char softcfg) { - if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + if (sc6000_write(devptr, vport, WRITE_MDIRQ_CFG)) { + dev_err(devptr, "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); return -EIO; } - if (sc6000_write(vport, softcfg)) { - snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + if (sc6000_write(devptr, vport, softcfg)) { + dev_err(devptr, "%s: failed!\n", __func__); return -EIO; } return 0; } -static int sc6000_setup_board(char __iomem *vport, int config) +static int sc6000_setup_board(struct device *devptr, + char __iomem *vport, int config) { int loop = 10; do { - if (sc6000_write(vport, COMMAND_88)) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", - COMMAND_88); + if (sc6000_write(devptr, vport, COMMAND_88)) { + dev_err(devptr, "CMD 0x%x: failed!\n", + COMMAND_88); return -EIO; } } while ((sc6000_wait_data(vport) < 0) && loop--); if (sc6000_read(vport) < 0) { - snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", - COMMAND_88); + dev_err(devptr, "sc6000_read after CMD 0x%x: failed\n", + COMMAND_88); return -EIO; } - if (sc6000_cfg_write(vport, config)) + if (sc6000_cfg_write(devptr, vport, config)) return -ENODEV; return 0; } -static int sc6000_init_mss(char __iomem *vport, int config, +static int sc6000_init_mss(struct device *devptr, + char __iomem *vport, int config, char __iomem *vmss_port, int mss_config) { - if (sc6000_write(vport, DSP_INIT_MSS)) { - snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", - DSP_INIT_MSS); + if (sc6000_write(devptr, vport, DSP_INIT_MSS)) { + dev_err(devptr, "%s [0x%x]: failed!\n", __func__, + DSP_INIT_MSS); return -EIO; } msleep(10); - if (sc6000_cfg_write(vport, config)) + if (sc6000_cfg_write(devptr, vport, config)) return -EIO; iowrite8(mss_config, vmss_port); @@ -348,7 +362,7 @@ static int sc6000_init_mss(char __iomem *vport, int config, return 0; } -static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, +static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, long xport, long xmpu, long xmss_port, int joystick) { @@ -367,31 +381,88 @@ static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, cfg[0] |= 0x02; cfg[1] |= 0x80; /* enable WSS system */ cfg[1] &= ~0x40; /* disable IDE */ - snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); +} + +static void sc6000_prepare_board(struct device *devptr, + struct snd_sc6000 *sc6000, + unsigned int dev, int xirq, int xdma) +{ + sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | + sc6000_dma_to_softcfg(xdma); + sc6000->config = sc6000->mss_config | + sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], + mss_port[dev], joystick[dev]); } -static int sc6000_init_board(char __iomem *vport, - char __iomem *vmss_port, int dev) +static void sc6000_detect_old_dsp(struct device *devptr, + struct snd_sc6000 *sc6000) +{ + sc6000_write(devptr, sc6000->vport, COMMAND_5C); + sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; +} + +static int sc6000_program_board(struct device *devptr, + struct snd_sc6000 *sc6000) +{ + int err; + + if (!sc6000->old_dsp) { + if (sc6000_hw_cfg_write(devptr, sc6000->vport, + sc6000->hw_cfg) < 0) { + dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); + return -EIO; + } + } + + err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); + if (err < 0) { + dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + sc6000_dsp_reset(sc6000->vport); + + if (!sc6000->old_dsp) { + sc6000_write(devptr, sc6000->vport, COMMAND_60); + sc6000_write(devptr, sc6000->vport, 0x02); + sc6000_dsp_reset(sc6000->vport); + } + + err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); + if (err < 0) { + dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, + sc6000->vmss_port, sc6000->mss_config); + if (err < 0) { + dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); + return -ENODEV; + } + + return 0; +} + +static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) { char answer[15]; char version[2]; - int mss_config = sc6000_irq_to_softcfg(irq[dev]) | - sc6000_dma_to_softcfg(dma[dev]); - int config = mss_config | - sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); int err; - int old = 0; - err = sc6000_dsp_reset(vport); + err = sc6000_dsp_reset(sc6000->vport); if (err < 0) { - snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); return err; } memset(answer, 0, sizeof(answer)); - err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); + err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, + answer, 15); if (err <= 0) { - snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); return -ENODEV; } /* @@ -399,56 +470,19 @@ static int sc6000_init_board(char __iomem *vport, * if we have something different, we have to be warned. */ if (strncmp("SC-6000", answer, 7)) - snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); - if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { - snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); + if (sc6000_dsp_get_answer(devptr, sc6000->vport, + GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); return -ENODEV; } - printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", answer, version[0], version[1]); - /* set configuration */ - sc6000_write(vport, COMMAND_5C); - if (sc6000_read(vport) < 0) - old = 1; - - if (!old) { - int cfg[2]; - sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], - mss_port[dev], joystick[dev]); - if (sc6000_hw_cfg_write(vport, cfg) < 0) { - snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); - return -EIO; - } - } - err = sc6000_setup_board(vport, config); - if (err < 0) { - snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); - return -ENODEV; - } - - sc6000_dsp_reset(vport); - - if (!old) { - sc6000_write(vport, COMMAND_60); - sc6000_write(vport, 0x02); - sc6000_dsp_reset(vport); - } + sc6000_detect_old_dsp(devptr, sc6000); - err = sc6000_setup_board(vport, config); - if (err < 0) { - snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); - return -ENODEV; - } - err = sc6000_init_mss(vport, config, vmss_port, mss_config); - if (err < 0) { - snd_printk(KERN_ERR "Cannot initialize " - "Microsoft Sound System mode.\n"); - return -ENODEV; - } - - return 0; + return sc6000_program_board(devptr, sc6000); } static int snd_sc6000_mixer(struct snd_wss *chip) @@ -491,39 +525,39 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) if (!enable[dev]) return 0; if (port[dev] == SNDRV_AUTO_PORT) { - printk(KERN_ERR PFX "specify IO port\n"); + dev_err(devptr, "specify IO port\n"); return 0; } if (mss_port[dev] == SNDRV_AUTO_PORT) { - printk(KERN_ERR PFX "specify MSS port\n"); + dev_err(devptr, "specify MSS port\n"); return 0; } if (port[dev] != 0x220 && port[dev] != 0x240) { - printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); + dev_err(devptr, "Port must be 0x220 or 0x240\n"); return 0; } if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { - printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); + dev_err(devptr, "MSS port must be 0x530 or 0xe80\n"); return 0; } if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { - printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); + dev_err(devptr, "invalid IRQ %d\n", irq[dev]); return 0; } if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { - printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); + dev_err(devptr, "invalid DMA %d\n", dma[dev]); return 0; } if (mpu_port[dev] != SNDRV_AUTO_PORT && (mpu_port[dev] & ~0x30L) != 0x300) { - printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", + dev_err(devptr, "invalid MPU-401 port %lx\n", mpu_port[dev]); return 0; } if (mpu_port[dev] != SNDRV_AUTO_PORT && mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { - printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + dev_err(devptr, "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); return 0; } return 1; @@ -531,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) static void snd_sc6000_free(struct snd_card *card) { - char __iomem *vport = (char __force __iomem *)card->private_data; + struct snd_sc6000 *sc6000 = card->private_data; - if (vport) - sc6000_setup_board(vport, 0); + if (sc6000->vport) + sc6000_setup_board(card->dev, sc6000->vport, 0); } static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) @@ -545,20 +579,22 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) int xirq = irq[dev]; int xdma = dma[dev]; struct snd_card *card; + struct snd_sc6000 *sc6000; struct snd_wss *chip; struct snd_opl3 *opl3; char __iomem *vport; char __iomem *vmss_port; err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, - 0, &card); + sizeof(*sc6000), &card); if (err < 0) return err; + sc6000 = card->private_data; if (xirq == SNDRV_AUTO_IRQ) { xirq = snd_legacy_find_free_irq(possible_irqs); if (xirq < 0) { - snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + dev_err(devptr, "unable to find a free IRQ\n"); return -EBUSY; } } @@ -566,42 +602,42 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) if (xdma == SNDRV_AUTO_DMA) { xdma = snd_legacy_find_free_dma(possible_dmas); if (xdma < 0) { - snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); + dev_err(devptr, "unable to find a free DMA\n"); return -EBUSY; } } if (!devm_request_region(devptr, port[dev], 0x10, DRV_NAME)) { - snd_printk(KERN_ERR PFX - "I/O port region is already in use.\n"); + dev_err(devptr, "I/O port region is already in use.\n"); return -EBUSY; } vport = devm_ioport_map(devptr, port[dev], 0x10); if (!vport) { - snd_printk(KERN_ERR PFX - "I/O port cannot be iomapped.\n"); + dev_err(devptr, "I/O port cannot be iomapped.\n"); return -EBUSY; } - card->private_data = (void __force *)vport; + sc6000->vport = vport; /* to make it marked as used */ if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { - snd_printk(KERN_ERR PFX - "SC-6000 port I/O port region is already in use.\n"); + dev_err(devptr, + "SC-6000 port I/O port region is already in use.\n"); return -EBUSY; } vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); if (!vmss_port) { - snd_printk(KERN_ERR PFX - "MSS port I/O cannot be iomapped.\n"); + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); return -EBUSY; } + sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); - snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", - port[dev], xirq, xdma, - mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); - err = sc6000_init_board(vport, vmss_port, dev); + err = sc6000_init_board(devptr, sc6000); if (err < 0) return err; card->private_free = snd_sc6000_free; @@ -613,25 +649,24 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) err = snd_wss_pcm(chip, 0); if (err < 0) { - snd_printk(KERN_ERR PFX - "error creating new WSS PCM device\n"); + dev_err(devptr, "error creating new WSS PCM device\n"); return err; } err = snd_wss_mixer(chip); if (err < 0) { - snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); + dev_err(devptr, "error creating new WSS mixer\n"); return err; } err = snd_sc6000_mixer(chip); if (err < 0) { - snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); + dev_err(devptr, "the mixer rewrite failed\n"); return err; } if (snd_opl3_create(card, 0x388, 0x388 + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", - 0x388, 0x388 + 2); + dev_err(devptr, "no OPL device at 0x%x-0x%x ?\n", + 0x388, 0x388 + 2); } else { err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); if (err < 0) @@ -645,8 +680,8 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) MPU401_HW_MPU401, mpu_port[dev], 0, mpu_irq[dev], NULL) < 0) - snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", - mpu_port[dev]); + dev_err(devptr, "no MPU-401 device at 0x%lx ?\n", + mpu_port[dev]); } strcpy(card->driver, DRV_NAME); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 355b26583eb4e7..f6e563e03edf2d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -42,7 +42,7 @@ struct conexant_spec { unsigned int gpio_led; unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; - bool is_cx8070_sn6140; + bool is_cx11880_sn6140; }; @@ -166,18 +166,18 @@ static void cxt_init_gpio_led(struct hda_codec *codec) static void cx_fixup_headset_recog(struct hda_codec *codec) { - unsigned int mic_persent; + unsigned int mic_present; /* fix some headset type recognize fail issue, such as EDIFIER headset */ - /* set micbiasd output current comparator threshold from 66% to 55%. */ + /* set micbias output current comparator threshold from 66% to 55%. */ snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); - /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor + /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register * value adjustment trim from 2.2K ohms to 2.0K ohms. */ snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); /* fix reboot headset type recognize fail issue */ - mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); - if (mic_persent & AC_PINSENSE_PRESENCE) + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (mic_present & AC_PINSENSE_PRESENCE) /* enable headset mic VREF */ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); else @@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) cxt_init_gpio_led(codec); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); - if (spec->is_cx8070_sn6140) + if (spec->is_cx11880_sn6140) cx_fixup_headset_recog(codec); return 0; @@ -247,9 +247,9 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ { unsigned int mic_present; - /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, - * the node 19 can only be config to microphone or disabled. - * Check hp&mic tag to process headset pulgin&plugout. + /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. */ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ @@ -1186,6 +1186,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) static int patch_conexant_auto(struct hda_codec *codec) { struct conexant_spec *spec; + struct hda_jack_callback *callback; int err; codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); @@ -1197,12 +1198,17 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = cx_auto_patch_ops; - /* init cx8070/sn6140 flag and reset headset_present_flag */ + /* init cx11880/sn6140 flag and reset headset_present_flag */ switch (codec->core.vendor_id) { case 0x14f11f86: case 0x14f11f87: - spec->is_cx8070_sn6140 = true; - snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + spec->is_cx11880_sn6140 = true; + callback = snd_hda_jack_detect_enable_callback(codec, 0x19, + cx_update_headset_mic_vref); + if (IS_ERR(callback)) { + err = PTR_ERR(callback); + goto error; + } break; } @@ -1289,7 +1295,7 @@ static int patch_conexant_auto(struct hda_codec *codec) */ static const struct hda_device_id snd_hda_id_conexant[] = { - HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ef859f59f8d10..937f3fdbab252c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6043,9 +6043,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, struct alc_spec *spec = codec->spec; spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; alc255_set_default_jack_type(codec); - } - else + } else { alc_fixup_headset_mode(codec, fix, action); + } } static void alc288_update_headset_jack_cb(struct hda_codec *codec, diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 68342917419e4e..42e448978c4a0d 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) return status; } fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; drvdata->anc_fir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; drvdata->anc_iir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; drvdata->sid_fir_values = (long *)fc->value; snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index c78abf7698e0f7..16aa0063aa65ce 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, unsigned int regval = ucontrol->value.integer.value[0]; int ret; + if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) + return -EINVAL; + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); easrc_priv->bps_iec958[mc->regbase] = regval; @@ -70,8 +73,16 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; - ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; + ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; +} +static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; return 0; } @@ -81,11 +92,33 @@ static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; - unsigned int regval; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); + unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; + int ret; + + ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); + if (ret) + return ret; - regval = snd_soc_component_read(component, mc->regbase); + ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); + if (ret) + return ret; + + ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); + if (ret) + return ret; + + ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); + if (ret) + return ret; + + ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); + if (ret) + return ret; - ucontrol->value.integer.value[0] = regval; + ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); + if (ret) + return ret; return 0; } @@ -97,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); - unsigned int regval = ucontrol->value.integer.value[0]; - bool changed; + unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; + bool changed, changed_all = false; int ret; - ret = regmap_update_bits_check(easrc->regmap, mc->regbase, - GENMASK(31, 0), regval, &changed); - if (ret != 0) + ret = pm_runtime_resume_and_get(component->dev); + if (ret) return ret; - return changed; + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), + GENMASK(31, 0), regval[0], &changed); + if (ret != 0) + goto err; + changed_all |= changed; + + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), + GENMASK(31, 0), regval[1], &changed); + if (ret != 0) + goto err; + changed_all |= changed; + + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), + GENMASK(31, 0), regval[2], &changed); + if (ret != 0) + goto err; + changed_all |= changed; + + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), + GENMASK(31, 0), regval[3], &changed); + if (ret != 0) + goto err; + changed_all |= changed; + + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), + GENMASK(31, 0), regval[4], &changed); + if (ret != 0) + goto err; + changed_all |= changed; + + ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), + GENMASK(31, 0), regval[5], &changed); + if (ret != 0) + goto err; + changed_all |= changed; +err: + pm_runtime_put_autosuspend(component->dev); + + if (ret != 0) + return ret; + else + return changed_all; } #define SOC_SINGLE_REG_RW(xname, xreg) \ { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ + .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ .put = fsl_easrc_set_reg, \ .private_value = (unsigned long)&(struct soc_mreg_control) \ { .regbase = xreg, .regcount = 1, .nbits = 32, \ @@ -143,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), - SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), - SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), - SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), - SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), + SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), + SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), + SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), + SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), }; /* diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 80ff1d1359f64c..189f65989fcfe1 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -181,10 +181,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, { struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); + int val = ucontrol->value.integer.value[0]; + bool change = false; + int old_val; + int ret; + + if (val < QUALITY_HIGH || val > QUALITY_VLOW2) + return -EINVAL; + + if (micfil->quality != val) { + ret = pm_runtime_resume_and_get(cmpnt->dev); + if (ret) + return ret; + + old_val = micfil->quality; + micfil->quality = val; + ret = micfil_set_quality(micfil); - micfil->quality = ucontrol->value.integer.value[0]; + pm_runtime_put_autosuspend(cmpnt->dev); - return micfil_set_quality(micfil); + if (ret) { + micfil->quality = old_val; + return ret; + } + + change = true; + } + + return change; } static const char * const micfil_hwvad_enable[] = { @@ -243,6 +267,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, if (val < 0 || val > 3) return -EINVAL; + ret = pm_runtime_resume_and_get(comp->dev); + if (ret) + return ret; + micfil->dc_remover = val; /* Calculate total value for all channels */ @@ -252,10 +280,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, /* Update DC Remover mode for all channels */ ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, MICFIL_DC_CTRL_CONFIG, reg_val); - if (ret < 0) - return ret; - return 0; + pm_runtime_put_autosuspend(comp->dev); + + return ret; } static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, @@ -277,10 +305,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol, unsigned int *item = ucontrol->value.enumerated.item; struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); int val = snd_soc_enum_item_to_val(e, item[0]); + bool change = false; + if (val < 0 || val > 1) + return -EINVAL; + + change = (micfil->vad_enabled != val); micfil->vad_enabled = val; - return 0; + return change; } static int hwvad_get_enable(struct snd_kcontrol *kcontrol, @@ -302,13 +335,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, unsigned int *item = ucontrol->value.enumerated.item; struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); int val = snd_soc_enum_item_to_val(e, item[0]); + bool change = false; + + if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE) + return -EINVAL; /* 0 - Envelope-based Mode * 1 - Energy-based Mode */ + change = (micfil->vad_init_mode != val); micfil->vad_init_mode = val; - return 0; + return change; } static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, @@ -395,7 +433,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), SOC_SINGLE("HWVAD ZCD And Behavior Switch", REG_MICFIL_VAD0_ZCD, 4, 1, 0), - SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .name = "VAD Detected", + .info = snd_soc_info_bool_ext, + .get = hwvad_detected, + }, }; static int fsl_micfil_use_verid(struct device *dev) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 90a0a24c05d845..d6aa9c30978f40 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -98,10 +98,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int *item = ucontrol->value.enumerated.item; + int val = snd_soc_enum_item_to_val(e, item[0]); + int ret; - xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); + if (val < 0 || val > 1) + return -EINVAL; - return 0; + ret = (xcvr->arc_mode != val); + + xcvr->arc_mode = val; + + return ret; } static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, @@ -201,10 +208,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int *item = ucontrol->value.enumerated.item; + int val = snd_soc_enum_item_to_val(e, item[0]); struct snd_soc_card *card = dai->component->card; struct snd_soc_pcm_runtime *rtd; + int ret; + + if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) + return -EINVAL; - xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); + ret = (xcvr->mode != val); + + xcvr->mode = val; fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, (xcvr->mode == FSL_XCVR_MODE_ARC)); @@ -214,7 +228,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, rtd = snd_soc_get_pcm_runtime(card, card->dai_link); rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); - return 0; + return ret; } static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c index d4c3bc85fb3562..51d1926ea3c2b0 100644 --- a/sound/soc/qcom/qdsp6/topology.c +++ b/sound/soc/qcom/qdsp6/topology.c @@ -903,9 +903,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, struct audioreach_container *cont; struct audioreach_module *mod; - mod = dobj->private; - cont = mod->container; - if (w->id == snd_soc_dapm_mixer) { /* virtual widget */ struct snd_ar_control *scontrol = dobj->private; @@ -914,6 +911,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, kfree(scontrol); return 0; } + mod = dobj->private; + if (!mod) + return 0; + + cont = mod->container; mutex_lock(&apm->lock); idr_remove(&apm->modules_idr, mod->instance_id); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3cd14fbca28eae..68f91fc5434933 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1995,7 +1995,7 @@ static int rsnd_probe(struct platform_device *pdev) * asoc register */ ci = 0; - for (i = 0; priv->component_dais[i] > 0; i++) { + for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) { int nr = priv->component_dais[i]; ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c index c469bb706e4a49..b64a5d99fe6084 100644 --- a/sound/soc/sof/compress.c +++ b/sound/soc/sof/compress.c @@ -247,6 +247,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, sstream->sampling_rate = params->codec.sample_rate; sstream->channels = params->codec.ch_out; sstream->sample_container_bytes = pcm->params.sample_container_bytes; + sstream->codec_params = params->codec; spcm->prepared[cstream->direction] = true; @@ -259,9 +260,10 @@ out: static int sof_compr_get_params(struct snd_soc_component *component, struct snd_compr_stream *cstream, struct snd_codec *params) { - /* TODO: we don't query the supported codecs for now, if the - * application asks for an unsupported codec the set_params() will fail. - */ + struct sof_compr_stream *sstream = cstream->runtime->private_data; + + *params = sstream->codec_params; + return 0; } diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 19ec1a45737eac..a3d0b6d721aaf6 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -77,18 +77,29 @@ static const struct hda_dai_widget_dma_ops * hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); - struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_widget *swidget; struct snd_sof_dev *sdev; struct snd_sof_dai *sdai; - sdev = widget_to_sdev(w); - /* - * The swidget parameter of hda_select_dai_widget_ops() is ignored in - * case of DSPless mode + * this is unlikely if the topology and the machine driver DAI links match. + * But if there's a missing DAI link in topology, this will prevent a NULL pointer + * dereference later on. */ + if (!w) { + dev_err(cpu_dai->dev, "%s: widget is NULL\n", __func__); + return NULL; + } + + sdev = widget_to_sdev(w); + swidget = w->dobj.private; + if (!swidget) { + dev_err(sdev->dev, "%s: swidget is NULL\n", __func__); + return NULL; + } + if (sdev->dspless_mode_selected) - return hda_select_dai_widget_ops(sdev, NULL); + return hda_select_dai_widget_ops(sdev, swidget); sdai = swidget->private; @@ -368,8 +379,11 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, return ret; } - /* get stream_id */ sdev = widget_to_sdev(w); + if (sdev->dspless_mode_selected) + goto skip_tlv; + + /* get stream_id */ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); if (!hext_stream) { @@ -402,6 +416,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ dma_config->dma_priv_config_size = 0; +skip_tlv: return 0; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3bb743cb167a5b..924cef8d96c605 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -415,16 +415,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params) { - struct hdac_stream *hstream = &hext_stream->hstream; - int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + struct hdac_stream *hstream; + int sd_offset; int ret; - u32 mask = 0x1 << hstream->index; + u32 mask; if (!hext_stream) { dev_err(sdev->dev, "error: no stream available\n"); return -ENODEV; } + hstream = &hext_stream->hstream; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + mask = 0x1 << hstream->index; + if (!dmab) { dev_err(sdev->dev, "error: no dma buffer allocated!\n"); return -ENODEV; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d4f6702e93dcb8..6bf461506ce37c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -119,6 +120,7 @@ struct sof_compr_stream { u32 sampling_rate; u16 channels; u16 sample_container_bytes; + struct snd_codec codec_params; size_t posn_offset; }; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 6d1ce030963c62..45d35b887e4ebf 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -1028,8 +1028,13 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, return PTR_ERR(regmap); } - player->clk_sel = regmap_field_alloc(regmap, regfield[0]); - player->valid_sel = regmap_field_alloc(regmap, regfield[1]); + player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + + player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); return 0; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index fdf69917d19cc8..c2f63d0c6c33a8 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1974,15 +1974,17 @@ static struct usb_ms_endpoint_descriptor *find_usb_ms_endpoint_descriptor( while (extralen > 3) { struct usb_ms_endpoint_descriptor *ms_ep = (struct usb_ms_endpoint_descriptor *)extra; + int length = ms_ep->bLength; - if (ms_ep->bLength > 3 && + if (!length || length > extralen) + break; + + if (length > 3 && ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT && ms_ep->bDescriptorSubtype == UAC_MS_GENERAL) return ms_ep; - if (!extra[0]) - break; - extralen -= extra[0]; - extra += extra[0]; + extralen -= length; + extra += length; } return NULL; } diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 9e183d9d1b09bf..42a82aad8a3be8 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -504,15 +504,17 @@ static void *find_usb_ms_endpoint_descriptor(struct usb_host_endpoint *hostep, while (extralen > 3) { struct usb_ms_endpoint_descriptor *ms_ep = (struct usb_ms_endpoint_descriptor *)extra; + int length = ms_ep->bLength; - if (ms_ep->bLength > 3 && + if (!length || length > extralen) + break; + + if (length > 3 && ms_ep->bDescriptorType == USB_DT_CS_ENDPOINT && ms_ep->bDescriptorSubtype == subtype) return ms_ep; - if (!extra[0]) - break; - extralen -= extra[0]; - extra += extra[0]; + extralen -= length; + extra += length; } return NULL; } diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index c4b29b3670cd4b..8aa7414d0b2fa8 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -1011,7 +1011,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, /* End of list */ - { 0, NULL }, + { 0, NULL, NULL }, }; /* get the starting port index number for a given port type/direction */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 847878438b8b75..ed625d5bbe9ab0 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, snd_usb_audioformat_set_sync_ep(chip, fp); - err = snd_usb_add_audio_stream(chip, stream, fp); + err = snd_usb_add_audio_stream(chip, stream, fp, NULL); if (err < 0) return err; diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 920a718f91e687..f964082da3a63e 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) static void snd_usb_init_substream(struct snd_usb_stream *as, int stream, struct audioformat *fp, - struct snd_usb_power_domain *pd) + struct snd_usb_power_domain **pdptr) { struct snd_usb_substream *subs = &as->substream[stream]; @@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, if (fp->channels > subs->channels_max) subs->channels_max = fp->channels; - if (pd) { - subs->str_pd = pd; + if (pdptr && *pdptr) { + subs->str_pd = *pdptr; + *pdptr = NULL; /* assigned */ /* Initialize Power Domain to idle status D1 */ - snd_usb_power_domain_set(subs->stream->chip, pd, + snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, UAC3_PD_STATE_D1); } @@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor * if not, create a new pcm stream. note, fp is added to the substream * fmt_list and will be freed on the chip instance release. do not free * fp or do remove it from the substream fmt_list to avoid double-free. + * + * pdptr is optional and can be NULL. When it's non-NULL and the PD gets + * assigned to the stream, *pdptr is cleared to NULL upon return. */ -static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp, - struct snd_usb_power_domain *pd) +int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp, + struct snd_usb_power_domain **pdptr) { struct snd_usb_stream *as; @@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) return err; - snd_usb_init_substream(as, stream, fp, pd); + snd_usb_init_substream(as, stream, fp, pdptr); return add_chmap(as->pcm, stream, subs); } @@ -551,7 +555,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, else strcpy(pcm->name, "USB Audio"); - snd_usb_init_substream(as, stream, fp, pd); + snd_usb_init_substream(as, stream, fp, pdptr); /* * Keep using head insertion for M-Audio Audiophile USB (tm) which has a @@ -569,21 +573,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, return add_chmap(pcm, stream, &as->substream[stream]); } -int snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp) -{ - return __snd_usb_add_audio_stream(chip, stream, fp, NULL); -} - -static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp, - struct snd_usb_power_domain *pd) -{ - return __snd_usb_add_audio_stream(chip, stream, fp, pd); -} - static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, struct usb_host_interface *alts, int protocol, int iface_no) @@ -1102,8 +1091,7 @@ found_clock: } } - if (pd) - *pd_out = pd; + *pd_out = pd; return fp; } @@ -1118,7 +1106,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, struct usb_interface_descriptor *altsd; int i, altno, err, stream; struct audioformat *fp = NULL; - struct snd_usb_power_domain *pd = NULL; bool set_iface_first; int num, protocol; @@ -1160,6 +1147,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) continue; + /* pd may be allocated at snd_usb_get_audioformat_uac3() and + * assigned at snd_usb_add_audio_stream(); otherwise it'll be + * freed automatically by cleanup at each loop. + */ + struct snd_usb_power_domain *pd __free(kfree) = NULL; + /* * Roland audio streaming interfaces are marked with protocols * 0/1/2, but are UAC 1 compatible. @@ -1215,23 +1208,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, *has_non_pcm = true; if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { audioformat_free(fp); - kfree(pd); fp = NULL; - pd = NULL; continue; } snd_usb_audioformat_set_sync_ep(chip, fp); dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); - if (protocol == UAC_VERSION_3) - err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); - else - err = snd_usb_add_audio_stream(chip, stream, fp); - + err = snd_usb_add_audio_stream(chip, stream, fp, &pd); if (err < 0) { audioformat_free(fp); - kfree(pd); return err; } diff --git a/sound/usb/stream.h b/sound/usb/stream.h index d92e18d5818fee..61b9a133da018a 100644 --- a/sound/usb/stream.h +++ b/sound/usb/stream.h @@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int snd_usb_add_audio_stream(struct snd_usb_audio *chip, int stream, - struct audioformat *fp); + struct audioformat *fp, + struct snd_usb_power_domain **pdptr); #endif /* __USBAUDIO_STREAM_H */ diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 2e064a1032a050..8967952de0c2ee 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1344,6 +1344,8 @@ enum { #define BPF_F_TEST_RUN_ON_CPU (1U << 0) /* If set, XDP frames will be transmitted after processing */ #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) +/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ +#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) /* type for BPF_ENABLE_STATS */ enum bpf_stats_type { diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c index 63a4d5ad12d1a3..04c8febfc0aa73 100644 --- a/tools/lib/bpf/relo_core.c +++ b/tools/lib/bpf/relo_core.c @@ -293,6 +293,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, ++spec_str; if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) return -EINVAL; + if (access_idx < 0) + return -EINVAL; if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) return -E2BIG; spec_str += parsed_len; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index bd24ed0af208a1..bd294fd574972f 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -2271,7 +2271,7 @@ static int parse_map_entry(const struct option *opt, const char *str, static int parse_max_stack(const struct option *opt, const char *str, int unset __maybe_unused) { - unsigned long *len = (unsigned long *)opt->value; + int *len = opt->value; long val; char *endptr; diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h index e41bfffe22170b..31ad6ded983ec9 100644 --- a/tools/perf/util/branch.h +++ b/tools/perf/util/branch.h @@ -64,6 +64,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl { u64 *entry = (u64 *)sample->branch_stack; + if (entry == NULL) + return NULL; + entry++; if (sample->no_hw_idx) return (struct branch_entry *)entry; diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index e917985bbbe6d7..640e383cef441c 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, (void *)decoder, cs_etm_decoder__print_str_cb); if (ret != 0) - ret = -1; - - return 0; -} + return -1; #ifdef CS_LOG_RAW_FRAMES -static void -cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, - struct cs_etm_decoder *decoder) -{ - /* Only log these during a --dump operation */ - if (d_params->operation == CS_ETM_OPERATION_PRINT) { - /* set up a library default logger to process the - * raw frame printer we add later - */ - ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); - - /* no stdout / err / file output */ - ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); - - /* set the string CB for the default logger, - * passes strings to perf print logger. - */ - ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, - (void *)decoder, - cs_etm_decoder__print_str_cb); - + /* + * Only log raw frames if --dump operation and hardware is actually + * generating formatted CoreSight trace frames + */ + if ((d_params->operation == CS_ETM_OPERATION_PRINT) && + (d_params->formatted == true)) { /* use the built in library printer for the raw frames */ - ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, - CS_RAW_DEBUG_FLAGS); + ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, + CS_RAW_DEBUG_FLAGS); + if (ret != 0) + return -1; } -} -#else -static void -cs_etm_decoder__init_raw_frame_logging( - struct cs_etm_decoder_params *d_params __maybe_unused, - struct cs_etm_decoder *decoder __maybe_unused) -{ -} #endif + return 0; +} static ocsd_datapath_resp_t cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, @@ -755,9 +733,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, if (ret != 0) goto err_free_decoder; - /* init raw frame logging if required */ - cs_etm_decoder__init_raw_frame_logging(d_params, decoder); - for (i = 0; i < decoders; i++) { ret = cs_etm_decoder__create_etm_decoder(d_params, &t_params[i], diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index fa0473f7a4ff45..d952ce37c873bf 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -377,7 +377,8 @@ int expr__find_ids(const char *expr, const char *one, if (one) expr__del_id(ctx, one); - return ret; + /* A positive value means syntax error, convert to -EINVAL */ + return ret > 0 ? -EINVAL : ret; } double expr_id_data__value(const struct expr_id_data *data) diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 7c8915d92dca20..d49f66a986ae75 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -25,7 +25,6 @@ extern bool perf_guest; /* General helper functions */ void usage(const char *err) __noreturn; -void die(const char *err, ...) __noreturn __printf(1, 2); struct dirent; struct strlist; diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index e93ac83270dad1..d78d5f3b0a55e8 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -98,6 +98,7 @@ my $test_type; my $build_type; my $build_options; my $final_post_ktest; +my $post_ktest_done = 0; my $pre_ktest; my $post_ktest; my $pre_test; @@ -1537,6 +1538,24 @@ sub get_test_name() { return $name; } +sub run_post_ktest { + my $cmd; + + return if ($post_ktest_done); + + if (defined($final_post_ktest)) { + $cmd = $final_post_ktest; + } elsif (defined($post_ktest)) { + $cmd = $post_ktest; + } else { + return; + } + + my $cp_post_ktest = eval_kernel_version($cmd); + run_command $cp_post_ktest; + $post_ktest_done = 1; +} + sub dodie { # avoid recursion return if ($in_die); @@ -1596,6 +1615,7 @@ sub dodie { if (defined($post_test)) { run_command $post_test; } + run_post_ktest; die @_, "\n"; } @@ -2472,7 +2492,7 @@ sub check_buildlog { my $save_no_reboot = $no_reboot; $no_reboot = 1; - if (-f $warnings_file) { + if (defined($warnings_file) && -f $warnings_file) { open(IN, $warnings_file) or dodie "Error opening $warnings_file"; @@ -4113,7 +4133,8 @@ sub __set_test_option { my $option = "$name\[$i\]"; - if (option_defined($option)) { + if (exists($opt{$option})) { + return undef if (!option_defined($option)); return $opt{$option}; } @@ -4121,7 +4142,8 @@ sub __set_test_option { if ($i >= $test && $i < $test + $repeat_tests{$test}) { $option = "$name\[$test\]"; - if (option_defined($option)) { + if (exists($opt{$option})) { + return undef if (!option_defined($option)); return $opt{$option}; } } @@ -4228,6 +4250,7 @@ sub cancel_test { send_email("KTEST: Your [$name] test was cancelled", "Your test started at $script_start_time was cancelled: sig int"); } + run_post_ktest; die "\nCaught Sig Int, test interrupted: $!\n" } @@ -4538,11 +4561,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { success $i; } -if (defined($final_post_ktest)) { - - my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; - run_command $cp_final_post_ktest; -} +run_post_ktest; if ($opt{"POWEROFF_ON_SUCCESS"}) { halt; diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c index 4be6fdb78c6a12..20a3c622bd28a1 100644 --- a/tools/testing/selftests/bpf/prog_tests/snprintf.c +++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c @@ -114,7 +114,8 @@ static void test_snprintf_negative(void) ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); - ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); + ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); + ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); } diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c index b462416b380612..6efa26a8383e10 100644 --- a/tools/testing/selftests/cgroup/test_memcontrol.c +++ b/tools/testing/selftests/cgroup/test_memcontrol.c @@ -940,8 +940,11 @@ static int tcp_server(const char *cgroup, void *arg) saddr.sin6_port = htons(srv_args->port); sk = socket(AF_INET6, SOCK_STREAM, 0); - if (sk < 0) + if (sk < 0) { + /* Pass back errno to the ctl_fd */ + write(ctl_fd, &errno, sizeof(errno)); return ret; + } if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) goto cleanup; @@ -1071,6 +1074,12 @@ static int test_memcg_sock(const char *root) goto cleanup; close(args.ctl[0]); + /* Skip if address family not supported by protocol */ + if (err == EAFNOSUPPORT) { + ret = KSFT_SKIP; + goto cleanup; + } + if (!err) break; if (err != EADDRINUSE) diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c index 6908569ef4065d..877ee32d04c82f 100644 --- a/tools/testing/selftests/mm/migration.c +++ b/tools/testing/selftests/mm/migration.c @@ -33,7 +33,8 @@ FIXTURE_SETUP(migration) { int n; - ASSERT_EQ(numa_available(), 0); + if (numa_available() < 0) + SKIP(return, "NUMA not available"); self->nthreads = numa_num_task_cpus() - 1; self->n1 = -1; self->n2 = -1; diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index a32a6ab8991449..75f5232c3aeca5 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile @@ -4,11 +4,11 @@ TEST_GEN_FILES := exec_target TEST_FILES := settings -CFLAGS += -O2 - top_srcdir = ../../../../.. include ../../lib.mk +CFLAGS += -O2 + $(TEST_GEN_PROGS): ../harness.c $(OUTPUT)/context_switch: ../utils.c diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index 77594e697f2fad..72684ed589c0ac 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -1,14 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# The loops are all 64-bit code -CFLAGS += -m64 -CFLAGS += -I$(CURDIR) -CFLAGS += -D SELFTEST -CFLAGS += -maltivec -CFLAGS += -mcpu=power4 - -# Use our CFLAGS for the implicit .S rule & set the asm machine type -ASFLAGS = $(CFLAGS) -Wa,-mpower4 - TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \ copyuser_p7_t0 copyuser_p7_t1 \ memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \ @@ -21,6 +11,16 @@ EXTRA_SOURCES := validate.c ../harness.c stubs.S top_srcdir = ../../../../.. include ../../lib.mk +# The loops are all 64-bit code +CFLAGS += -m64 +CFLAGS += -I$(CURDIR) +CFLAGS += -D SELFTEST +CFLAGS += -maltivec +CFLAGS += -mcpu=power4 + +# Use our CFLAGS for the implicit .S rule & set the asm machine type +ASFLAGS = $(CFLAGS) -Wa,-mpower4 + $(OUTPUT)/copyuser_64_t%: copyuser_64.S $(EXTRA_SOURCES) $(CC) $(CPPFLAGS) $(CFLAGS) \ -D COPY_LOOP=test___copy_tofrom_user_base \ diff --git a/tools/testing/selftests/powerpc/nx-gzip/Makefile b/tools/testing/selftests/powerpc/nx-gzip/Makefile index 0785c2e99d407e..b40991f902b2c5 100644 --- a/tools/testing/selftests/powerpc/nx-gzip/Makefile +++ b/tools/testing/selftests/powerpc/nx-gzip/Makefile @@ -1,8 +1,8 @@ -CFLAGS = -O3 -m64 -I./include -I../include - TEST_GEN_FILES := gzfht_test gunz_test TEST_PROGS := nx-gzip-test.sh include ../../lib.mk +CFLAGS = -O3 -m64 -I./include -I../include + $(TEST_GEN_FILES): gzip_vas.c ../utils.c diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile index 0101606902272c..b3946ce17e0c13 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile +++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile @@ -4,16 +4,6 @@ include ../../../../../build/Build.include noarg: $(MAKE) -C ../../ -# The EBB handler is 64-bit code and everything links against it -CFLAGS += -m64 - -TMPOUT = $(OUTPUT)/TMPDIR/ -# Toolchains may build PIE by default which breaks the assembly -no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \ - $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie) - -LDFLAGS += $(no-pie-option) - TEST_GEN_PROGS := reg_access_test event_attributes_test cycles_test \ cycles_with_freeze_test pmc56_overflow_test \ ebb_vs_cpu_event_test cpu_event_vs_ebb_test \ @@ -29,6 +19,16 @@ TEST_GEN_PROGS := reg_access_test event_attributes_test cycles_test \ top_srcdir = ../../../../../.. include ../../../lib.mk +# The EBB handler is 64-bit code and everything links against it +CFLAGS += -m64 + +TMPOUT = $(OUTPUT)/TMPDIR/ +# Toolchains may build PIE by default which breaks the assembly +no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \ + $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie) + +LDFLAGS += $(no-pie-option) + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \ ebb.c ebb_handler.S trace.c busy_loop.S diff --git a/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile b/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile index 4e07d70464574e..509d4b235b9e54 100644 --- a/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile +++ b/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -CFLAGS += -m64 - TEST_GEN_PROGS := group_constraint_pmc56_test group_pmc56_exclude_constraints_test group_constraint_pmc_count_test \ group_constraint_repeat_test group_constraint_radix_scope_qual_test reserved_bits_mmcra_sample_elig_mode_test \ group_constraint_mmcra_sample_test invalid_event_code_test reserved_bits_mmcra_thresh_ctl_test \ @@ -12,4 +10,6 @@ TEST_GEN_PROGS := group_constraint_pmc56_test group_pmc56_exclude_constraints_te top_srcdir = ../../../../../.. include ../../../lib.mk +CFLAGS += -m64 + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c ../sampling_tests/misc.h ../sampling_tests/misc.c diff --git a/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile b/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile index 9e67351fb252b7..d45892151e05d0 100644 --- a/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile +++ b/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -CFLAGS += -m64 - TEST_GEN_PROGS := mmcr0_exceptionbits_test mmcr0_cc56run_test mmcr0_pmccext_test \ mmcr0_pmcjce_test mmcr0_fc56_pmc1ce_test mmcr0_fc56_pmc56_test \ mmcr1_comb_test mmcr2_l2l3_test mmcr2_fcs_fch_test \ @@ -12,4 +10,6 @@ TEST_GEN_PROGS := mmcr0_exceptionbits_test mmcr0_cc56run_test mmcr0_pmccext_test top_srcdir = ../../../../../.. include ../../../lib.mk +CFLAGS += -m64 + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c misc.c misc.h ../loop.S ../branch_loops.S diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile index 9b9491a6321365..6dc5c5a42ca95f 100644 --- a/tools/testing/selftests/powerpc/primitives/Makefile +++ b/tools/testing/selftests/powerpc/primitives/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -CFLAGS += -I$(CURDIR) - TEST_GEN_PROGS := load_unaligned_zeropad top_srcdir = ../../../../.. include ../../lib.mk +CFLAGS += -I$(CURDIR) + $(TEST_GEN_PROGS): ../harness.c diff --git a/tools/testing/selftests/powerpc/security/Makefile b/tools/testing/selftests/powerpc/security/Makefile index e0d979ab020402..0a08386be9696b 100644 --- a/tools/testing/selftests/powerpc/security/Makefile +++ b/tools/testing/selftests/powerpc/security/Makefile @@ -5,10 +5,10 @@ TEST_PROGS := mitigation-patching.sh top_srcdir = ../../../../.. -CFLAGS += $(KHDR_INCLUDES) - include ../../lib.mk +CFLAGS += $(KHDR_INCLUDES) + $(TEST_GEN_PROGS): ../harness.c ../utils.c $(OUTPUT)/spectre_v2: CFLAGS += -m64 diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile index f679d260afc874..b15d5dbccc24bc 100644 --- a/tools/testing/selftests/powerpc/signal/Makefile +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -3,7 +3,6 @@ TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso sig_sc_double_restart TEST_GEN_PROGS += sigreturn_kernel TEST_GEN_PROGS += sigreturn_unaligned -CFLAGS += -maltivec $(OUTPUT)/signal_tm: CFLAGS += -mhtm $(OUTPUT)/sigfuz: CFLAGS += -pthread -m64 @@ -12,4 +11,6 @@ TEST_FILES := settings top_srcdir = ../../../../.. include ../../lib.mk +CFLAGS += -maltivec + $(TEST_GEN_PROGS): ../harness.c ../utils.c signal.S diff --git a/tools/testing/selftests/powerpc/stringloops/Makefile b/tools/testing/selftests/powerpc/stringloops/Makefile index 9c39f55a58ff3d..87c8c8f238daa8 100644 --- a/tools/testing/selftests/powerpc/stringloops/Makefile +++ b/tools/testing/selftests/powerpc/stringloops/Makefile @@ -1,7 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# The loops are all 64-bit code -CFLAGS += -I$(CURDIR) - EXTRA_SOURCES := ../harness.c build_32bit = $(shell if ($(CC) $(CFLAGS) -m32 -o /dev/null memcmp.c >/dev/null 2>&1) then echo "1"; fi) @@ -27,9 +24,12 @@ $(OUTPUT)/strlen_32: CFLAGS += -m32 TEST_GEN_PROGS += strlen_32 endif -ASFLAGS = $(CFLAGS) - top_srcdir = ../../../../.. include ../../lib.mk +# The loops are all 64-bit code +CFLAGS += -I$(CURDIR) + +ASFLAGS = $(CFLAGS) + $(TEST_GEN_PROGS): $(EXTRA_SOURCES) diff --git a/tools/testing/selftests/powerpc/switch_endian/Makefile b/tools/testing/selftests/powerpc/switch_endian/Makefile index bdc081afedb0f0..8f0c2a1d3333b7 100644 --- a/tools/testing/selftests/powerpc/switch_endian/Makefile +++ b/tools/testing/selftests/powerpc/switch_endian/Makefile @@ -1,13 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 TEST_GEN_PROGS := switch_endian_test -ASFLAGS += -O2 -Wall -g -nostdlib -m64 - EXTRA_CLEAN = $(OUTPUT)/*.o $(OUTPUT)/check-reversed.S top_srcdir = ../../../../.. include ../../lib.mk +ASFLAGS += -O2 -Wall -g -nostdlib -m64 + $(OUTPUT)/switch_endian_test: ASFLAGS += -I $(OUTPUT) $(OUTPUT)/switch_endian_test: $(OUTPUT)/check-reversed.S diff --git a/tools/testing/selftests/powerpc/syscalls/Makefile b/tools/testing/selftests/powerpc/syscalls/Makefile index ee1740ddfb0c2d..83dc3350077320 100644 --- a/tools/testing/selftests/powerpc/syscalls/Makefile +++ b/tools/testing/selftests/powerpc/syscalls/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only TEST_GEN_PROGS := ipc_unmuxed rtas_filter -CFLAGS += $(KHDR_INCLUDES) - top_srcdir = ../../../../.. include ../../lib.mk +CFLAGS += $(KHDR_INCLUDES) + $(TEST_GEN_PROGS): ../harness.c ../utils.c diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile index cf65cbf33085aa..873bc6b3739a67 100644 --- a/tools/testing/selftests/powerpc/vphn/Makefile +++ b/tools/testing/selftests/powerpc/vphn/Makefile @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only TEST_GEN_PROGS := test-vphn -CFLAGS += -m64 -I$(CURDIR) - top_srcdir = ../../../../.. include ../../lib.mk +CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing + $(TEST_GEN_PROGS): ../harness.c diff --git a/virt/kvm/dirty_ring.c b/virt/kvm/dirty_ring.c index c1cd7dfe4a9088..375a4fe27c06ef 100644 --- a/virt/kvm/dirty_ring.c +++ b/virt/kvm/dirty_ring.c @@ -63,7 +63,8 @@ static void kvm_reset_dirty_gfn(struct kvm *kvm, u32 slot, u64 offset, u64 mask) memslot = id_to_memslot(__kvm_memslots(kvm, as_id), id); - if (!memslot || (offset + __fls(mask)) >= memslot->npages) + if (!memslot || offset >= memslot->npages || + offset + __fls(mask) >= memslot->npages) return; KVM_MMU_LOCK(kvm);